1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-28 00:21:52 +03:00

Linux: Move timer helper routines from librt to libc

This adds several temporary GLIBC_PRIVATE exports.  The symbol names
are changed so that they all start with __timer_.

It is now possible to invoke the fork handler directly, so
pthread_atfork is no longer necessary.  The associated error cannot
happen anymore, and cancellation handling can be removed from
the helper thread routine.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Florian Weimer
2021-06-25 10:51:31 +02:00
parent 1a5a653be2
commit 2c16cb88a6
7 changed files with 64 additions and 50 deletions

View File

@ -17,7 +17,7 @@
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
ifeq ($(subdir),rt) ifeq ($(subdir),rt)
librt-sysdep_routines += timer_routines sysdep_routines += timer_routines
tests += tst-mqueue8x tests += tst-mqueue8x
CFLAGS-tst-mqueue8x.c += -fexceptions CFLAGS-tst-mqueue8x.c += -fexceptions

View File

@ -20,6 +20,7 @@
#define _FORK_H #define _FORK_H
#include <assert.h> #include <assert.h>
#include <kernel-posix-timers.h>
#include <ldsodefs.h> #include <ldsodefs.h>
#include <list.h> #include <list.h>
#include <mqueue.h> #include <mqueue.h>
@ -44,6 +45,7 @@ fork_system_setup_after_fork (void)
__default_pthread_attr_lock = LLL_LOCK_INITIALIZER; __default_pthread_attr_lock = LLL_LOCK_INITIALIZER;
call_function_static_weak (__mq_notify_fork_subprocess); call_function_static_weak (__mq_notify_fork_subprocess);
call_function_static_weak (__timer_fork_subprocess);
} }
/* In case of a fork() call the memory allocation in the child will be /* In case of a fork() call the memory allocation in the child will be

View File

@ -282,6 +282,11 @@ libc {
__pread64_nocancel; __pread64_nocancel;
__close_nocancel; __close_nocancel;
__sigtimedwait; __sigtimedwait;
__timer_active_sigev_thread;
__timer_active_sigev_thread_lock;
__timer_helper_once;
__timer_helper_tid;
__timer_start_helper_thread;
# functions used by nscd # functions used by nscd
__netlink_assert_response; __netlink_assert_response;
} }

View File

@ -26,19 +26,27 @@
extern int __no_posix_timers attribute_hidden; extern int __no_posix_timers attribute_hidden;
/* Callback to start helper thread. */ /* Callback to start helper thread. */
extern void __start_helper_thread (void) attribute_hidden; extern void __timer_start_helper_thread (void);
libc_hidden_proto (__timer_start_helper_thread)
/* Control variable for helper thread creation. */ /* Control variable for helper thread creation. */
extern pthread_once_t __helper_once attribute_hidden; extern pthread_once_t __timer_helper_once;
libc_hidden_proto (__timer_helper_once)
/* Called from fork so that the new subprocess re-creates the
notification thread if necessary. */
void __timer_fork_subprocess (void) attribute_hidden;
/* TID of the helper thread. */ /* TID of the helper thread. */
extern pid_t __helper_tid attribute_hidden; extern pid_t __timer_helper_tid;
libc_hidden_proto (__timer_helper_tid)
/* List of active SIGEV_THREAD timers. */ /* List of active SIGEV_THREAD timers. */
extern struct timer *__active_timer_sigev_thread attribute_hidden; extern struct timer *__timer_active_sigev_thread;
/* Lock for the __active_timer_sigev_thread. */ libc_hidden_proto (__timer_active_sigev_thread)
extern pthread_mutex_t __active_timer_sigev_thread_lock attribute_hidden; /* Lock for __timer_active_sigev_thread. */
extern pthread_mutex_t __timer_active_sigev_thread_lock;
libc_hidden_proto (__timer_active_sigev_thread_lock)
/* Type of timers in the kernel. */ /* Type of timers in the kernel. */
typedef int kernel_timer_t; typedef int kernel_timer_t;

View File

@ -74,8 +74,8 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
else else
{ {
/* Create the helper thread. */ /* Create the helper thread. */
pthread_once (&__helper_once, __start_helper_thread); pthread_once (&__timer_helper_once, __timer_start_helper_thread);
if (__helper_tid == 0) if (__timer_helper_tid == 0)
{ {
/* No resources to start the helper thread. */ /* No resources to start the helper thread. */
__set_errno (EAGAIN); __set_errno (EAGAIN);
@ -118,7 +118,7 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
{ .sigev_value.sival_ptr = newp, { .sigev_value.sival_ptr = newp,
.sigev_signo = SIGTIMER, .sigev_signo = SIGTIMER,
.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID, .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID,
._sigev_un = { ._pad = { [0] = __helper_tid } } }; ._sigev_un = { ._pad = { [0] = __timer_helper_tid } } };
/* Create the timer. */ /* Create the timer. */
int res; int res;
@ -132,10 +132,10 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
} }
/* Add to the queue of active timers with thread delivery. */ /* Add to the queue of active timers with thread delivery. */
pthread_mutex_lock (&__active_timer_sigev_thread_lock); pthread_mutex_lock (&__timer_active_sigev_thread_lock);
newp->next = __active_timer_sigev_thread; newp->next = __timer_active_sigev_thread;
__active_timer_sigev_thread = newp; __timer_active_sigev_thread = newp;
pthread_mutex_unlock (&__active_timer_sigev_thread_lock); pthread_mutex_unlock (&__timer_active_sigev_thread_lock);
*timerid = timer_to_timerid (newp); *timerid = timer_to_timerid (newp);
} }

View File

@ -42,12 +42,12 @@ timer_delete (timer_t timerid)
struct timer *kt = timerid_to_timer (timerid); struct timer *kt = timerid_to_timer (timerid);
/* Remove the timer from the list. */ /* Remove the timer from the list. */
pthread_mutex_lock (&__active_timer_sigev_thread_lock); pthread_mutex_lock (&__timer_active_sigev_thread_lock);
if (__active_timer_sigev_thread == kt) if (__timer_active_sigev_thread == kt)
__active_timer_sigev_thread = kt->next; __timer_active_sigev_thread = kt->next;
else else
{ {
struct timer *prevp = __active_timer_sigev_thread; struct timer *prevp = __timer_active_sigev_thread;
while (prevp->next != NULL) while (prevp->next != NULL)
if (prevp->next == kt) if (prevp->next == kt)
{ {
@ -57,7 +57,7 @@ timer_delete (timer_t timerid)
else else
prevp = prevp->next; prevp = prevp->next;
} }
pthread_mutex_unlock (&__active_timer_sigev_thread_lock); pthread_mutex_unlock (&__timer_active_sigev_thread_lock);
free (kt); free (kt);
} }

View File

@ -26,10 +26,13 @@
/* List of active SIGEV_THREAD timers. */ /* List of active SIGEV_THREAD timers. */
struct timer *__active_timer_sigev_thread; struct timer *__timer_active_sigev_thread __attribute__ ((nocommon));
/* Lock for the __active_timer_sigev_thread. */ libc_hidden_data_def (__timer_active_sigev_thread)
pthread_mutex_t __active_timer_sigev_thread_lock = PTHREAD_MUTEX_INITIALIZER;
/* Lock for _timer_active_sigev_thread. */
pthread_mutex_t __timer_active_sigev_thread_lock __attribute__ ((nocommon))
= PTHREAD_MUTEX_INITIALIZER;
libc_hidden_data_def (__timer_active_sigev_thread_lock)
struct thread_start_data struct thread_start_data
{ {
@ -59,7 +62,7 @@ timer_sigev_thread (void *arg)
/* Helper function to support starting threads for SIGEV_THREAD. */ /* Helper function to support starting threads for SIGEV_THREAD. */
static void * static _Noreturn void *
timer_helper_thread (void *arg) timer_helper_thread (void *arg)
{ {
/* Endless loop of waiting for signals. The loop is only ended when /* Endless loop of waiting for signals. The loop is only ended when
@ -68,16 +71,16 @@ timer_helper_thread (void *arg)
{ {
siginfo_t si; siginfo_t si;
while (sigwaitinfo (&sigtimer_set, &si) < 0); while (__sigwaitinfo (&sigtimer_set, &si) < 0);
if (si.si_code == SI_TIMER) if (si.si_code == SI_TIMER)
{ {
struct timer *tk = (struct timer *) si.si_ptr; struct timer *tk = (struct timer *) si.si_ptr;
/* Check the timer is still used and will not go away /* Check the timer is still used and will not go away
while we are reading the values here. */ while we are reading the values here. */
pthread_mutex_lock (&__active_timer_sigev_thread_lock); __pthread_mutex_lock (&__timer_active_sigev_thread_lock);
struct timer *runp = __active_timer_sigev_thread; struct timer *runp = __timer_active_sigev_thread;
while (runp != NULL) while (runp != NULL)
if (runp == tk) if (runp == tk)
break; break;
@ -96,45 +99,44 @@ timer_helper_thread (void *arg)
td->sival = tk->sival; td->sival = tk->sival;
pthread_t th; pthread_t th;
pthread_create (&th, &tk->attr, timer_sigev_thread, td); __pthread_create (&th, &tk->attr, timer_sigev_thread, td);
} }
} }
pthread_mutex_unlock (&__active_timer_sigev_thread_lock); __pthread_mutex_unlock (&__timer_active_sigev_thread_lock);
} }
else if (si.si_code == SI_TKILL)
/* The thread is canceled. */
pthread_exit (NULL);
} }
} }
/* Control variable for helper thread creation. */ /* Control variable for helper thread creation. */
pthread_once_t __helper_once attribute_hidden; pthread_once_t __timer_helper_once __attribute__ ((nocommon))
= PTHREAD_ONCE_INIT;
libc_hidden_data_def (__timer_helper_once)
/* TID of the helper thread. */ /* TID of the helper thread. */
pid_t __helper_tid attribute_hidden; pid_t __timer_helper_tid __attribute__ ((nocommon));
libc_hidden_data_def (__timer_helper_tid)
/* Reset variables so that after a fork a new helper thread gets started. */ /* Reset variables so that after a fork a new helper thread gets started. */
static void void
reset_helper_control (void) __timer_fork_subprocess (void)
{ {
__helper_once = PTHREAD_ONCE_INIT; __timer_helper_once = PTHREAD_ONCE_INIT;
__helper_tid = 0; __timer_helper_tid = 0;
} }
void void
attribute_hidden __timer_start_helper_thread (void)
__start_helper_thread (void)
{ {
/* The helper thread needs only very little resources /* The helper thread needs only very little resources
and should go away automatically when canceled. */ and should go away automatically when canceled. */
pthread_attr_t attr; pthread_attr_t attr;
(void) pthread_attr_init (&attr); __pthread_attr_init (&attr);
(void) pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr)); __pthread_attr_setstacksize (&attr, __pthread_get_minstack (&attr));
/* Block all signals in the helper thread but SIGSETXID. */ /* Block all signals in the helper thread but SIGSETXID. */
sigset_t ss; sigset_t ss;
@ -143,21 +145,18 @@ __start_helper_thread (void)
int res = __pthread_attr_setsigmask_internal (&attr, &ss); int res = __pthread_attr_setsigmask_internal (&attr, &ss);
if (res != 0) if (res != 0)
{ {
pthread_attr_destroy (&attr); __pthread_attr_destroy (&attr);
return; return;
} }
/* Create the helper thread for this timer. */ /* Create the helper thread for this timer. */
pthread_t th; pthread_t th;
res = pthread_create (&th, &attr, timer_helper_thread, NULL); res = __pthread_create (&th, &attr, timer_helper_thread, NULL);
if (res == 0) if (res == 0)
/* We managed to start the helper thread. */ /* We managed to start the helper thread. */
__helper_tid = ((struct pthread *) th)->tid; __timer_helper_tid = ((struct pthread *) th)->tid;
/* No need for the attribute anymore. */ /* No need for the attribute anymore. */
(void) pthread_attr_destroy (&attr); __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);
} }
libc_hidden_def (__timer_start_helper_thread)