This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.
Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
| Other format: | [Raw text] | |
There is a race condition in linuxthreads during thread creation on
architectures that use a dedicated thread register. Between the point the
thread is created and inserted in the list of active threads, and the
point the thread register is initialized in the child a cancel signal may
arrive, with the thread manager calling pthread_handle_exit. The newly
created thread now calls pthread_handle_sigcancel, which uses thread_self
to find itself. But since the thread register is not yet initialized it
still points to the manager thread, and the signal handler falls trough to
__pthread_manager_sighandler. Now if main is calling exit without joining
the threads it is waiting for all threads to terminate, but if the new
thread goes on waiting on a condition or similar it will never be able to
exit.
To fix this race I have blocked the cancel signal in the manager around
the clone call, so that the child does not call the signal handler before
thread_self is initialized.
An easy way to reproduce the race is to insert a sleep in
pthread_start_thread before INIT_THREAD_SELF.
Andreas.
2001-11-20 Andreas Schwab <schwab@suse.de>
* manager.c (pthread_handle_create): Make sure the cancel signal
is initially blocked in the child so that it can initialize
thread_self before the signal is handled.
--- linuxthreads/manager.c.~1.73.~ Wed Sep 12 15:09:52 2001
+++ linuxthreads/manager.c Tue Nov 20 22:55:36 2001
@@ -611,6 +611,13 @@
if ((mask & (__pthread_threads_events.event_bits[idx]
| event_maskp->event_bits[idx])) != 0)
{
+ sigset_t newmask, oldmask;
+
+ /* Block cancel signal in the child until it is fully
+ initialized. */
+ sigemptyset(&newmask);
+ sigaddset(&newmask, __pthread_sig_cancel);
+ sigprocmask(SIG_BLOCK, &newmask, &oldmask);
/* Lock the mutex the child will use now so that it will stop. */
__pthread_lock(new_thread->p_lock, NULL);
@@ -638,6 +645,8 @@
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
__pthread_sig_cancel, new_thread);
#endif
+ if (pid != 0)
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
if (pid != -1)
{
/* Now fill in the information about the new thread in
@@ -663,6 +672,13 @@
}
if (pid == 0)
{
+ sigset_t newmask, oldmask;
+
+ /* Block cancel signal in the child until it is fully
+ initialized. */
+ sigemptyset(&newmask);
+ sigaddset(&newmask, __pthread_sig_cancel);
+ sigprocmask(SIG_BLOCK, &newmask, &oldmask);
#ifdef NEED_SEPARATE_REGISTER_STACK
pid = __clone2(pthread_start_thread,
(void **)new_thread_bottom,
@@ -678,6 +694,8 @@
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
__pthread_sig_cancel, new_thread);
#endif /* !NEED_SEPARATE_REGISTER_STACK */
+ if (pid != 0)
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
/* Check if cloning succeeded */
if (pid == -1) {
--
Andreas Schwab "And now for something
Andreas.Schwab@suse.de completely different."
SuSE Labs, SuSE GmbH, Schanzäckerstr. 10, D-90443 Nürnberg
Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |