* 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.
This commit is contained in:
Christopher Faylor 2013-03-31 12:35:44 +00:00
parent 4332090c2d
commit 8f8eeb70ba
10 changed files with 111 additions and 62 deletions

View File

@ -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> 2013-03-29 Corinna Vinschen <corinna@vinschen.de>
* cygthread.cc (cygthread::terminate_thread): Only try to free * cygthread.cc (cygthread::terminate_thread): Only try to free

View File

@ -122,6 +122,7 @@ public:
int envc; int envc;
char **envp; char **envp;
HANDLE myself_pinfo; HANDLE myself_pinfo;
sigset_t sigmask;
int nchildren; int nchildren;
cchildren children[0]; cchildren children[0];
static cygheap_exec_info *alloc (); static cygheap_exec_info *alloc ();

View File

@ -611,37 +611,34 @@ init_cygheap::remove_tls (_cygtls *t, DWORD wait)
} }
} }
_cygtls * _cygtls __reg3 *
init_cygheap::find_tls (int sig) init_cygheap::find_tls (int sig, bool& issig_wait)
{ {
debug_printf ("sig %d\n", sig); debug_printf ("sig %d\n", sig);
tls_sentry here (INFINITE); 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; myfault efault;
if (efault.faulted ()) if (efault.faulted ())
threadlist[threadlist_ix]->remove (INFINITE); threadlist[ix]->remove (INFINITE);
else else
{ {
threadlist_ix = -1; ix = -1;
while (++threadlist_ix < (int) nthreads) while (++ix < (int) nthreads)
if (threadlist[threadlist_ix]->tid if (!threadlist[ix]->tid)
&& sigismember (&(threadlist[threadlist_ix]->sigwait_mask), sig)) continue;
else if (sigismember (&(threadlist[ix]->sigwait_mask), sig))
{ {
t = cygheap->threadlist[threadlist_ix]; t = cygheap->threadlist[ix];
issig_wait = true;
goto out; goto out;
} }
threadlist_ix = -1; else if (!t && !sigismember (&(threadlist[ix]->sigmask), sig))
while (++threadlist_ix < (int) nthreads) t = cygheap->threadlist[ix];
if (threadlist[threadlist_ix]->tid
&& !sigismember (&(threadlist[threadlist_ix]->sigmask), sig))
{
t = cygheap->threadlist[threadlist_ix];
break;
}
} }
out: out:
return t; return t;

View File

@ -398,7 +398,7 @@ struct init_cygheap: public mini_cygheap
void __reg1 init_tls_list ();; void __reg1 init_tls_list ();;
void __reg2 add_tls (_cygtls *); void __reg2 add_tls (_cygtls *);
void __reg3 remove_tls (_cygtls *, DWORD); void __reg3 remove_tls (_cygtls *, DWORD);
_cygtls __reg2 *find_tls (int); _cygtls __reg3 *find_tls (int, bool&);
}; };

View File

@ -397,7 +397,8 @@ check_sanity_and_sync (per_process *p)
__cygwin_user_data.cxx_malloc = &default_cygwin_cxx_malloc; __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) #define CYGWIN_GUARD (PAGE_READWRITE | PAGE_GUARD)
@ -654,6 +655,8 @@ child_info_spawn::handle_spawn ()
FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
h = NULL; h = NULL;
parent_sigmask = moreinfo->sigmask;
/* Setup our write end of the process pipe. Clear the one in the structure. /* 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 The destructor should never be called for this but, it can't hurt to be
safe. */ safe. */
@ -821,6 +824,9 @@ dll_crt0_1 (void *)
extern void initial_setlocale (); extern void initial_setlocale ();
_my_tls.incyg++; _my_tls.incyg++;
if (!in_forkee)
_my_tls.sigmask = parent_sigmask; /* always zero if started by non-cygwin
process */
if (dynamically_loaded) if (dynamically_loaded)
sigproc_init (); sigproc_init ();
@ -1009,6 +1015,7 @@ dll_crt0_1 (void *)
while ((*nav++ = *oav++) != NULL) while ((*nav++ = *oav++) != NULL)
continue; continue;
/* Handle any signals which may have arrived */ /* Handle any signals which may have arrived */
sig_dispatch_pending (false);
_my_tls.call_signal_handler (); _my_tls.call_signal_handler ();
_my_tls.incyg--; /* Not in Cygwin anymore */ _my_tls.incyg--; /* Not in Cygwin anymore */
cygwin_exit (user_data->main (__argc, newargv, *user_data->envptr)); cygwin_exit (user_data->main (__argc, newargv, *user_data->envptr));

View File

@ -1124,12 +1124,19 @@ signal_exit (int sig, siginfo_t *si)
int __stdcall int __stdcall
sigpacket::process () sigpacket::process ()
{ {
bool continue_now; int rc = 1;
struct sigaction dummy = global_sigs[SIGSTOP]; 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) if (!cygwin_finished_initializing)
continue_now = false; {
else rc = -1;
goto really_done;
}
if (si.si_signo == SIGCONT)
{ {
continue_now = ISSTATE (myself, PID_STOPPED); continue_now = ISSTATE (myself, PID_STOPPED);
myself->stopsig = 0; myself->stopsig = 0;
@ -1141,30 +1148,43 @@ sigpacket::process ()
sig_clear (SIGTTOU); sig_clear (SIGTTOU);
} }
int rc = 1;
sigproc_printf ("signal %d processing", si.si_signo); sigproc_printf ("signal %d processing", si.si_signo);
struct sigaction& thissig = global_sigs[si.si_signo];
myself->rusage_self.ru_nsignals++; myself->rusage_self.ru_nsignals++;
_cygtls *tls; _cygtls *tls;
if (sigtls) if (!sigtls)
{ {
tls = sigtls; tls = cygheap->find_tls (si.si_signo, issig_wait);
sigproc_printf ("using sigtls %p", sigtls); sigproc_printf ("using tls %p", tls);
} }
else else
{ {
tls = cygheap->find_tls (si.si_signo); tls = sigtls;
sigproc_printf ("using tls %p", tls); 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 */ /* Do stuff for gdb */
if ((HANDLE) *tls) if ((HANDLE) *tls)
tls->signal_debugger (si); 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) if (handler == SIG_IGN)
{ {
@ -1180,18 +1200,6 @@ sigpacket::process ()
goto stop; 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 */ /* Clear pending SIGCONT on stop signals */
if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU) if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
sig_clear (SIGCONT); sig_clear (SIGCONT);
@ -1218,7 +1226,7 @@ sigpacket::process ()
stop: stop:
handler = (void *) sig_handle_tty_stop; handler = (void *) sig_handle_tty_stop;
thissig = dummy; thissig = global_sigs[SIGSTOP];
goto dosig; goto dosig;
exit_sig: exit_sig:
@ -1248,9 +1256,10 @@ dispatch_sig:
done: done:
if (continue_now) if (continue_now)
{ {
tls->sig = SIGCONT; (tls ?: _main_tls)->sig = SIGCONT;
SetEvent (tls->signal_arrived); SetEvent (tls->signal_arrived);
} }
really_done:
sigproc_printf ("returning %d", rc); sigproc_printf ("returning %d", rc);
return rc; return rc;

View File

@ -835,9 +835,12 @@ child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_r
cygheap_exec_info * cygheap_exec_info *
cygheap_exec_info::alloc () cygheap_exec_info::alloc ()
{ {
return (cygheap_exec_info *) ccalloc_abort (HEAP_1_EXEC, 1, cygheap_exec_info *res =
(cygheap_exec_info *) ccalloc_abort (HEAP_1_EXEC, 1,
sizeof (cygheap_exec_info) sizeof (cygheap_exec_info)
+ (nprocs * sizeof (children[0]))); + (nprocs * sizeof (children[0])));
res->sigmask = _my_tls.sigmask;
return res;
} }
void void
@ -1237,7 +1240,6 @@ pending_signals::add (sigpacket& pack)
if (se->si.si_signo) if (se->si.si_signo)
return; return;
*se = pack; *se = pack;
se->mask = &pack.sigtls->sigmask;
se->next = NULL; se->next = NULL;
if (end) if (end)
end->next = se; end->next = se;
@ -1365,8 +1367,13 @@ wait_sig (VOID *)
lock_process::force_release (pack.sigtls); lock_process::force_release (pack.sigtls);
ForceCloseHandle1 (h, exit_thread); ForceCloseHandle1 (h, exit_thread);
if (res != WAIT_OBJECT_0) if (res != WAIT_OBJECT_0)
{
#ifdef DEBUGGING
try_to_debug();
#endif
system_printf ("WaitForSingleObject(%p) for thread exit returned %u", h, res); system_printf ("WaitForSingleObject(%p) for thread exit returned %u", h, res);
} }
}
break; break;
} }
if (clearwait && !have_execed) if (clearwait && !have_execed)

View File

@ -1,7 +1,7 @@
/* spawn.cc /* spawn.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 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. This file is part of Cygwin.

View File

@ -338,7 +338,7 @@ pthread::init_mainthread ()
api_fatal ("failed to create mainthread object"); api_fatal ("failed to create mainthread object");
} }
set_tls_self_pointer (thread); thread->set_tls_self_pointer ();
thread->thread_id = GetCurrentThreadId (); thread->thread_id = GetCurrentThreadId ();
if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
GetCurrentProcess (), &thread->win32_obj_id, GetCurrentProcess (), &thread->win32_obj_id,
@ -357,16 +357,16 @@ pthread::self ()
if (!thread) if (!thread)
{ {
thread = pthread_null::get_null_pthread (); thread = pthread_null::get_null_pthread ();
set_tls_self_pointer (thread); thread->set_tls_self_pointer ();
} }
return thread; return thread;
} }
void void
pthread::set_tls_self_pointer (pthread *thread) pthread::set_tls_self_pointer ()
{ {
thread->cygtls = &_my_tls; cygtls = &_my_tls;
_my_tls.tid = thread; _my_tls.tid = this;
} }
List<pthread> pthread::threads; List<pthread> pthread::threads;
@ -1912,14 +1912,14 @@ DWORD WINAPI
pthread::thread_init_wrapper (void *arg) pthread::thread_init_wrapper (void *arg)
{ {
pthread *thread = (pthread *) arg; pthread *thread = (pthread *) arg;
set_tls_self_pointer (thread); _my_tls.sigmask = thread->parent_sigmask;
thread->set_tls_self_pointer ();
thread->mutex.lock (); thread->mutex.lock ();
// if thread is detached force cleanup on exit // if thread is detached force cleanup on exit
if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL) if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL)
thread->joiner = thread; thread->joiner = thread;
_my_tls.sigmask = thread->parent_sigmask;
thread->mutex.unlock (); thread->mutex.unlock ();
debug_printf ("tid %p", &_my_tls); debug_printf ("tid %p", &_my_tls);

View File

@ -443,7 +443,7 @@ private:
void precreate (pthread_attr *); void precreate (pthread_attr *);
void postcreate (); void postcreate ();
bool create_cancel_event (); bool create_cancel_event ();
static void set_tls_self_pointer (pthread *); void set_tls_self_pointer ();
void cancel_self () __attribute__ ((noreturn)); void cancel_self () __attribute__ ((noreturn));
DWORD get_thread_id (); DWORD get_thread_id ();
}; };