interruptible.
(call_handler): Avoid suspending a thread if it owns a mutex. Only set
signal_arrived if the thread was actually interrupted.
(events_init): Initialize module information needed by interruptible().
(sigdelayed): Don't call sig_dispatch_pending since it could screw up
* init.cc (dll_entry): Record module handle of main for use by interruptible().
(proc_subproc): Reorganize handling of terminated child so that the bulk of the
processing comes from the signal thread.
(wait_sig): Force processing of waiting threads if SIGCHLD is not processed.
* sync.cc (muto::release): Set tid == 0 after lock is released or signal
processor will be confused.
+Wed Feb 23 21:34:58 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * exceptions.cc (interruptible): Change method for determining if
+ something is interruptible.
+ (call_handler): Avoid suspending a thread if it owns a mutex. Only set
+ signal_arrived if the thread was actually interrupted.
+ (events_init): Initialize module information needed by interruptible().
+ (sigdelayed): Don't call sig_dispatch_pending since it could screw up
+ * init.cc (dll_entry): Record module handle of main for use by
+ interruptible().
+ (proc_subproc): Reorganize handling of terminated child so that the
+ bulk of the processing comes from the signal thread.
+ (wait_sig): Force processing of waiting threads if SIGCHLD is not
+ processed.
+ * sync.cc (muto::release): Set tid == 0 after lock is released or
+ signal processor will be confused.
+
Tue Feb 22 23:06:01 2000 Christopher Faylor <cgf@cygnus.com>
Respond to more g++ warnings relating to initializing structures.
/* autoload.h: Define functions for auto-loading symbols from a DLL.
- Copyright 1999 Cygnus Solutions.
+ Copyright 1999, 2000 Cygnus Solutions.
Written by Christopher Faylor <cgf@cygnus.com>
/* errno.cc: errno-related functions
- Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.
static BOOL WINAPI ctrl_c_handler (DWORD);
static void really_exit (int);
+static char windows_system_directory[1024];
+static size_t windows_system_directory_length;
/* This is set to indicate that we have already exited. */
static NO_COPY int exit_already = 0;
static NO_COPY muto *mask_sync = NULL;
+HMODULE cygwin_hmodule;
HANDLE NO_COPY console_handler_thread_waiter = NULL;
static const struct
extern DWORD exec_exit; // Possible exit value for exec
extern int pending_signals;
-extern __inline int
+int
interruptible (DWORD pc)
{
+#if 0
DWORD pchigh = pc & 0xf0000000;
return ((pc >= (DWORD) &__sigfirst) && (pc <= (DWORD) &__siglast)) ||
!(pchigh == 0xb0000000 || pchigh == 0x70000000 || pchigh == 0x60000000);
+#else
+ if ((pc >= (DWORD) &__sigfirst) && (pc <= (DWORD) &__siglast))
+ return 1;
+
+ MEMORY_BASIC_INFORMATION m;
+ memset (&m, 0, sizeof m);
+ if (!VirtualQuery ((LPCVOID) pc, &m, sizeof m))
+ sigproc_printf ("couldn't get memory info, %E");
+
+# define h ((HMODULE) m.AllocationBase)
+ if (h == cygwin_hmodule)
+ return 0;
+ char *checkdir = (char *) alloca (windows_system_directory_length);
+ if (!GetModuleFileName (h, checkdir, windows_system_directory_length))
+ return 0;
+ return !strncasematch (windows_system_directory, checkdir, windows_system_directory_length);
+# undef h
+#endif
}
void
call_handler (int sig, struct sigaction& siga, void *handler)
{
CONTEXT *cx, orig;
+ int interrupted = 1;
int res;
+ extern muto *sync_proc_subproc;
if (hExeced != NULL && hExeced != INVALID_HANDLE_VALUE)
{
sigproc_printf ("Suspending %p (mainthread)", myself->getthread2signal());
HANDLE hth = myself->getthread2signal ();
- res = SuspendThread (hth);
+ /* Suspend the thread which will receive the signal. But first ensure that
+ this thread doesn't have the sync_proc_subproc and mask_sync mutos, since
+ we need those (hack alert). If the thread-to-be-suspended has either of
+ these mutos, enter a busy loop until it is released. If the thread is
+ already suspended (which should never occur) then just queue the signal. */
+ for (;;)
+ {
+ res = SuspendThread (hth);
+ /* FIXME: Make multi-thread aware */
+ if (sync_proc_subproc->owner () != maintid && mask_sync->owner () != maintid)
+ break;
+
+ if (res)
+ goto set_pending;
+ ResumeThread (hth);
+ Sleep (0);
+ }
+
sigproc_printf ("suspend said %d, %E", res);
/* Clear any waiting threads prior to dispatching to handler function */
interrupt_now (cx, sig, siga, handler);
else if (!interrupt_on_return (cx, sig, siga, handler))
{
+ set_pending:
pending_signals = 1; /* FIXME: Probably need to be more tricky here */
sig_set_pending (sig);
+ interrupted = 0;
}
(void) ResumeThread (hth);
- (void) SetEvent (signal_arrived); // For an EINTR case
+ if (interrupted)
+ (void) SetEvent (signal_arrived); // For an EINTR case
sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res);
out:
sigproc_printf ("returning");
- return 1;
+ return interrupted;
}
#endif /* i386 */
ProtectHandle (title_mutex);
mask_sync = new_muto (FALSE, NULL);
+ windows_system_directory[0] = '\0';
+ (void) GetSystemDirectory (windows_system_directory, sizeof (windows_system_directory) - 2);
+ char *end = strchr (windows_system_directory, '\0');
+ if (end == windows_system_directory)
+ api_fatal ("can't find windows system directory");
+ if (end[-1] != '\\')
+ {
+ *end++ = '\\';
+ *end = '\0';
+ }
+ windows_system_directory_length = end - windows_system_directory;
}
void
ret
_sigdelayed:
- # addl 4,%%esp
- cmpl $0,_pending_signals
- je 2f
- pushl $0
- call _sig_dispatch_pending@4
-2: pushl %2 # original return address
+ pushl %2 # original return address
pushf
pushl %%esi
pushl %%edi
pushl %4 # signal argument
pushl $_sigreturn
movl $0,%0
- pushl $_signal_arrived
- call _ResetEvent@4
- jmp *%5
+
+ pushl _signal_arrived # Everybody waiting for this should
+ call _ResetEvent@4 # have woken up by now.
+
+ cmpl $0,_pending_signals
+ je 2f
+ pushl $0
+ call _sig_dispatch_pending@4
+
+2: jmp *%5
___siglast:
" : "=m" (sigsave.sig) : "m" (&_impure_ptr->_errno),
/* external.cc: Interface to Cygwin internals from external programs.
- Copyright 1997, 1998, 1999 Cygnus Solutions.
+ Copyright 1997, 1998, 1999, 2000 Cygnus Solutions.
Written by Christopher Faylor <cgf@cygnus.com>
/* fhandler_floppy.cc. See fhandler.h for a description of the
fhandler classes.
- Copyright 1999 Cygnus Solutions.
+ Copyright 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.
/* fork.cc
- Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.
/* heap.cc: Cygwin heap manager.
- Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.
/* init.cc for WIN32.
- Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.
#include <ctype.h>
#include "winsup.h"
-extern "C"
-{
- int WINAPI dll_entry (HANDLE h, DWORD reason, void *ptr);
-};
-
-extern "C" void *export_malloc (unsigned int);
-extern "C" void *export_realloc (void *,unsigned int);
-extern "C" void *export_calloc (unsigned int,unsigned int);
-extern "C" void export_free (void *);
-
-extern void do_global_ctors (void (**in_pfunc)(), int force);
+extern HMODULE cygwin_hmodule;
int NO_COPY dynamically_loaded;
-int
-WINAPI dll_entry (HANDLE, DWORD reason, void *static_load)
+extern "C" int
+WINAPI dll_entry (HANDLE h, DWORD reason, void *static_load)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
+ cygwin_hmodule = (HMODULE) h;
dynamically_loaded = (static_load == NULL);
break;
case DLL_THREAD_ATTACH:
-/* pipe.cc: pipe for WIN32.
+/* pipe.cc: pipe for Cygwin.
- Copyright 1996, 1998, 1999 Cygnus Solutions.
+ Copyright 1996, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.
/* registry.cc: registry interface
- Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.
Static HANDLE wait_sig_inited = NULL; // Control synchronization of
// message queue startup
-Static muto *sync_proc_subproc = NULL; // Control access to
- // subproc stuff
/* Used by WaitForMultipleObjects. These are handles to child processes.
*/
Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
Static waitq waitq_main; // Storage for main thread
+muto NO_COPY *sync_proc_subproc = NULL; // Control access to
+ // subproc stuff
+
DWORD NO_COPY maintid = 0; // ID of the main thread
Static DWORD sigtid = 0; // ID of the signal thread
int potential_match;
DWORD exitcode;
pinfo *child;
- int send_sigchld = 0;
+ int clearing = 0;
waitq *w;
#define wval ((waitq *) val)
wake_wait_subproc ();
break;
- /* A child is in the stopped state. Scan wait() queue to see if anyone
- * should be notified. (Called from wait_sig thread)
- */
- case PROC_CHILDSTOPPED:
- child = myself; // Just to avoid accidental NULL dereference
- sip_printf ("Received stopped notification");
- goto scan_wait;
-
/* A child process had terminated.
* Possibly this is just due to an exec(). Cygwin implements an exec()
* as a "handoff" from one windows process to another. If child->hProcess
ForceCloseHandle1 (hchildren[val], childhProc);
hchildren[val] = child->hProcess; /* Filled out by child */
ProtectHandle1 (child->hProcess, childhProc);
- wake_wait_subproc ();
break; // This was an exec()
}
child->pid, val, hchildren[val], nchildren, nzombies);
remove_child (val); // Remove from children arrays
zombies[nzombies++] = child; // Add to zombie array
- wake_wait_subproc (); // Notify wait_subproc thread that
- // nchildren has changed.
child->process_state = PID_ZOMBIE;// Walking dead
if (!proc_loop_wait) // Don't bother if wait_subproc is
break; // exiting
- send_sigchld = 1;
+ /* Send a SIGCHLD to myself. */
+ rc = sig_send (myself_nowait, SIGCHLD); // Send a SIGCHLD
+ break; // Don't try to unlock. We don't have a lock.
+
+ /* A child is in the stopped state. Scan wait() queue to see if anyone
+ * should be notified. (Called from wait_sig thread)
+ */
+ case PROC_CHILDSTOPPED:
+ child = myself; // Just to avoid accidental NULL dereference
+ sip_printf ("Received stopped notification");
+ goto scan_wait;
+ /* Clear all waiting threads. Called from exceptions.cc prior to
+ * the main thread's dispatch to a signal handler function.
+ * (called from wait_sig thread)
+ */
+ case PROC_CLEARWAIT:
+ /* Clear all "wait"ing threads. */
+ sip_printf ("clear waiting threads");
+ clearing = 1;
+
+ case PROC_SIGCHLD:
scan_wait:
/* Scan the linked list of wait()ing threads. If a wait's parameters
* match this pid, then activate it.
{
if ((potential_match = checkstate (w)) > 0)
sip_printf ("released waiting thread");
- else if (potential_match < 0)
+ else if (!clearing && potential_match < 0)
sip_printf ("only found non-terminated children");
- else if (potential_match == 0) // nothing matched
+ else if (potential_match <= 0) // nothing matched
{
sip_printf ("waiting thread found no children");
HANDLE oldw = w->next->ev;
w->next->ev = NULL;
+ if (clearing)
+ w->next->status = -1; /* flag that a signal was received */
if (!SetEvent (oldw))
system_printf ("couldn't wake up wait event %p, %E", oldw);
w->next = w->next->next;
break;
}
- sip_printf ("finished processing terminated/stopped child");
- if (!send_sigchld)
- break; // No need to send a SIGCHLD
-
- /* Send a SIGCHLD to myself. */
- sync_proc_subproc->release (); // Avoid a potential deadlock
- rc = sig_send (NULL, SIGCHLD); // Send a SIGCHLD
- goto out1; // Don't try to unlock. We don't have a lock.
-
-
- /* Clear all waiting threads. Called from exceptions.cc prior to
- * the main thread's dispatch to a signal handler function.
- * (called from wait_sig thread)
- */
- case PROC_CLEARWAIT:
- /* Clear all "wait"ing threads. */
- sip_printf ("clear waiting threads");
- for (w = &waitq_head; w->next != NULL; w = w->next)
+ if (!clearing)
+ sip_printf ("finished processing terminated/stopped child");
+ else
{
- sip_printf ("clearing waiting thread, pid %d", w->next->pid);
- w->next->status = -1; /* flag that a signal was received */
- if (!SetEvent (w->next->ev))
- system_printf ("Couldn't wake up wait event, %E");
+ waitq_head.next = NULL;
+ sip_printf ("finished clearing");
}
- waitq_head.next = NULL;
- sip_printf ("finished clearing");
break;
/* Handle a wait4() operation. Allocates an event for the calling
/* A normal UNIX signal */
default:
sip_printf ("Got signal %d", sig);
+ int wasdispatched = sig_handle (sig);
+ dispatched |= wasdispatched;
+ if (sig == SIGCHLD && !wasdispatched)
+ proc_subproc (PROC_SIGCHLD, 0);
dispatched |= sig_handle (sig);
goto nextsig;
}
PROC_CHILDSTOPPED = 2, // a child stopped
PROC_CHILDTERMINATED = 3, // a child died
PROC_CLEARWAIT = 4, // clear all waits - signal arrived
- PROC_WAIT = 5 // setup for wait() for subproc
+ PROC_WAIT = 5, // setup for wait() for subproc
+ PROC_SIGCHLD = 6 // saw a non-trapped SIGCHLD
};
typedef struct struct_waitq
which is intended to operate similarly to a mutex but attempts to
avoid making expensive calls to the kernel.
- Copyright 1999 Cygnus Solutions.
+ Copyright 2000 Cygnus Solutions.
Written by Christopher Faylor <cgf@cygnus.com>
/* Acquire the lock. Argument is the number of milliseconds to wait for
the lock. Multiple visits from the same thread are allowed and should
- be handled correctly. */
+ be handled correctly.
+
+ Note: The goal here is to minimize, as much as possible, calls to the
+ OS. Hence the use of InterlockedIncrement, etc., rather than (much) more
+ expensive OS mutexes. */
int
muto::acquire (DWORD ms)
{
lock the same muto to succeed without attempting to manipulate sync.
If the muto is already locked then this thread will wait for ms until
it is signalled by muto::release. Then it will attempt to grab the
- sync field. If it succeeds, then this thread owns the mutex.
+ sync field. If it succeeds, then this thread owns the muto.
There is a pathological condition where a thread times out waiting for
bruteforce but the release code triggers the bruteforce event. In this
/* FIXME: Need to check that other thread has not exited, too. */
if (!--visits)
{
- tid = 0; /* We were the last unlocker. */
InterlockedExchange (&sync, 0); /* Reset trigger. */
/* This thread had incremented waiters but had never decremented it.
Decrement it now. If it is >= 0 then there are possibly other
threads waiting for the lock, so trigger bruteforce. */
+ tid = 0; /* We were the last unlocker. */
if (InterlockedDecrement (&waiters) >= 0)
(void) SetEvent (bruteforce); /* Wake up one of the waiting threads */
}
/* sync.h: Header file for cygwin synchronization primitives.
- Copyright 1999 Cygnus Solutions.
+ Copyright 1999, 2000 Cygnus Solutions.
Written by Christopher Faylor <cgf@cygnus.com>
/* Return true if caller thread owns the lock. */
int ismine () {return tid == GetCurrentThreadId ();}
+ DWORD owner () {return tid;}
};
/* Use a statically allocated buffer as the storage for a muto */
/* thread.h: Locking and threading module definitions
- Copyright 1998, 1999 Cygnus Solutions.
+ Copyright 1998, 1999, 2000 Cygnus Solutions.
Written by Marco Fuykschot <marco@ddi.nl>
/* wait.cc: Posix wait routines.
- Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.