diff options
author | Christopher Faylor <me@cgf.cx> | 2013-03-31 12:35:44 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2013-03-31 12:35:44 +0000 |
commit | 8f8eeb70ba7354749c78bc5013eeb12f4c18fba0 (patch) | |
tree | 5a33777acf2ae03b9f4ef75de12bdccecd1df068 | |
parent | 4332090c2d497c08dd1c98df7702f861905b2508 (diff) | |
download | newlib-8f8eeb70ba7354749c78bc5013eeb12f4c18fba0.zip newlib-8f8eeb70ba7354749c78bc5013eeb12f4c18fba0.tar.gz newlib-8f8eeb70ba7354749c78bc5013eeb12f4c18fba0.tar.bz2 |
* child_info.h (cygheap_exec_info::sigmask): Declare new field.
* cygheap.cc (init_cygheap::find_tls): Rename threadlist_ix -> ix. Only take
one pass through thread list, looking for eligible threads to signal. Set a
new param indicating that function has found a sigwait* mask.
* cygheap.h (init_cygheap::find_tls): Reflect new parameter.
* dcrt0.cc (parent_sigmask): New variable.
(child_info_spawn::handle_spawn): Save parent's signal mask here.
(dll_crt0_1): Restore parent's signal mask to tls sigmask as appropriate. Call
sig_dispatch_pending to flush signal queue when we can finally do something
with signals.
* exceptions.cc (sigpacket::process): Avoid attempting to handle signals if we
haven't finished initializing. Rely on the fact that find_tls will do mask
checking and don't do it again. Delete ill-named 'dummy' variable.
* sigproc.cc (cygheap_exec_info::alloc): Save calling thread's signal mask in
new sigmask field.
(wait_sig): Try to debug when WFSO fails and DEBUGGING is defined.
* thread.cc (pthread::set_tls_self_pointer): Make this a true automatic method
rather than inexplicably relying on a thread parameter.
(pthread::thread_init_wrapper): Accommodate set_tls_self_pointer change to
non-static. Initialize sigmask before setting tid or suffer signal races.
* ehread.h (pthread::set_tls_self_pointer): Make non-static, delete parameter.
-rw-r--r-- | winsup/cygwin/ChangeLog | 28 | ||||
-rw-r--r-- | winsup/cygwin/child_info.h | 1 | ||||
-rw-r--r-- | winsup/cygwin/cygheap.cc | 33 | ||||
-rw-r--r-- | winsup/cygwin/cygheap.h | 2 | ||||
-rw-r--r-- | winsup/cygwin/dcrt0.cc | 9 | ||||
-rw-r--r-- | winsup/cygwin/exceptions.cc | 65 | ||||
-rw-r--r-- | winsup/cygwin/sigproc.cc | 17 | ||||
-rw-r--r-- | winsup/cygwin/spawn.cc | 2 | ||||
-rw-r--r-- | winsup/cygwin/thread.cc | 14 | ||||
-rw-r--r-- | winsup/cygwin/thread.h | 2 |
10 files changed, 111 insertions, 62 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 7b19686..4b04b33 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,31 @@ +2013-03-31 Christopher Faylor <me.cygwin2013@cgf.cx> + + * child_info.h (cygheap_exec_info::sigmask): Declare new field. + * cygheap.cc (init_cygheap::find_tls): Rename threadlist_ix -> ix. + Only take one pass through thread list, looking for eligible threads to + signal. Set a new param indicating that function has found a sigwait* + mask. + * cygheap.h (init_cygheap::find_tls): Reflect new parameter. + * dcrt0.cc (parent_sigmask): New variable. + (child_info_spawn::handle_spawn): Save parent's signal mask here. + (dll_crt0_1): Restore parent's signal mask to tls sigmask as + appropriate. Call sig_dispatch_pending to flush signal queue when we + can finally do something with signals. + * exceptions.cc (sigpacket::process): Avoid attempting to handle + signals if we haven't finished initializing. Rely on the fact that + find_tls will do mask checking and don't do it again. Delete ill-named + 'dummy' variable. + * sigproc.cc (cygheap_exec_info::alloc): Save calling thread's signal + mask in new sigmask field. + (wait_sig): Try to debug when WFSO fails and DEBUGGING is defined. + * thread.cc (pthread::set_tls_self_pointer): Make this a true automatic + method rather than inexplicably relying on a thread parameter. + (pthread::thread_init_wrapper): Accommodate set_tls_self_pointer change + to non-static. Initialize sigmask before setting tid or suffer signal + races. + * ehread.h (pthread::set_tls_self_pointer): Make non-static, delete + parameter. + 2013-03-29 Corinna Vinschen <corinna@vinschen.de> * cygthread.cc (cygthread::terminate_thread): Only try to free diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h index 66d6b95..17da88e 100644 --- a/winsup/cygwin/child_info.h +++ b/winsup/cygwin/child_info.h @@ -122,6 +122,7 @@ public: int envc; char **envp; HANDLE myself_pinfo; + sigset_t sigmask; int nchildren; cchildren children[0]; static cygheap_exec_info *alloc (); diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index f0a4e3e..7ac3012 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -611,37 +611,34 @@ init_cygheap::remove_tls (_cygtls *t, DWORD wait) } } -_cygtls * -init_cygheap::find_tls (int sig) +_cygtls __reg3 * +init_cygheap::find_tls (int sig, bool& issig_wait) { debug_printf ("sig %d\n", sig); tls_sentry here (INFINITE); - static int NO_COPY threadlist_ix; + static int NO_COPY ix; - _cygtls *t = _main_tls; + _cygtls *t = NULL; + issig_wait = false; myfault efault; if (efault.faulted ()) - threadlist[threadlist_ix]->remove (INFINITE); + threadlist[ix]->remove (INFINITE); else { - threadlist_ix = -1; - while (++threadlist_ix < (int) nthreads) - if (threadlist[threadlist_ix]->tid - && sigismember (&(threadlist[threadlist_ix]->sigwait_mask), sig)) + ix = -1; + while (++ix < (int) nthreads) + if (!threadlist[ix]->tid) + continue; + else if (sigismember (&(threadlist[ix]->sigwait_mask), sig)) { - t = cygheap->threadlist[threadlist_ix]; + t = cygheap->threadlist[ix]; + issig_wait = true; goto out; } - threadlist_ix = -1; - while (++threadlist_ix < (int) nthreads) - if (threadlist[threadlist_ix]->tid - && !sigismember (&(threadlist[threadlist_ix]->sigmask), sig)) - { - t = cygheap->threadlist[threadlist_ix]; - break; - } + else if (!t && !sigismember (&(threadlist[ix]->sigmask), sig)) + t = cygheap->threadlist[ix]; } out: return t; diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 4cade6a..b510764 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -398,7 +398,7 @@ struct init_cygheap: public mini_cygheap void __reg1 init_tls_list ();; void __reg2 add_tls (_cygtls *); void __reg3 remove_tls (_cygtls *, DWORD); - _cygtls __reg2 *find_tls (int); + _cygtls __reg3 *find_tls (int, bool&); }; diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 094c0a0..f7f7756 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -397,7 +397,8 @@ check_sanity_and_sync (per_process *p) __cygwin_user_data.cxx_malloc = &default_cygwin_cxx_malloc; } -child_info NO_COPY *child_proc_info = NULL; +child_info NO_COPY *child_proc_info; +static NO_COPY sigset_t parent_sigmask; #define CYGWIN_GUARD (PAGE_READWRITE | PAGE_GUARD) @@ -654,6 +655,8 @@ child_info_spawn::handle_spawn () FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) h = NULL; + parent_sigmask = moreinfo->sigmask; + /* Setup our write end of the process pipe. Clear the one in the structure. The destructor should never be called for this but, it can't hurt to be safe. */ @@ -821,6 +824,9 @@ dll_crt0_1 (void *) extern void initial_setlocale (); _my_tls.incyg++; + if (!in_forkee) + _my_tls.sigmask = parent_sigmask; /* always zero if started by non-cygwin + process */ if (dynamically_loaded) sigproc_init (); @@ -1009,6 +1015,7 @@ dll_crt0_1 (void *) while ((*nav++ = *oav++) != NULL) continue; /* Handle any signals which may have arrived */ + sig_dispatch_pending (false); _my_tls.call_signal_handler (); _my_tls.incyg--; /* Not in Cygwin anymore */ cygwin_exit (user_data->main (__argc, newargv, *user_data->envptr)); diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index e419229..9815be2 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1124,12 +1124,19 @@ signal_exit (int sig, siginfo_t *si) int __stdcall sigpacket::process () { - bool continue_now; - struct sigaction dummy = global_sigs[SIGSTOP]; + int rc = 1; + bool issig_wait = false; + bool continue_now = false; + struct sigaction& thissig = global_sigs[si.si_signo]; + void *handler = have_execed ? NULL : (void *) thissig.sa_handler; - if (si.si_signo != SIGCONT) - continue_now = false; - else + if (!cygwin_finished_initializing) + { + rc = -1; + goto really_done; + } + + if (si.si_signo == SIGCONT) { continue_now = ISSTATE (myself, PID_STOPPED); myself->stopsig = 0; @@ -1141,30 +1148,43 @@ sigpacket::process () sig_clear (SIGTTOU); } - int rc = 1; - sigproc_printf ("signal %d processing", si.si_signo); - struct sigaction& thissig = global_sigs[si.si_signo]; myself->rusage_self.ru_nsignals++; _cygtls *tls; - if (sigtls) + if (!sigtls) { - tls = sigtls; - sigproc_printf ("using sigtls %p", sigtls); + tls = cygheap->find_tls (si.si_signo, issig_wait); + sigproc_printf ("using tls %p", tls); } else { - tls = cygheap->find_tls (si.si_signo); - sigproc_printf ("using tls %p", tls); + tls = sigtls; + if (sigismember (&tls->sigwait_mask, si.si_signo)) + issig_wait = true; + else if (!sigismember (&tls->sigmask, si.si_signo)) + issig_wait = false; + else + tls = NULL; + } + + if (!tls || ISSTATE (myself, PID_STOPPED)) + { + sigproc_printf ("signal %d blocked", si.si_signo); + rc = -1; + goto done; } /* Do stuff for gdb */ if ((HANDLE) *tls) tls->signal_debugger (si); - void *handler = have_execed ? NULL : (void *) thissig.sa_handler; + if (issig_wait) + { + tls->sigwait_mask = 0; + goto dosig; + } if (handler == SIG_IGN) { @@ -1180,18 +1200,6 @@ sigpacket::process () goto stop; } - if (sigismember (&tls->sigwait_mask, si.si_signo)) - { - tls->sigwait_mask = 0; - goto dosig; - } - if (sigismember (&tls->sigmask, si.si_signo) || ISSTATE (myself, PID_STOPPED)) - { - sigproc_printf ("signal %d blocked", si.si_signo); - rc = -1; - goto done; - } - /* Clear pending SIGCONT on stop signals */ if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU) sig_clear (SIGCONT); @@ -1218,7 +1226,7 @@ sigpacket::process () stop: handler = (void *) sig_handle_tty_stop; - thissig = dummy; + thissig = global_sigs[SIGSTOP]; goto dosig; exit_sig: @@ -1248,9 +1256,10 @@ dispatch_sig: done: if (continue_now) { - tls->sig = SIGCONT; + (tls ?: _main_tls)->sig = SIGCONT; SetEvent (tls->signal_arrived); } +really_done: sigproc_printf ("returning %d", rc); return rc; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 015cbaf..4bf6f56 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -835,9 +835,12 @@ child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_r cygheap_exec_info * cygheap_exec_info::alloc () { - return (cygheap_exec_info *) ccalloc_abort (HEAP_1_EXEC, 1, - sizeof (cygheap_exec_info) - + (nprocs * sizeof (children[0]))); + cygheap_exec_info *res = + (cygheap_exec_info *) ccalloc_abort (HEAP_1_EXEC, 1, + sizeof (cygheap_exec_info) + + (nprocs * sizeof (children[0]))); + res->sigmask = _my_tls.sigmask; + return res; } void @@ -1237,7 +1240,6 @@ pending_signals::add (sigpacket& pack) if (se->si.si_signo) return; *se = pack; - se->mask = &pack.sigtls->sigmask; se->next = NULL; if (end) end->next = se; @@ -1365,7 +1367,12 @@ wait_sig (VOID *) lock_process::force_release (pack.sigtls); ForceCloseHandle1 (h, exit_thread); if (res != WAIT_OBJECT_0) - system_printf ("WaitForSingleObject(%p) for thread exit returned %u", h, res); + { +#ifdef DEBUGGING + try_to_debug(); +#endif + system_printf ("WaitForSingleObject(%p) for thread exit returned %u", h, res); + } } break; } diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 5d2942b..4ed3221 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -1,7 +1,7 @@ /* spawn.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. + 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 38d718f..699b344 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -338,7 +338,7 @@ pthread::init_mainthread () api_fatal ("failed to create mainthread object"); } - set_tls_self_pointer (thread); + thread->set_tls_self_pointer (); thread->thread_id = GetCurrentThreadId (); if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), &thread->win32_obj_id, @@ -357,16 +357,16 @@ pthread::self () if (!thread) { thread = pthread_null::get_null_pthread (); - set_tls_self_pointer (thread); + thread->set_tls_self_pointer (); } return thread; } void -pthread::set_tls_self_pointer (pthread *thread) +pthread::set_tls_self_pointer () { - thread->cygtls = &_my_tls; - _my_tls.tid = thread; + cygtls = &_my_tls; + _my_tls.tid = this; } List<pthread> pthread::threads; @@ -1912,14 +1912,14 @@ DWORD WINAPI pthread::thread_init_wrapper (void *arg) { pthread *thread = (pthread *) arg; - set_tls_self_pointer (thread); + _my_tls.sigmask = thread->parent_sigmask; + thread->set_tls_self_pointer (); thread->mutex.lock (); // if thread is detached force cleanup on exit if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL) thread->joiner = thread; - _my_tls.sigmask = thread->parent_sigmask; thread->mutex.unlock (); debug_printf ("tid %p", &_my_tls); diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 218e70f..71f3012 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -443,7 +443,7 @@ private: void precreate (pthread_attr *); void postcreate (); bool create_cancel_event (); - static void set_tls_self_pointer (pthread *); + void set_tls_self_pointer (); void cancel_self () __attribute__ ((noreturn)); DWORD get_thread_id (); }; |