* 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>
* cygthread.cc (cygthread::terminate_thread): Only try to free

View File

@ -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 ();

View File

@ -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;

View File

@ -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&);
};

View File

@ -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));

View File

@ -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;

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::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)
+ (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,8 +1367,13 @@ wait_sig (VOID *)
lock_process::force_release (pack.sigtls);
ForceCloseHandle1 (h, exit_thread);
if (res != WAIT_OBJECT_0)
{
#ifdef DEBUGGING
try_to_debug();
#endif
system_printf ("WaitForSingleObject(%p) for thread exit returned %u", h, res);
}
}
break;
}
if (clearwait && !have_execed)

View File

@ -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.

View File

@ -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);

View File

@ -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 ();
};