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] |