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:
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
Reference in New Issue
Block a user