diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 7b19686ae..4b04b3334 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,31 @@ +2013-03-31 Christopher Faylor + + * 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 * cygthread.cc (cygthread::terminate_thread): Only try to free diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h index 66d6b95aa..17da88ec6 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 f0a4e3e96..7ac30122b 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 4cade6a2b..b51076472 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 094c0a09a..f7f7756a2 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 e41922900..9815be280 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 015cbaf2b..4bf6f5630 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 5d2942bef..4ed3221dd 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 38d718fb3..699b34479 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::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 218e70f6a..71f301258 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 (); };