1 /* Copyright (C) 2003-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, see <https://www.gnu.org/licenses/>. */
22 #include <sysdep-cancel.h>
24 #include "kernel-posix-timers.h"
27 /* List of active SIGEV_THREAD timers. */
28 struct timer
*__timer_active_sigev_thread
;
30 /* Lock for _timer_active_sigev_thread. */
31 pthread_mutex_t __timer_active_sigev_thread_lock
= PTHREAD_MUTEX_INITIALIZER
;
33 struct thread_start_data
35 void (*thrfunc
) (sigval_t
);
40 /* Helper thread to call the user-provided function. */
42 timer_sigev_thread (void *arg
)
44 signal_unblock_sigtimer ();
46 struct thread_start_data
*td
= (struct thread_start_data
*) arg
;
47 void (*thrfunc
) (sigval_t
) = td
->thrfunc
;
48 sigval_t sival
= td
->sival
;
50 /* The TD object was allocated in timer_helper_thread. */
53 /* Call the user-provided function. */
60 /* Helper function to support starting threads for SIGEV_THREAD. */
61 static _Noreturn
void *
62 timer_helper_thread (void *arg
)
64 /* Endless loop of waiting for signals. The loop is only ended when
65 the thread is canceled. */
70 while (__sigwaitinfo (&sigtimer_set
, &si
) < 0);
71 if (si
.si_code
== SI_TIMER
)
73 struct timer
*tk
= (struct timer
*) si
.si_ptr
;
75 /* Check the timer is still used and will not go away
76 while we are reading the values here. */
77 __pthread_mutex_lock (&__timer_active_sigev_thread_lock
);
79 struct timer
*runp
= __timer_active_sigev_thread
;
88 struct thread_start_data
*td
= malloc (sizeof (*td
));
90 /* There is not much we can do if the allocation fails. */
93 /* This is the signal we are waiting for. */
94 td
->thrfunc
= tk
->thrfunc
;
95 td
->sival
= tk
->sival
;
98 __pthread_create (&th
, &tk
->attr
, timer_sigev_thread
, td
);
102 __pthread_mutex_unlock (&__timer_active_sigev_thread_lock
);
108 /* Control variable for helper thread creation. */
109 pthread_once_t __timer_helper_once
= PTHREAD_ONCE_INIT
;
112 /* TID of the helper thread. */
113 pid_t __timer_helper_tid
;
116 /* Reset variables so that after a fork a new helper thread gets started. */
118 __timer_fork_subprocess (void)
120 __timer_helper_once
= PTHREAD_ONCE_INIT
;
121 __timer_helper_tid
= 0;
126 __timer_start_helper_thread (void)
128 /* The helper thread needs only very little resources
129 and should go away automatically when canceled. */
131 __pthread_attr_init (&attr
);
132 __pthread_attr_setstacksize (&attr
, __pthread_get_minstack (&attr
));
134 /* Block all signals in the helper thread but SIGSETXID. */
137 __sigdelset (&ss
, SIGSETXID
);
138 int res
= __pthread_attr_setsigmask_internal (&attr
, &ss
);
141 __pthread_attr_destroy (&attr
);
145 /* Create the helper thread for this timer. */
147 res
= __pthread_create (&th
, &attr
, timer_helper_thread
, NULL
);
149 /* We managed to start the helper thread. */
150 __timer_helper_tid
= ((struct pthread
*) th
)->tid
;
152 /* No need for the attribute anymore. */
153 __pthread_attr_destroy (&attr
);