diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 9490f86776..3bf0064ce6 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,5 +1,20 @@ 2003-03-27 Ulrich Drepper + * sysdeps/unix/sysv/linux/kernel-posix-timers.h: Don't declare + __timer_helper_thread. Declare __start_helper_thread, __helper_once, + and __helper_tid. + (struct timer): Remove th and bar field. + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Remove + debugging code. Create only one helper thread. + * sysdeps/unix/sysv/linux/timer_delete.c (timer_delete): Don't kill + helper thread. + * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread): + Renamed. Define statically. Use thread info from siginfo. + (__helper_once): New variable. + (__helper_tid): New variable. + (__reset_helper_control): New function. + (__start_helper_thread): New function. + * pthread_create.c (start_thread): Don't use setjmp inside __builtin_expect to work around gcc bug. diff --git a/nptl/sysdeps/unix/sysv/linux/timer_create.c b/nptl/sysdeps/unix/sysv/linux/timer_create.c index 97ffb6ddb6..915fa812e1 100644 --- a/nptl/sysdeps/unix/sysv/linux/timer_create.c +++ b/nptl/sysdeps/unix/sysv/linux/timer_create.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "kernel-posix-timers.h" @@ -138,12 +139,16 @@ timer_create (clock_id, evp, timerid) if (__no_posix_timers > 0) # endif { - sigset_t ss; - sigemptyset (&ss); - sigaddset (&ss, TIMER_SIG); - pthread_sigmask (SIG_BLOCK, &ss, NULL); - struct timer *newp; + /* Create the helper thread. */ + pthread_once (&__helper_once, __start_helper_thread); + if (__helper_tid == 0) + { + /* No resources to start the helper thread. */ + __set_errno (EAGAIN); + return -1; + } + struct timer *newp; newp = (struct timer *) malloc (sizeof (struct timer)); if (newp == NULL) return -1; @@ -176,57 +181,29 @@ timer_create (clock_id, evp, timerid) (void) pthread_attr_setdetachstate (&newp->attr, PTHREAD_CREATE_DETACHED); - /* Set up the barrier for sychronization. */ - (void) pthread_barrier_init (&newp->bar, NULL, 2); - - /* The helper thread needs only very little resources - and should go away automatically when canceled. */ - pthread_attr_t attr; - (void) pthread_attr_init (&attr); - (void) pthread_attr_setdetachstate (&attr, - PTHREAD_CREATE_DETACHED); - (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); - - /* Create the helper thread for this timer. */ - int res = pthread_create (&newp->th, &attr, - __timer_helper_thread, newp); - if (res != 0) - goto err_out; - - /* No need for the attribute anymore. */ - (void) pthread_attr_destroy (&attr); - /* Create the event structure for the kernel timer. */ struct sigevent sev; sev.sigev_value.sival_ptr = newp; - sev.sigev_signo = TIMER_SIG; + sev.sigev_signo = SIGTIMER; sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; /* This is the thread ID of the helper thread. */ - sev._sigev_un._pad[0] = ((struct pthread *) newp->th)->tid; - - /* Wait until the helper thread is set up. */ - (void) pthread_barrier_wait (&newp->bar); - - /* No need for the barrier anymore. */ - (void) pthread_barrier_destroy (&newp->bar); + sev._sigev_un._pad[0] = __helper_tid; /* Create the timer. */ INTERNAL_SYSCALL_DECL (err); - res = INTERNAL_SYSCALL (timer_create, err, 3, clock_id, &sev, - &newp->ktimerid); + int res = INTERNAL_SYSCALL (timer_create, err, 3, clock_id, &sev, + &newp->ktimerid); if (! INTERNAL_SYSCALL_ERROR_P (res, err)) { *timerid = (timer_t) newp; return 0; } - /* Something went wrong. Kill the thread. */ - pthread_cancel (newp->th); /* Free the resources. */ - res = INTERNAL_SYSCALL_ERRNO (res, err); - err_out: free (newp); - __set_errno (res); + + __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); + return -1; } } diff --git a/nptl/sysdeps/unix/sysv/linux/timer_delete.c b/nptl/sysdeps/unix/sysv/linux/timer_delete.c index 9028dc4efc..106e1ae883 100644 --- a/nptl/sysdeps/unix/sysv/linux/timer_delete.c +++ b/nptl/sysdeps/unix/sysv/linux/timer_delete.c @@ -58,10 +58,6 @@ timer_delete (timerid) __no_posix_timers = 1; # endif - /* We have to get rid of the helper thread if we created one. */ - if (kt->sigev_notify == SIGEV_THREAD) - (void) pthread_cancel (kt->th); - /* Free the memory. */ (void) free (kt); diff --git a/nptl/sysdeps/unix/sysv/linux/timer_routines.c b/nptl/sysdeps/unix/sysv/linux/timer_routines.c index 3f69aa64fd..e9ece9f488 100644 --- a/nptl/sysdeps/unix/sysv/linux/timer_routines.c +++ b/nptl/sysdeps/unix/sysv/linux/timer_routines.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "kernel-posix-timers.h" @@ -40,24 +41,14 @@ timer_sigev_thread (void *arg) /* Helper function to support starting threads for SIGEV_THREAD. */ -void * -attribute_hidden -__timer_helper_thread (void *arg) +static void * +timer_helper_thread (void *arg) { - /* Block all signals. */ + /* Block all signals. We will only wait for the signal the kernel + will send. */ sigset_t ss; - - sigfillset (&ss); - (void) pthread_sigmask (SIG_BLOCK, &ss, NULL); - - struct timer *tk = (struct timer *) arg; - - /* Synchronize with the parent. */ - (void) pthread_barrier_wait (&tk->bar); - - /* We will only wait for the signal the kernel will send. */ sigemptyset (&ss); - sigaddset (&ss, TIMER_SIG); + sigaddset (&ss, SIGTIMER); /* Endless loop of waiting for signals. The loop is only ended when the thread is canceled. */ @@ -65,15 +56,60 @@ __timer_helper_thread (void *arg) { siginfo_t si; - if (sigwaitinfo (&ss, &si) > 0 && si.si_timerid == tk->ktimerid) + if (sigwaitinfo (&ss, &si) > 0 && si.si_code == SI_TIMER) { + + struct timer *tk = (struct timer *) si.si_ptr; + /* That the signal we are waiting for. */ pthread_t th; - (void) pthread_create (&th, &tk->attr, timer_sigev_thread, arg); + (void) pthread_create (&th, &tk->attr, timer_sigev_thread, tk); } } } + +/* Control variable for helper thread creation. */ +pthread_once_t __helper_once attribute_hidden; + + +/* TID of the helper thread. */ +pid_t __helper_tid attribute_hidden; + + +/* Reset variables so that after a fork a new helper thread gets started. */ +static void +reset_helper_control (void) +{ + __helper_once = PTHREAD_ONCE_INIT; + __helper_tid = 0; +} + + +void +attribute_hidden +__start_helper_thread (void) +{ + /* The helper thread needs only very little resources + and should go away automatically when canceled. */ + pthread_attr_t attr; + (void) pthread_attr_init (&attr); + (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + /* Create the helper thread for this timer. */ + pthread_t th; + int res = pthread_create (&th, &attr, timer_helper_thread, NULL); + if (res == 0) + /* We managed to start the helper thread. */ + __helper_tid = ((struct pthread *) th)->tid; + + /* No need for the attribute anymore. */ + (void) pthread_attr_destroy (&attr); + + /* We have to make sure that after fork()ing a new helper thread can + be created. */ + pthread_atfork (NULL, NULL, reset_helper_control); +} #endif #ifndef __ASSUME_POSIX_TIMERS