From e431827c7cab81292e8cd4ec9d3a4a60b35a42f2 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Thu, 12 Feb 2004 03:01:58 +0000 Subject: [PATCH] Rename _threadinfo to _cygtls, throughout. * cygtls.h (_cygtls::call_signal_handler): Rename from call_signal_handler_now. (_cygtls::push): Make second argument mandatory. (_cygtls::fixup_after_fork): Declare new function. (_cygtls::lock): Ditto. * cygtls.cc (_cygtls::fixup_after_fork): Define new function. * dcrt0.cc (cygwin_finished_initializing): Define as bool. (alloc_stack): Use _tlstop rather than arbitrary variable in probably vain attempt to avoid strange fork problem on CTRL-C. (dll_crt0_0): Remove obsolete winpids::init call. * dll_init.cc (dll_dllcrt0): Detect forkee condition as equivalent to initializing. * winsup.h (cygwin_finished_initializing): Declare as bool. * exceptions.cc (handle_exceptions): Rely on cygwin_finished_initializing to determine how to handle exception during process startup. (_cygtls::call_signal_handler): Rename from call_signal_handler_now. (_cygtls::interrupt_now): Fill in second argument to push. (signal_fixup_after_fork): Eliminate. (setup_handler): Initialize locked to avoid potential inappropriate unlock. Resume thread if it has acquired the stack lock. (ctrl_c_handler): Just exit if ctrl-c is hit before cygiwn has finished initializing. * fork.cc (sync_with_child): Don't call abort since it can cause exit deadlocks. (sync_with_child): Change debugging output slightly. (fork_child): Set cygwin_finished_initializing here. Call _cygtls fork fixup and explicitly call sigproc_init. (fork_parent): Release malloc lock on fork failure. (vfork): Call signal handler via _my_tls. * sigproc.cc (sig_send): Ditto. * syscalls.cc (readv): Ditto. * termios.cc (tcsetattr): Ditto. * wait.cc (wait4): Ditto. * signal.cc (nanosleep): Ditto. (abort): Ditto. (kill_pgrp): Avoid killing self if exiting. * sync.cc (muto::acquire): Remove (temporarily?) ill-advised exiting_thread check. * gendef (_sigfe): Be more agressive in protecting stack pointer from other access by signal thread. (_cygtls::locked): Define new function. (_sigbe): Ditto. (_cygtls::pop): Protect edx. (_cygtls::lock): Use guaranteed method to set eax to 1. (longjmp): Aggressively protect signal stack. * miscfuncs.cc (low_priority_sleep): Reduce "sleep time" for secs == 0. * pinfo.cc (winpids::set): Counterintuitively use malloc's lock to protect simultaneous access to the pids list since there are pathological conditions which can cause malloc to call winpid. (winpids::init): Eliminate. * pinfo.h (winpids::cs): Eliminate declaration. * pinfo.h (winpids::init): Eliminate definition. --- winsup/cygwin/ChangeLog | 57 ++++++++++++++++ winsup/cygwin/cygheap.h | 2 +- winsup/cygwin/cygtls.cc | 48 ++++++++----- winsup/cygwin/cygtls.h | 17 +++-- winsup/cygwin/dcrt0.cc | 23 +++---- winsup/cygwin/dll_init.cc | 4 +- winsup/cygwin/exceptions.cc | 106 +++++++++++++---------------- winsup/cygwin/fork.cc | 50 ++++++++------ winsup/cygwin/gendef | 131 +++++++++++++++++++++--------------- winsup/cygwin/init.cc | 2 +- winsup/cygwin/miscfuncs.cc | 2 +- winsup/cygwin/perthread.h | 2 +- winsup/cygwin/pinfo.cc | 13 +--- winsup/cygwin/pinfo.h | 2 - winsup/cygwin/signal.cc | 6 +- winsup/cygwin/sigproc.cc | 6 +- winsup/cygwin/sigproc.h | 5 +- winsup/cygwin/sync.cc | 4 +- winsup/cygwin/syscalls.cc | 2 +- winsup/cygwin/termios.cc | 3 +- winsup/cygwin/thread.h | 4 +- winsup/cygwin/wait.cc | 5 +- winsup/cygwin/winsup.h | 2 +- 23 files changed, 287 insertions(+), 209 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 852c1839f..2cc0cb88b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,60 @@ +2004-02-11 Christopher Faylor + + Rename _threadinfo to _cygtls, throughout. + * cygtls.h (_cygtls::call_signal_handler): Rename from + call_signal_handler_now. + (_cygtls::push): Make second argument mandatory. + (_cygtls::fixup_after_fork): Declare new function. + (_cygtls::lock): Ditto. + * cygtls.cc (_cygtls::fixup_after_fork): Define new function. + * dcrt0.cc (cygwin_finished_initializing): Define as bool. + (alloc_stack): Use _tlstop rather than arbitrary variable in probably + vain attempt to avoid strange fork problem on CTRL-C. + (dll_crt0_0): Remove obsolete winpids::init call. + * dll_init.cc (dll_dllcrt0): Detect forkee condition as equivalent to + initializing. + * winsup.h (cygwin_finished_initializing): Declare as bool. + * exceptions.cc (handle_exceptions): Rely on + cygwin_finished_initializing to determine how to handle exception + during process startup. + (_cygtls::call_signal_handler): Rename from call_signal_handler_now. + (_cygtls::interrupt_now): Fill in second argument to push. + (signal_fixup_after_fork): Eliminate. + (setup_handler): Initialize locked to avoid potential inappropriate + unlock. Resume thread if it has acquired the stack lock. + (ctrl_c_handler): Just exit if ctrl-c is hit before cygiwn has finished + initializing. + * fork.cc (sync_with_child): Don't call abort since it can cause exit + deadlocks. + (sync_with_child): Change debugging output slightly. + (fork_child): Set cygwin_finished_initializing here. Call _cygtls fork + fixup and explicitly call sigproc_init. + (fork_parent): Release malloc lock on fork failure. + (vfork): Call signal handler via _my_tls. + * sigproc.cc (sig_send): Ditto. + * syscalls.cc (readv): Ditto. + * termios.cc (tcsetattr): Ditto. + * wait.cc (wait4): Ditto. + * signal.cc (nanosleep): Ditto. + (abort): Ditto. + (kill_pgrp): Avoid killing self if exiting. + * sync.cc (muto::acquire): Remove (temporarily?) ill-advised + exiting_thread check. + * gendef (_sigfe): Be more agressive in protecting stack pointer from + other access by signal thread. + (_cygtls::locked): Define new function. + (_sigbe): Ditto. + (_cygtls::pop): Protect edx. + (_cygtls::lock): Use guaranteed method to set eax to 1. + (longjmp): Aggressively protect signal stack. + * miscfuncs.cc (low_priority_sleep): Reduce "sleep time" for secs == 0. + * pinfo.cc (winpids::set): Counterintuitively use malloc's lock to + protect simultaneous access to the pids list since there are + pathological conditions which can cause malloc to call winpid. + (winpids::init): Eliminate. + * pinfo.h (winpids::cs): Eliminate declaration. + * pinfo.h (winpids::init): Eliminate definition. + 2004-02-11 Corinna Vinschen * security.cc (get_nt_object_attribute): Fix error handling. diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index a5134cfde..518e9dce6 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -266,7 +266,7 @@ struct init_cygheap #ifdef NEWVFORK fhandler_tty_slave *ctty_on_hold; #endif - struct _threadinfo **threadlist; + struct _cygtls **threadlist; size_t sthreads; int open_fhs; void close_ctty (); diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index d3ed824c8..89e21d473 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -20,6 +20,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "cygthread.h" +#include "pinfo.h" #include "sigproc.h" class sentry @@ -32,7 +33,7 @@ public: sentry () {destroy = 0;} sentry (DWORD wait) {destroy = lock->acquire (wait);} ~sentry () {if (destroy) lock->release ();} - friend void _threadinfo::init (); + friend void _cygtls::init (); }; muto NO_COPY *sentry::lock; @@ -42,27 +43,27 @@ static size_t NO_COPY nthreads; #define THREADLIST_CHUNK 256 void -_threadinfo::init () +_cygtls::init () { if (cygheap->threadlist) memset (cygheap->threadlist, 0, cygheap->sthreads * sizeof (cygheap->threadlist[0])); else { cygheap->sthreads = THREADLIST_CHUNK; - cygheap->threadlist = (_threadinfo **) ccalloc (HEAP_TLS, cygheap->sthreads, + cygheap->threadlist = (_cygtls **) ccalloc (HEAP_TLS, cygheap->sthreads, sizeof (cygheap->threadlist[0])); } new_muto1 (sentry::lock, sentry_lock); } void -_threadinfo::set_state (bool is_exception) +_cygtls::set_state (bool is_exception) { initialized = CYGTLS_INITIALIZED + is_exception; } void -_threadinfo::reset_exception () +_cygtls::reset_exception () { if (initialized == CYGTLS_EXCEPTION) { @@ -75,14 +76,14 @@ _threadinfo::reset_exception () /* Two calls to get the stack right... */ void -_threadinfo::call (DWORD (*func) (void *, void *), void *arg) +_cygtls::call (DWORD (*func) (void *, void *), void *arg) { char buf[CYGTLS_PADSIZE]; call2 (func, arg, buf); } void -_threadinfo::call2 (DWORD (*func) (void *, void *), void *arg, void *buf) +_cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf) { exception_list except_entry; /* Initialize this thread's ability to respond to things like @@ -95,7 +96,7 @@ _threadinfo::call2 (DWORD (*func) (void *, void *), void *arg, void *buf) } void -_threadinfo::init_thread (void *x, DWORD (*func) (void *, void *)) +_cygtls::init_thread (void *x, DWORD (*func) (void *, void *)) { if (x) { @@ -125,7 +126,7 @@ _threadinfo::init_thread (void *x, DWORD (*func) (void *, void *)) sentry here (INFINITE); if (nthreads >= cygheap->sthreads) { - cygheap->threadlist = (_threadinfo **) + cygheap->threadlist = (_cygtls **) crealloc (cygheap->threadlist, (cygheap->sthreads += THREADLIST_CHUNK) * sizeof (cygheap->threadlist[0])); memset (cygheap->threadlist + nthreads, 0, THREADLIST_CHUNK * sizeof (cygheap->threadlist[0])); @@ -135,7 +136,22 @@ _threadinfo::init_thread (void *x, DWORD (*func) (void *, void *)) } void -_threadinfo::remove (DWORD wait) +_cygtls::fixup_after_fork () +{ + if (sig) + { + set_signal_mask (oldmask); + sig = 0; + } + stacklock = 0; + stackptr = stack + 1; // FIXME? +#ifdef DEBUGGING + memset (stackptr, 0, sizeof (stack) - sizeof (stack[0])); +#endif +} + +void +_cygtls::remove (DWORD wait) { debug_printf ("wait %p\n", wait); sentry here (wait); @@ -153,7 +169,7 @@ _threadinfo::remove (DWORD wait) } void -_threadinfo::push (__stack_t addr, bool exception) +_cygtls::push (__stack_t addr, bool exception) { if (exception) lock (); @@ -166,13 +182,13 @@ _threadinfo::push (__stack_t addr, bool exception) #define BAD_IX ((size_t) -1) static size_t NO_COPY threadlist_ix = BAD_IX; -_threadinfo * -_threadinfo::find_tls (int sig) +_cygtls * +_cygtls::find_tls (int sig) { debug_printf ("sig %d\n", sig); sentry here (INFINITE); __asm__ volatile (".equ _threadlist_exception_return,."); - _threadinfo *res = NULL; + _cygtls *res = NULL; for (threadlist_ix = 0; threadlist_ix < nthreads; threadlist_ix++) if (sigismember (&(cygheap->threadlist[threadlist_ix]->sigwait_mask), sig)) { @@ -184,7 +200,7 @@ _threadinfo::find_tls (int sig) } void -_threadinfo::set_siginfo (sigpacket *pack) +_cygtls::set_siginfo (sigpacket *pack) { infodata = pack->si; } @@ -222,7 +238,7 @@ handle_threadlist_exception (EXCEPTION_RECORD *e, void *frame, CONTEXT *, void * } void -_threadinfo::init_threadlist_exceptions (exception_list *el) +_cygtls::init_threadlist_exceptions (exception_list *el) { extern void init_exception_handler (exception_list *, exception_handler *); init_exception_handler (el, handle_threadlist_exception); diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h index 43802dd81..78f61242b 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -90,7 +90,7 @@ struct _local_storage 'gentls_offsets' (<<-- start parsing here). */ typedef __uint32_t __stack_t; -struct _threadinfo +struct _cygtls { void (*func) /*gentls_offsets*/(int)/*gentls_offsets*/; int saved_errno; @@ -108,7 +108,7 @@ struct _threadinfo struct pthread *tid; struct _reent local_clib; struct _local_storage locals; - struct _threadinfo *prev, *next; + struct _cygtls *prev, *next; __stack_t *stackptr; int sig; unsigned stacklock; @@ -121,9 +121,9 @@ struct _threadinfo void init_thread (void *, DWORD (*) (void *, void *)); static void call (DWORD (*) (void *, void *), void *); static void call2 (DWORD (*) (void *, void *), void *, void *) __attribute__ ((regparm (3))); - static struct _threadinfo *find_tls (int sig); + static struct _cygtls *find_tls (int sig); void remove (DWORD); - void push (__stack_t, bool = false) __attribute__ ((regparm (3))); + void push (__stack_t, bool) __attribute__ ((regparm (3))); __stack_t pop () __attribute__ ((regparm (1))); bool isinitialized () {return initialized == CYGTLS_INITIALIZED || initialized == CYGTLS_EXCEPTION;} void set_state (bool); @@ -138,16 +138,19 @@ struct _threadinfo void set_siginfo (struct sigpacket *) __attribute__ ((regparm (3))); void set_threadkill () {threadkill = true;} void reset_threadkill () {threadkill = false;} - int lock () __attribute__ ((regparm (1))); + int call_signal_handler () __attribute__ ((regparm (1))); + void fixup_after_fork () __attribute__ ((regparm (1))); + void lock () __attribute__ ((regparm (1))); void unlock () __attribute__ ((regparm (1))); + bool locked () __attribute__ ((regparm (1))); /*gentls_offsets*/ }; #pragma pack(pop) extern char *_tlsbase __asm__ ("%fs:4"); extern char *_tlstop __asm__ ("%fs:8"); -#define _my_tls (((_threadinfo *) _tlsbase)[-1]) -extern _threadinfo *_main_tls; +#define _my_tls (((_cygtls *) _tlsbase)[-1]) +extern _cygtls *_main_tls; #define __getreent() (&_my_tls.local_clib) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index f1df888b2..374c901b4 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -72,9 +72,9 @@ char NO_COPY **envp; extern "C" void __sinit (_reent *); -_threadinfo NO_COPY *_main_tls; +_cygtls NO_COPY *_main_tls; -int cygwin_finished_initializing; +bool NO_COPY cygwin_finished_initializing; /* Used in SIGTOMASK for generating a bit for insertion into a sigset_t. This is subtracted from the signal number prior to shifting the bit. @@ -513,18 +513,16 @@ alloc_stack_hard_way (child_info_fork *ci, volatile char *b) static void alloc_stack (child_info_fork *ci) { - /* FIXME: adding 16384 seems to avoid a stack copy problem during - fork on Win95, but I don't know exactly why yet. DJ */ - volatile char b[ci->stacksize + 16384]; - - if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm)) + if (!VirtualQuery ((LPCVOID) _tlstop, &sm, sizeof sm)) api_fatal ("fork: couldn't get stack info, %E"); if (sm.AllocationBase == ci->stacktop) - ci->stacksize = 0; - else - alloc_stack_hard_way (ci, b + sizeof (b) - 1); + { + ci->stacksize = 0; + return; + } + alloc_stack_hard_way (ci, b + sizeof (b) - 1); return; } @@ -662,7 +660,6 @@ dll_crt0_0 () } device::init (); - winpids::init (); do_global_ctors (&__CTOR_LIST__, 1); cygthread::init (); @@ -718,7 +715,7 @@ dll_crt0_0 () CloseHandle (child_proc_info->pppid_handle); } - _threadinfo::init (); + _cygtls::init (); /* Initialize events */ events_init (); @@ -873,7 +870,7 @@ dll_crt0_1 (char *) set_console_title (cp); } - cygwin_finished_initializing = 1; + cygwin_finished_initializing = true; /* Call init of loaded dlls. */ dlls.init (); diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 72048eff1..a1901a02d 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -371,7 +371,7 @@ dll_dllcrt0 (HMODULE h, per_process *p) initializing, then the DLL must be a cygwin-aware DLL that was explicitly linked into the program rather than a dlopened DLL. */ - if (!cygwin_finished_initializing) + if (!in_forkee && !cygwin_finished_initializing) type = DLL_LINK; else { @@ -387,7 +387,7 @@ dll_dllcrt0 (HMODULE h, per_process *p) initialize the DLL. If we haven't finished initializing, it may not be safe to call the dll's "main" since not all of cygwin's internal structures may have been set up. */ - if (!d || (cygwin_finished_initializing && !d->init ())) + if (!d || ((in_forkee || cygwin_finished_initializing) && !d->init ())) return -1; return (DWORD) d; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 03df67f10..490756544 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -519,7 +519,7 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *) break; } - if (!myself->progname[0] + if (!cygwin_finished_initializing || GetCurrentThreadId () == sigtid || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN @@ -692,10 +692,10 @@ interruptible (DWORD pc) return res; } void __stdcall -_threadinfo::interrupt_setup (int sig, void *handler, +_cygtls::interrupt_setup (int sig, void *handler, struct sigaction& siga) { - push ((__stack_t) sigdelayed); + push ((__stack_t) sigdelayed, false); oldmask = myself->getsigmask (); newmask = oldmask | siga.sa_mask | SIGTOMASK (sig); sa_flags = siga.sa_flags; @@ -717,28 +717,16 @@ _threadinfo::interrupt_setup (int sig, void *handler, } bool -_threadinfo::interrupt_now (CONTEXT *ctx, int sig, void *handler, +_cygtls::interrupt_now (CONTEXT *ctx, int sig, void *handler, struct sigaction& siga) { - push ((__stack_t) ctx->Eip); + push ((__stack_t) ctx->Eip, false); interrupt_setup (sig, handler, siga); ctx->Eip = pop (); SetThreadContext (*this, ctx); /* Restart the thread in a new location */ return 1; } -void __stdcall -signal_fixup_after_fork () -{ - if (_my_tls.sig) - { - _my_tls.sig = 0; - _my_tls.stackptr = _my_tls.stack + 1; // FIXME? - set_signal_mask (_my_tls.oldmask); - } - sigproc_init (); -} - extern "C" void __stdcall set_sig_errno (int e) { @@ -747,13 +735,14 @@ set_sig_errno (int e) // sigproc_printf ("errno %d", e); } -static int setup_handler (int, void *, struct sigaction&, _threadinfo *tls) +static int setup_handler (int, void *, struct sigaction&, _cygtls *tls) __attribute__((regparm(3))); static int -setup_handler (int sig, void *handler, struct sigaction& siga, _threadinfo *tls) +setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls) { CONTEXT cx; bool interrupted = false; + bool locked = false; if (tls->sig) { @@ -762,12 +751,11 @@ setup_handler (int sig, void *handler, struct sigaction& siga, _threadinfo *tls) goto out; } - int locked; for (int i = 0; i < CALL_HANDLER_RETRY; i++) { - locked = tls->lock (); - __stack_t *retaddr_on_stack = tls->stackptr - 1; - if (retaddr_on_stack >= tls->stack) + tls->lock (); + locked = true; + if (tls->stackptr > tls->stack) { tls->reset_exception (); tls->interrupt_setup (sig, handler, siga); @@ -776,14 +764,14 @@ setup_handler (int sig, void *handler, struct sigaction& siga, _threadinfo *tls) break; } + tls->unlock (); + locked = false; DWORD res; HANDLE hth = (HANDLE) *tls; - /* Suspend the thread which will receive the signal. But first ensure that - this thread doesn't have any mutos. (FIXME: Someday we should just grab - all of the mutos rather than checking for them) - For Windows 95, we also have to ensure that the addresses returned by GetThreadContext - are valid. + /* Suspend the thread which will receive the signal. + For Windows 95, we also have to ensure that the addresses returned by + GetThreadContext are valid. If one of these conditions is not true we loop for a fixed number of times since we don't want to stall the signal handler. FIXME: Will this result in noticeable delays? @@ -799,31 +787,25 @@ setup_handler (int sig, void *handler, struct sigaction& siga, _threadinfo *tls) sigproc_printf ("suspending mainthread PC %p", cx.Eip); #endif res = SuspendThread (hth); - /* Just release the lock now since we hav suspended the main thread and it - definitely can't be grabbing it now. This will have to change, of course, - if/when we can send signals to other than the main thread. */ - /* Just set pending if thread is already suspended */ if (res) { (void) ResumeThread (hth); break; } - - // FIXME - add check for reentering of DLL here - - cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - if (!GetThreadContext (hth, &cx)) - system_printf ("couldn't get context of main thread, %E"); - else if (interruptible (cx.Eip)) - interrupted = tls->interrupt_now (&cx, sig, handler, siga); + if (!tls->locked ()) + { + cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext (hth, &cx)) + system_printf ("couldn't get context of main thread, %E"); + else if (interruptible (cx.Eip)) + interrupted = tls->interrupt_now (&cx, sig, handler, siga); + } res = ResumeThread (hth); if (interrupted) break; - tls->unlock (); - locked = false; sigproc_printf ("couldn't interrupt. trying again."); low_priority_sleep (0); } @@ -845,6 +827,10 @@ static BOOL WINAPI ctrl_c_handler (DWORD type) { static bool saw_close; + + if (!cygwin_finished_initializing) + ExitProcess (STATUS_CONTROL_C_EXIT); + _my_tls.remove (INFINITE); /* Return FALSE to prevent an "End task" dialog box from appearing @@ -977,7 +963,7 @@ sigpacket::process () /* nothing to do */; else if (tls && sigismember (&tls->sigwait_mask, si.si_signo)) insigwait_mask = true; - else if (!tls && (tls = _threadinfo::find_tls (si.si_signo))) + else if (!tls && (tls = _cygtls::find_tls (si.si_signo))) insigwait_mask = true; else if (!(masked = sigismember (mask, si.si_signo)) && tls) masked = sigismember (&tls->sigmask, si.si_signo); @@ -1153,36 +1139,36 @@ events_terminate (void) exit_already = 1; } -extern "C" { -int __stdcall -call_signal_handler_now () +int +_cygtls::call_signal_handler () { - int sa_flags = 0; - while (_my_tls.sig && _my_tls.stackptr > _my_tls.stack) + int this_sa_flags = 0; + /* Call signal handler. No need to set stacklock since sig effectively + implies that. */ + while (sig) { - sa_flags = _my_tls.sa_flags; - int sig = _my_tls.sig; - void (*sigfunc) (int) = _my_tls.func; + this_sa_flags = sa_flags; + int thissig = sig; + void (*sigfunc) (int) = func; - (void) _my_tls.pop (); + (void) pop (); reset_signal_arrived (); - sigset_t oldmask = _my_tls.oldmask; - int this_errno = _my_tls.saved_errno; - set_process_mask (_my_tls.newmask); - _my_tls.sig = 0; - sigfunc (sig); + sigset_t oldmask = oldmask; + int this_errno = saved_errno; + set_process_mask (newmask); + sig = 0; + sigfunc (thissig); set_process_mask (oldmask); if (this_errno >= 0) set_errno (this_errno); } - return sa_flags & SA_RESTART; + return this_sa_flags & SA_RESTART; } -void __stdcall +extern "C" void __stdcall reset_signal_arrived () { (void) ResetEvent (signal_arrived); sigproc_printf ("reset signal_arrived"); } -} diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 8a5e5bfa0..01b9dbc23 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -167,11 +167,11 @@ sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready, */ if (errcode != STATUS_CONTROL_C_EXIT) { - system_printf ("child %u(%p) died before initialization with status code %p", - cygwin_pid (pi.dwProcessId), pi.hProcess, errcode); - system_printf ("*** child state %s", s); + system_printf ("child %u(%p) died before initialization with status code %p", + cygwin_pid (pi.dwProcessId), pi.hProcess, errcode); + system_printf ("*** child state %s", s); #ifdef DEBUGGING - abort (); + try_to_debug (); #endif } set_errno (EAGAIN); @@ -212,13 +212,13 @@ sync_with_parent (const char *s, bool hang_self) switch (psync_rc) { case WAIT_TIMEOUT: - api_fatal ("WFSO timed out for %s", s); + api_fatal ("WFSO timed out %s", s); break; case WAIT_FAILED: if (GetLastError () == ERROR_INVALID_HANDLE && WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED) break; - api_fatal ("WFSO failed for %s, fork_finished %p, %E", s, + api_fatal ("WFSO failed %s, fork_finished %p, %E", s, fork_info->forker_finished); break; default: @@ -243,6 +243,17 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d", hParent, first_dll, load_dlls); + /* If we've played with the stack, stacksize != 0. That means that + fork() was invoked from other than the main thread. Make sure that + the threadinfo information is properly set up. */ + if (!fork_info->stacksize) + { + _main_tls = &_my_tls; + _main_tls->init_thread (NULL, NULL); + _main_tls->local_clib = *_impure_ptr; + _impure_ptr = &_main_tls->local_clib; + } + #ifdef DEBUGGING char c; if (GetEnvironmentVariable ("FORKDEBUG", &c, 1)) @@ -257,18 +268,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) } #endif - /* If we've played with the stack, stacksize != 0. That means that - fork() was invoked from other than the main thread. Make sure that - when the "main" thread exits it calls do_exit, like a normal process. - Exit with a status code of 0. */ - if (fork_info->stacksize) - { - _main_tls = &_my_tls; - _main_tls->init_thread (NULL, NULL); - _main_tls->local_clib = *_impure_ptr; - _impure_ptr = &_main_tls->local_clib; - } - set_file_api_mode (current_codepage); MALLOC_CHECK; @@ -307,7 +306,8 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) #endif pinfo_fixup_after_fork (); - signal_fixup_after_fork (); + _my_tls.fixup_after_fork (); + sigproc_init (); /* Set thread local stuff to zero. Under Windows 95/98 this is sometimes non-zero, for some reason. @@ -320,6 +320,7 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) fixup_timers_after_fork (); wait_for_sigthread (); cygbench ("fork-child"); + cygwin_finished_initializing = true; return 0; } @@ -458,7 +459,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)", myself->progname, myself->progname, c_flags, &si, &pi); - __malloc_lock (); + bool locked = __malloc_lock (); void *newheap; newheap = cygheap_setup_for_child (&ch, cygheap->fdtab.need_fixup_before ()); rc = CreateProcess (myself->progname, /* image to run */ @@ -483,6 +484,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, /* Restore impersonation */ cygheap->user.reimpersonate (); cygheap_setup_for_child_cleanup (newheap, &ch, 0); + __malloc_unlock (); return -1; } @@ -573,6 +575,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, dll_bss_start, dll_bss_end, impure_beg, impure_end, NULL); __malloc_unlock (); + locked = false; MALLOC_CHECK; if (!rc) goto cleanup; @@ -622,6 +625,9 @@ fork_parent (HANDLE& hParent, dll *&first_dll, /* Common cleanup code for failure cases */ cleanup: + if (locked) + __malloc_unlock (); + /* Remember to de-allocate the fd table. */ if (pi.hProcess) ForceCloseHandle1 (pi.hProcess, childhProc); @@ -725,7 +731,7 @@ vfork () debug_printf ("cygheap->ctty_on_hold %p, cygheap->open_fhs %d", cygheap->ctty_on_hold, cygheap->open_fhs); int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1; debug_printf ("%d = vfork()", res); - call_signal_handler_now (); // FIXME: racy + _my_tls.call_signal_handler (); // FIXME: racy vf->tls = _my_tls; return res; } @@ -757,7 +763,7 @@ vfork () debug_printf ("exiting vfork, pid %d", pid); sig_dispatch_pending (); - call_signal_handler_now (); // FIXME: racy + _my_tls.call_signal_handler (); // FIXME: racy _my_tls = vf->tls; return pid; #endif diff --git a/winsup/cygwin/gendef b/winsup/cygwin/gendef index b391d501e..72afbc1c9 100755 --- a/winsup/cygwin/gendef +++ b/winsup/cygwin/gendef @@ -91,86 +91,99 @@ EOF .stabs "_sigfe:F(0,1)",36,0,0,__sigbe __sigfe: + pushl %ebx pushl %edx - movl %fs:4,%edx -1: movl \$1,%eax - lock xchgl %eax,$tls::stacklock(%edx) - cmpl %eax,%eax - jz 2f - xorl %eax,%eax - call _low_priority_sleep - jmp 1b -2: movl \$4,%eax - xadd %eax,$tls::stackptr(%edx) - decl $tls::stacklock(%edx) - leal __sigbe,%edx - xchgl %edx,8(%esp) - movl %edx,(%eax) - popl %edx +1: movl %fs:4,%edx # location of bottom of stack + movl \$1,%eax # potential lock value + lock xchgl %eax,$tls::stacklock(%edx) # see if we can grab it + orl %eax,%eax # it will be zero + jz 2f # if so + xorl %eax,%eax # nope. It was not zero + call _low_priority_sleep # should be a short-time thing, so + jmp 1b # sleep and loop +2: movl \$4,%eax # have the lock, now increment the + xadd %eax,$tls::stackptr(%edx) # stack pointer and get pointer + leal __sigbe,%ebx # new place to return to + xchgl %ebx,12(%esp) # exchange with real return value + movl %ebx,(%eax) # store real return value on alt stack + decl $tls::stacklock(%edx) # remove lock + popl %edx # restore saved value + popl %ebx ret .global __sigbe .stabs "_sigbe:F(0,1)",36,0,0,__sigbe __sigbe: - pushl %edx - pushl %eax - movl %fs:4,%edx -1: movl \$1,%eax - lock xchgl %eax,$tls::stacklock(%edx) - cmpl %eax,%eax - jz 2f - xorl %eax,%eax - call _low_priority_sleep - jmp 1b -2: movl \$-4,%eax - xadd %eax,$tls::stackptr(%edx) - decl $tls::stacklock(%edx) - xchgl %edx,-4(%eax) - xchgl %edx,4(%esp) + pushl %ebx + pushl %edx # return here after cygwin syscall + pushl %eax # don't clobber +1: movl %fs:4,%edx # address of bottom of tls + movl \$1,%eax # potential lock value + lock xchgl %eax,$tls::stacklock(%edx) # see if we can grab it + orl %eax,%eax # it will be zero + jz 2f # if so + xorl %eax,%eax # nope. not zero + call _low_priority_sleep # sleep + jmp 1b # and loop +2: movl \$-4,%eax # now decrement aux stack + xadd %eax,$tls::stackptr(%edx) # and get pointer +# xorl %ebx,%ebx + movl \$0x41774177,%ebx + xchgl %ebx,-4(%eax) # + xchgl %ebx,8(%esp) + decl $tls::stacklock(%edx) # release lock popl %eax + popl %edx ret - .global __ZN11_threadinfo3popEv -__ZN11_threadinfo3popEv: + .global __ZN7_cygtls3popEv +__ZN7_cygtls3popEv: 1: pushl %ebx + pushl %edx # FIXME: needed? movl %eax,%edx movl \$-4,%ebx xadd %ebx,$tls::pstackptr(%edx) - xorl %eax,%eax +# xorl %eax,%eax + movl 8(%esp),%eax xchgl %eax,-4(%ebx) + popl %edx # FIXME: needed? popl %ebx ret - .global __ZN11_threadinfo4lockEv -__ZN11_threadinfo4lockEv: - pushl %ebx - movl %eax,%ebx + .global __ZN7_cygtls4lockEv +__ZN7_cygtls4lockEv: + pushl %edi + movl %eax,%edi 1: movl \$1,%eax - lock xchgl %eax,$tls::pstacklock(%ebx) - cmpl %eax,%eax + lock xchgl %eax,$tls::pstacklock(%edi) + orl %eax,%eax jz 2f xorl %eax,%eax call _low_priority_sleep jmp 1b -2: xorl \$1,%eax - popl %ebx +2: popl %edi ret - .global __ZN11_threadinfo6unlockEv -__ZN11_threadinfo6unlockEv: + .global __ZN7_cygtls6unlockEv +__ZN7_cygtls6unlockEv: decl $tls::pstacklock(%eax) ret + .global __ZN7_cygtls6lockedEv +__ZN7_cygtls6lockedEv: + movl $tls::pstacklock(%eax),%eax + ret + .global _sigreturn .stabs "sigreturn:F(0,1)",36,0,0,_sigreturn _sigreturn: - addl \$4,%esp # Remove argument + addl \$4,%esp # Remove argument call _set_process_mask\@4 movl %fs:4,%ebx - cmpl \$0,$tls::sig(%ebx) # Did a signal come in? - jnz 3f # Yes, if non-zero +# cmpl \$0,$tls::sig(%ebx) # Did a signal come in? +# jnz 3f # Yes, if non-zero 1: popl %edx # saved errno testl %edx,%edx # Is it < 0 @@ -215,8 +228,7 @@ _sigdelayed: movl \$0,$tls::sig(%ebx) # zero the signal number as a # flag to the signal handler thread # that it is ok to set up sigsave -4: popl %ebx - jmp *%ebx +4: ret EOF } @@ -229,15 +241,26 @@ sub longjmp { .globl _longjmp _longjmp: +1: movl %fs:4,%edx + movl \$1,%eax + lock xchgl %eax,$tls::stacklock(%edx) + orl %eax,%eax + jz 2f + xorl %eax,%eax + call _low_priority_sleep + jmp 1b +2: leal ($tls::stack)(%edx),%eax + movl %eax,($tls::stackptr)(%edx) + pushl %ebp movl %esp,%ebp movl 8(%ebp),%edi movl 12(%ebp),%eax testl %eax,%eax - jne 0f + jne 3f incl %eax -0: - movl %eax,0(%edi) + +3: movl %eax,0(%edi) movl 24(%edi),%ebp pushfl popl %ebx @@ -250,14 +273,12 @@ _longjmp: movw %ax,%es movw 40(%edi),%ax movw %ax,%gs - movl %fs:4,%eax - leal ($tls::stack)(%eax),%edx - movl %edx,($tls::stackptr)(%eax) movl 0(%edi),%eax movl 4(%edi),%ebx movl 8(%edi),%ecx - movl 12(%edi),%edx movl 16(%edi),%esi + decl $tls::stacklock(%edx) + movl 12(%edi),%edx movl 20(%edi),%edi popfl ret diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc index 7ad38f11b..8bbc89bfb 100644 --- a/winsup/cygwin/init.cc +++ b/winsup/cygwin/init.cc @@ -27,7 +27,7 @@ HANDLE sync_startup; static void WINAPI threadfunc_fe (VOID *arg) { - _threadinfo::call ((DWORD (*) (void *, void *)) (((char **) _tlsbase)[OLDFUNC_OFFSET]), arg); + _cygtls::call ((DWORD (*) (void *, void *)) (((char **) _tlsbase)[OLDFUNC_OFFSET]), arg); } static DWORD WINAPI diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 37ef3a49c..4207c4d1a 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -318,7 +318,7 @@ low_priority_sleep (DWORD secs) if (!secs && wincap.has_switch_to_thread ()) { - for (int i = 0; i < 10; i++) + for (int i = 0; i < 3; i++) SwitchToThread (); } else diff --git a/winsup/cygwin/perthread.h b/winsup/cygwin/perthread.h index c721cefea..429b7cac9 100644 --- a/winsup/cygwin/perthread.h +++ b/winsup/cygwin/perthread.h @@ -58,7 +58,7 @@ class vfork_save public: int pid; DWORD frame[100]; - _threadinfo tls; + _cygtls tls; char **vfork_ebp; char **vfork_esp; int ctty; diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index e3723f863..a9a0b80e7 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -30,6 +30,7 @@ details. */ #include "shared_info.h" #include "cygheap.h" #include "fhandler.h" +#include "cygmalloc.h" static char NO_COPY pinfo_dummy[sizeof (_pinfo)] = {0}; @@ -755,22 +756,14 @@ winpids::enum9x (bool winpid) return nelem; } -NO_COPY CRITICAL_SECTION winpids::cs; - void winpids::set (bool winpid) { - EnterCriticalSection (&cs); + __malloc_lock (); npids = (this->*enum_processes) (winpid); if (pidlist) pidlist[npids] = 0; - LeaveCriticalSection (&cs); -} - -void -winpids::init () -{ - InitializeCriticalSection (&cs); + __malloc_unlock (); } DWORD diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index b0ddb6702..923b0bec7 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -179,7 +179,6 @@ class winpids DWORD enumNT (bool winpid); DWORD enum9x (bool winpid); void add (DWORD& nelem, bool, DWORD pid); - static CRITICAL_SECTION cs; public: DWORD npids; inline void reset () { npids = 0; release (); } @@ -196,7 +195,6 @@ public: inline _pinfo *operator [] (int i) const {return (_pinfo *) pinfolist[i];} ~winpids (); void release (); - static void init (); }; extern __inline pid_t diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 54232bb45..b0ac94a79 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -93,7 +93,7 @@ nanosleep (const struct timespec *rqtp, struct timespec *rmtp) rem = 0; if (rc == WAIT_OBJECT_0) { - (void) call_signal_handler_now (); + (void) _my_tls.call_signal_handler (); set_errno (EINTR); res = -1; } @@ -302,7 +302,7 @@ kill_pgrp (pid_t pid, siginfo_t& si) found++; } - if (killself && kill_worker (myself->pid, si)) + if (killself && !exit_state && kill_worker (myself->pid, si)) res = -1; if (!found) @@ -341,7 +341,7 @@ abort (void) set_signal_mask (sig_mask); raise (SIGABRT); - (void) call_signal_handler_now (); /* Call any signal handler */ + (void) _my_tls.call_signal_handler (); /* Call any signal handler */ do_exit (1); /* signal handler didn't exit. Goodbye. */ } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index caa22a5a9..c013e0d20 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -668,7 +668,7 @@ sig_send (_pinfo *p, int sig) If sending to this process, wait for notification that a signal has completed before returning. */ int __stdcall -sig_send (_pinfo *p, siginfo_t& si, _threadinfo *tls) +sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) { int rc = 1; bool its_me; @@ -747,7 +747,7 @@ sig_send (_pinfo *p, siginfo_t& si, _threadinfo *tls) if (!pack.si.si_uid) pack.si.si_uid = myself->uid; pack.pid = myself->pid; - pack.tls = (_threadinfo *) tls; + pack.tls = (_cygtls *) tls; if (wait_for_completion) { pack.wakeup = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); @@ -816,7 +816,7 @@ sig_send (_pinfo *p, siginfo_t& si, _threadinfo *tls) } if (wait_for_completion && si.si_signo != __SIGFLUSHFAST) - call_signal_handler_now (); + _my_tls.call_signal_handler (); out: if (pack.wakeup) diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index e9c762112..1176c919c 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -54,7 +54,7 @@ struct sigpacket { siginfo_t si; pid_t pid; - class _threadinfo *tls; + class _cygtls *tls; sigset_t *mask; union { @@ -91,9 +91,8 @@ void __stdcall subproc_init (); void __stdcall sigproc_terminate (); bool __stdcall proc_exists (_pinfo *) __attribute__ ((regparm(1))); bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1))); -int __stdcall sig_send (_pinfo *, siginfo_t&, class _threadinfo *tls = NULL) __attribute__ ((regparm (3))); +int __stdcall sig_send (_pinfo *, siginfo_t&, class _cygtls *tls = NULL) __attribute__ ((regparm (3))); int __stdcall sig_send (_pinfo *, int) __attribute__ ((regparm (2))); -void __stdcall signal_fixup_after_fork (); void __stdcall signal_fixup_after_exec (); void __stdcall wait_for_sigthread (); void __stdcall sigalloc (); diff --git a/winsup/cygwin/sync.cc b/winsup/cygwin/sync.cc index 2116ed0a8..f65e5a8e1 100644 --- a/winsup/cygwin/sync.cc +++ b/winsup/cygwin/sync.cc @@ -69,8 +69,10 @@ int muto::acquire (DWORD ms) { DWORD this_tid = GetCurrentThreadId (); +#if 0 if (exiting_thread) return this_tid == exiting_thread; +#endif if (tid != this_tid) { @@ -113,8 +115,6 @@ int muto::release () { DWORD this_tid = GetCurrentThreadId (); - if (exiting_thread) - return this_tid == exiting_thread; if (tid != this_tid || !visits) { diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 790fcb82b..ccf5848ca 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -461,7 +461,7 @@ readv (int fd, const struct iovec *const iov, const int iovcnt) } out: - if (res >= 0 || get_errno () != EINTR || !call_signal_handler_now ()) + if (res >= 0 || get_errno () != EINTR || !_my_tls.call_signal_handler ()) break; set_errno (e); } diff --git a/winsup/cygwin/termios.cc b/winsup/cygwin/termios.cc index e046984b6..c33054af5 100644 --- a/winsup/cygwin/termios.cc +++ b/winsup/cygwin/termios.cc @@ -23,6 +23,7 @@ details. */ #include "cygwin/version.h" #include "perprocess.h" #include "sigproc.h" +#include "cygtls.h" #include /* tcsendbreak: POSIX 7.2.2.1 */ @@ -146,7 +147,7 @@ tcsetattr (int fd, int a, const struct termios *t) e = get_errno (); break; case bg_signalled: - if (call_signal_handler_now ()) + if (_my_tls.call_signal_handler ()) continue; res = -1; /* fall through intentionally */ diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 361981777..7d68b5f5f 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -348,7 +348,7 @@ private: #define WAIT_CANCELED (WAIT_OBJECT_0 + 1) -class _threadinfo; +class _cygtls; class pthread: public verifyable_object { public: @@ -360,7 +360,7 @@ public: bool valid; bool suspended; int cancelstate, canceltype; - _threadinfo *cygtls; + _cygtls *cygtls; HANDLE cancel_event; pthread_t joiner; diff --git a/winsup/cygwin/wait.cc b/winsup/cygwin/wait.cc index 8e5800b63..d92a32911 100644 --- a/winsup/cygwin/wait.cc +++ b/winsup/cygwin/wait.cc @@ -15,6 +15,7 @@ details. */ #include "sigproc.h" #include "perthread.h" #include "thread.h" +#include "cygtls.h" /* This is called _wait and not wait because the real wait is defined in libc/syscalls/syswait.c. It calls us. */ @@ -99,7 +100,7 @@ wait4 (int intpid, int *status, int options, struct rusage *r) if (w->status == -1) { set_sig_errno (EINTR); - call_signal_handler_now (); + _my_tls.call_signal_handler (); sawsig = true; res = -1; } @@ -114,7 +115,7 @@ wait4 (int intpid, int *status, int options, struct rusage *r) *status = w->status; done: - if (!sawsig || !call_signal_handler_now ()) + if (!sawsig || !_my_tls.call_signal_handler ()) break; } diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 9301e92b1..d8930f9c6 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -239,7 +239,7 @@ extern "C" int try_to_debug (bool waitloop = 1); void set_file_api_mode (codepage_type); -extern int cygwin_finished_initializing; +extern bool cygwin_finished_initializing; /**************************** Miscellaneous ******************************/