* 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.
This commit is contained in:
Christopher Faylor 2000-02-24 02:49:44 +00:00
parent 58dabf5040
commit f02f1f1444
17 changed files with 164 additions and 96 deletions

View File

@ -1,3 +1,20 @@
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.

View File

@ -1,6 +1,6 @@
/* 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>

View File

@ -1,6 +1,6 @@
/* 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.

View File

@ -31,12 +31,15 @@ extern DWORD __sigfirst, __siglast;
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
@ -611,12 +614,31 @@ handle_sigsuspend (sigset_t tempmask)
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
@ -689,7 +711,9 @@ static int
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)
{
@ -706,7 +730,24 @@ call_handler (int sig, struct sigaction& siga, void *handler)
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 */
@ -734,17 +775,20 @@ call_handler (int sig, struct sigaction& siga, void *handler)
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 */
@ -983,6 +1027,17 @@ events_init (void)
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
@ -1035,12 +1090,7 @@ _sigreturn:
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
@ -1053,9 +1103,16 @@ _sigdelayed:
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),

View File

@ -1,6 +1,6 @@
/* 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>

View File

@ -1,7 +1,7 @@
/* 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.

View File

@ -1,6 +1,6 @@
/* fork.cc
Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
This file is part of Cygwin.

View File

@ -1,6 +1,6 @@
/* 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.

View File

@ -1,6 +1,6 @@
/* 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.
@ -12,26 +12,17 @@ details. */
#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:

View File

@ -1,6 +1,6 @@
/* 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.

View File

@ -1,6 +1,6 @@
/* 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.

View File

@ -85,8 +85,6 @@ Static HANDLE hwait_subproc = NULL; // Handle of sig_subproc thread
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.
*/
@ -100,6 +98,9 @@ Static int nzombies = 0; // Number of deceased children
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
@ -244,7 +245,7 @@ proc_subproc (DWORD what, DWORD val)
int potential_match;
DWORD exitcode;
pinfo *child;
int send_sigchld = 0;
int clearing = 0;
waitq *w;
#define wval ((waitq *) val)
@ -284,14 +285,6 @@ proc_subproc (DWORD what, DWORD 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
@ -310,7 +303,6 @@ proc_subproc (DWORD what, DWORD val)
ForceCloseHandle1 (hchildren[val], childhProc);
hchildren[val] = child->hProcess; /* Filled out by child */
ProtectHandle1 (child->hProcess, childhProc);
wake_wait_subproc ();
break; // This was an exec()
}
@ -318,46 +310,21 @@ proc_subproc (DWORD what, DWORD val)
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;
scan_wait:
/* Scan the linked list of wait()ing threads. If a wait's parameters
* match this pid, then activate it.
*/
for (w = &waitq_head; w->next != NULL; w = w->next)
{
if ((potential_match = checkstate (w)) > 0)
sip_printf ("released waiting thread");
else if (potential_match < 0)
sip_printf ("only found non-terminated children");
else if (potential_match == 0) // nothing matched
{
sip_printf ("waiting thread found no children");
HANDLE oldw = w->next->ev;
w->next->ev = NULL;
if (!SetEvent (oldw))
system_printf ("couldn't wake up wait event %p, %E", oldw);
w->next = w->next->next;
}
if (w->next == NULL)
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.
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.
@ -366,15 +333,41 @@ proc_subproc (DWORD what, DWORD val)
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.
*/
for (w = &waitq_head; w->next != NULL; w = w->next)
{
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");
if ((potential_match = checkstate (w)) > 0)
sip_printf ("released waiting thread");
else if (!clearing && potential_match < 0)
sip_printf ("only found non-terminated children");
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;
}
if (w->next == NULL)
break;
}
if (!clearing)
sip_printf ("finished processing terminated/stopped child");
else
{
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
@ -1252,6 +1245,10 @@ wait_sig (VOID *)
/* 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;
}

View File

@ -18,7 +18,8 @@ enum procstuff
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

View File

@ -4,7 +4,7 @@
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>
@ -43,7 +43,11 @@ muto::~muto ()
/* 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)
{
@ -59,7 +63,7 @@ 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
@ -99,11 +103,11 @@ muto::release ()
/* 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 */
}

View File

@ -1,6 +1,6 @@
/* sync.h: Header file for cygwin synchronization primitives.
Copyright 1999 Cygnus Solutions.
Copyright 1999, 2000 Cygnus Solutions.
Written by Christopher Faylor <cgf@cygnus.com>
@ -36,6 +36,7 @@ public:
/* 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 */

View File

@ -1,6 +1,6 @@
/* 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>

View File

@ -1,6 +1,6 @@
/* 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.