1 | /* Helper code for POSIX timer implementation on NPTL. |
2 | Copyright (C) 2000-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public License as |
7 | published by the Free Software Foundation; either version 2.1 of the |
8 | License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; see the file COPYING.LIB. If |
17 | not, see <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <assert.h> |
20 | #include <errno.h> |
21 | #include <pthread.h> |
22 | #include <stddef.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <sysdep.h> |
26 | #include <time.h> |
27 | #include <unistd.h> |
28 | #include <sys/syscall.h> |
29 | |
30 | #include "posix-timer.h" |
31 | #include <timer_routines.h> |
32 | |
33 | #ifndef DELAYTIMER_MAX |
34 | # define DELAYTIMER_MAX INT_MAX |
35 | #endif |
36 | |
37 | /* Number of threads used. */ |
38 | #define THREAD_MAXNODES 16 |
39 | |
40 | /* Array containing the descriptors for the used threads. */ |
41 | static struct thread_node thread_array[THREAD_MAXNODES]; |
42 | |
43 | /* Static array with the structures for all the timers. */ |
44 | struct timer_node __timer_array[TIMER_MAX]; |
45 | |
46 | /* Global lock to protect operation on the lists. */ |
47 | pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER; |
48 | |
49 | /* Variable to protect initialization. */ |
50 | pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT; |
51 | |
52 | /* Nonzero if initialization of timer implementation failed. */ |
53 | int __timer_init_failed; |
54 | |
55 | /* Node for the thread used to deliver signals. */ |
56 | struct thread_node __timer_signal_thread_rclk; |
57 | |
58 | /* Lists to keep free and used timers and threads. */ |
59 | static struct list_head timer_free_list; |
60 | static struct list_head thread_free_list; |
61 | static struct list_head thread_active_list; |
62 | |
63 | |
64 | #ifdef __NR_rt_sigqueueinfo |
65 | extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *); |
66 | #endif |
67 | |
68 | |
69 | /* List handling functions. */ |
70 | static inline void |
71 | list_append (struct list_head *list, struct list_head *newp) |
72 | { |
73 | newp->prev = list->prev; |
74 | newp->next = list; |
75 | list->prev->next = newp; |
76 | list->prev = newp; |
77 | } |
78 | |
79 | static inline void |
80 | list_insbefore (struct list_head *list, struct list_head *newp) |
81 | { |
82 | list_append (list, newp); |
83 | } |
84 | |
85 | /* |
86 | * Like list_unlink_ip, except that calling it on a node that |
87 | * is already unlinked is disastrous rather than a noop. |
88 | */ |
89 | |
90 | static inline void |
91 | list_unlink (struct list_head *list) |
92 | { |
93 | struct list_head *lnext = list->next, *lprev = list->prev; |
94 | |
95 | lnext->prev = lprev; |
96 | lprev->next = lnext; |
97 | } |
98 | |
99 | static inline struct list_head * |
100 | list_first (struct list_head *list) |
101 | { |
102 | return list->next; |
103 | } |
104 | |
105 | static inline struct list_head * |
106 | list_null (struct list_head *list) |
107 | { |
108 | return list; |
109 | } |
110 | |
111 | static inline struct list_head * |
112 | list_next (struct list_head *list) |
113 | { |
114 | return list->next; |
115 | } |
116 | |
117 | static inline int |
118 | list_isempty (struct list_head *list) |
119 | { |
120 | return list->next == list; |
121 | } |
122 | |
123 | |
124 | /* Functions build on top of the list functions. */ |
125 | static inline struct thread_node * |
126 | thread_links2ptr (struct list_head *list) |
127 | { |
128 | return (struct thread_node *) ((char *) list |
129 | - offsetof (struct thread_node, links)); |
130 | } |
131 | |
132 | static inline struct timer_node * |
133 | timer_links2ptr (struct list_head *list) |
134 | { |
135 | return (struct timer_node *) ((char *) list |
136 | - offsetof (struct timer_node, links)); |
137 | } |
138 | |
139 | |
140 | /* Initialize a newly allocated thread structure. */ |
141 | static void |
142 | thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id) |
143 | { |
144 | if (attr != NULL) |
145 | thread->attr = *attr; |
146 | else |
147 | { |
148 | pthread_attr_init (attr: &thread->attr); |
149 | pthread_attr_setdetachstate (attr: &thread->attr, PTHREAD_CREATE_DETACHED); |
150 | } |
151 | |
152 | thread->exists = 0; |
153 | INIT_LIST_HEAD (&thread->timer_queue); |
154 | pthread_cond_init (cond: &thread->cond, cond_attr: 0); |
155 | thread->current_timer = 0; |
156 | thread->captured = pthread_self (); |
157 | thread->clock_id = clock_id; |
158 | } |
159 | |
160 | |
161 | /* Initialize the global lists, and acquire global resources. Error |
162 | reporting is done by storing a non-zero value to the global variable |
163 | timer_init_failed. */ |
164 | static void |
165 | init_module (void) |
166 | { |
167 | int i; |
168 | |
169 | INIT_LIST_HEAD (&timer_free_list); |
170 | INIT_LIST_HEAD (&thread_free_list); |
171 | INIT_LIST_HEAD (&thread_active_list); |
172 | |
173 | for (i = 0; i < TIMER_MAX; ++i) |
174 | { |
175 | list_append (list: &timer_free_list, newp: &__timer_array[i].links); |
176 | __timer_array[i].inuse = TIMER_FREE; |
177 | } |
178 | |
179 | for (i = 0; i < THREAD_MAXNODES; ++i) |
180 | list_append (list: &thread_free_list, newp: &thread_array[i].links); |
181 | |
182 | thread_init (thread: &__timer_signal_thread_rclk, attr: 0, CLOCK_REALTIME); |
183 | } |
184 | |
185 | |
186 | /* This is a handler executed in a child process after a fork() |
187 | occurs. It reinitializes the module, resetting all of the data |
188 | structures to their initial state. The mutex is initialized in |
189 | case it was locked in the parent process. */ |
190 | static void |
191 | reinit_after_fork (void) |
192 | { |
193 | init_module (); |
194 | pthread_mutex_init (mutex: &__timer_mutex, mutexattr: 0); |
195 | } |
196 | |
197 | |
198 | /* Called once form pthread_once in timer_init. This initializes the |
199 | module and ensures that reinit_after_fork will be executed in any |
200 | child process. */ |
201 | void |
202 | __timer_init_once (void) |
203 | { |
204 | init_module (); |
205 | pthread_atfork (prepare: 0, parent: 0, child: reinit_after_fork); |
206 | } |
207 | |
208 | |
209 | /* Deinitialize a thread that is about to be deallocated. */ |
210 | static void |
211 | thread_deinit (struct thread_node *thread) |
212 | { |
213 | assert (list_isempty (&thread->timer_queue)); |
214 | pthread_cond_destroy (cond: &thread->cond); |
215 | } |
216 | |
217 | |
218 | /* Allocate a thread structure from the global free list. Global |
219 | mutex lock must be held by caller. The thread is moved to |
220 | the active list. */ |
221 | struct thread_node * |
222 | __timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id) |
223 | { |
224 | struct list_head *node = list_first (list: &thread_free_list); |
225 | |
226 | if (node != list_null (list: &thread_free_list)) |
227 | { |
228 | struct thread_node *thread = thread_links2ptr (list: node); |
229 | list_unlink (list: node); |
230 | thread_init (thread, attr: desired_attr, clock_id); |
231 | list_append (list: &thread_active_list, newp: node); |
232 | return thread; |
233 | } |
234 | |
235 | return 0; |
236 | } |
237 | |
238 | |
239 | /* Return a thread structure to the global free list. Global lock |
240 | must be held by caller. */ |
241 | void |
242 | __timer_thread_dealloc (struct thread_node *thread) |
243 | { |
244 | thread_deinit (thread); |
245 | list_unlink (list: &thread->links); |
246 | list_append (list: &thread_free_list, newp: &thread->links); |
247 | } |
248 | |
249 | |
250 | /* Each of our threads which terminates executes this cleanup |
251 | handler. We never terminate threads ourselves; if a thread gets here |
252 | it means that the evil application has killed it. If the thread has |
253 | timers, these require servicing and so we must hire a replacement |
254 | thread right away. We must also unblock another thread that may |
255 | have been waiting for this thread to finish servicing a timer (see |
256 | timer_delete()). */ |
257 | |
258 | static void |
259 | thread_cleanup (void *val) |
260 | { |
261 | if (val != NULL) |
262 | { |
263 | struct thread_node *thread = val; |
264 | |
265 | /* How did the signal thread get killed? */ |
266 | assert (thread != &__timer_signal_thread_rclk); |
267 | |
268 | pthread_mutex_lock (mutex: &__timer_mutex); |
269 | |
270 | thread->exists = 0; |
271 | |
272 | /* We are no longer processing a timer event. */ |
273 | thread->current_timer = 0; |
274 | |
275 | if (list_isempty (list: &thread->timer_queue)) |
276 | __timer_thread_dealloc (thread); |
277 | else |
278 | (void) __timer_thread_start (thread); |
279 | |
280 | pthread_mutex_unlock (mutex: &__timer_mutex); |
281 | |
282 | /* Unblock potentially blocked timer_delete(). */ |
283 | pthread_cond_broadcast (cond: &thread->cond); |
284 | } |
285 | } |
286 | |
287 | |
288 | /* Handle a timer which is supposed to go off now. */ |
289 | static void |
290 | thread_expire_timer (struct thread_node *self, struct timer_node *timer) |
291 | { |
292 | self->current_timer = timer; /* Lets timer_delete know timer is running. */ |
293 | |
294 | pthread_mutex_unlock (mutex: &__timer_mutex); |
295 | |
296 | switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL)) |
297 | { |
298 | case SIGEV_NONE: |
299 | break; |
300 | |
301 | case SIGEV_SIGNAL: |
302 | #ifdef __NR_rt_sigqueueinfo |
303 | { |
304 | siginfo_t info; |
305 | |
306 | /* First, clear the siginfo_t structure, so that we don't pass our |
307 | stack content to other tasks. */ |
308 | memset (&info, 0, sizeof (siginfo_t)); |
309 | /* We must pass the information about the data in a siginfo_t |
310 | value. */ |
311 | info.si_signo = timer->event.sigev_signo; |
312 | info.si_code = SI_TIMER; |
313 | info.si_pid = timer->creator_pid; |
314 | info.si_uid = getuid (); |
315 | info.si_value = timer->event.sigev_value; |
316 | |
317 | INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info); |
318 | } |
319 | #else |
320 | if (pthread_kill (self->captured, timer->event.sigev_signo) != 0) |
321 | { |
322 | if (pthread_kill (self->id, timer->event.sigev_signo) != 0) |
323 | abort (); |
324 | } |
325 | #endif |
326 | break; |
327 | |
328 | case SIGEV_THREAD: |
329 | timer->event.sigev_notify_function (timer->event.sigev_value); |
330 | break; |
331 | |
332 | default: |
333 | assert (! "unknown event" ); |
334 | break; |
335 | } |
336 | |
337 | pthread_mutex_lock (mutex: &__timer_mutex); |
338 | |
339 | self->current_timer = 0; |
340 | |
341 | pthread_cond_broadcast (cond: &self->cond); |
342 | } |
343 | |
344 | |
345 | /* Thread function; executed by each timer thread. The job of this |
346 | function is to wait on the thread's timer queue and expire the |
347 | timers in chronological order as close to their scheduled time as |
348 | possible. */ |
349 | static void |
350 | __attribute__ ((noreturn)) |
351 | thread_func (void *arg) |
352 | { |
353 | struct thread_node *self = arg; |
354 | |
355 | /* Register cleanup handler, in case rogue application terminates |
356 | this thread. (This cannot happen to __timer_signal_thread, which |
357 | doesn't invoke application callbacks). */ |
358 | |
359 | pthread_cleanup_push (thread_cleanup, self); |
360 | |
361 | pthread_mutex_lock (mutex: &__timer_mutex); |
362 | |
363 | while (1) |
364 | { |
365 | struct list_head *first; |
366 | struct timer_node *timer = NULL; |
367 | |
368 | /* While the timer queue is not empty, inspect the first node. */ |
369 | first = list_first (list: &self->timer_queue); |
370 | if (first != list_null (list: &self->timer_queue)) |
371 | { |
372 | struct timespec now; |
373 | |
374 | timer = timer_links2ptr (list: first); |
375 | |
376 | /* This assumes that the elements of the list of one thread |
377 | are all for the same clock. */ |
378 | __clock_gettime (timer->clock, &now); |
379 | |
380 | while (1) |
381 | { |
382 | /* If the timer is due or overdue, remove it from the queue. |
383 | If it's a periodic timer, re-compute its new time and |
384 | requeue it. Either way, perform the timer expiry. */ |
385 | if (timespec_compare (left: &now, right: &timer->expirytime) < 0) |
386 | break; |
387 | |
388 | list_unlink_ip (list: first); |
389 | |
390 | if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0 |
391 | || timer->value.it_interval.tv_nsec != 0) |
392 | { |
393 | timer->overrun_count = 0; |
394 | timespec_add (sum: &timer->expirytime, left: &timer->expirytime, |
395 | right: &timer->value.it_interval); |
396 | while (timespec_compare (left: &timer->expirytime, right: &now) < 0) |
397 | { |
398 | timespec_add (sum: &timer->expirytime, left: &timer->expirytime, |
399 | right: &timer->value.it_interval); |
400 | if (timer->overrun_count < DELAYTIMER_MAX) |
401 | ++timer->overrun_count; |
402 | } |
403 | __timer_thread_queue_timer (thread: self, insert: timer); |
404 | } |
405 | |
406 | thread_expire_timer (self, timer); |
407 | |
408 | first = list_first (list: &self->timer_queue); |
409 | if (first == list_null (list: &self->timer_queue)) |
410 | break; |
411 | |
412 | timer = timer_links2ptr (list: first); |
413 | } |
414 | } |
415 | |
416 | /* If the queue is not empty, wait until the expiry time of the |
417 | first node. Otherwise wait indefinitely. Insertions at the |
418 | head of the queue must wake up the thread by broadcasting |
419 | this condition variable. */ |
420 | if (timer != NULL) |
421 | pthread_cond_timedwait (cond: &self->cond, mutex: &__timer_mutex, |
422 | abstime: &timer->expirytime); |
423 | else |
424 | pthread_cond_wait (cond: &self->cond, mutex: &__timer_mutex); |
425 | } |
426 | /* This macro will never be executed since the while loop loops |
427 | forever - but we have to add it for proper nesting. */ |
428 | pthread_cleanup_pop (1); |
429 | } |
430 | |
431 | |
432 | /* Enqueue a timer in wakeup order in the thread's timer queue. |
433 | Returns 1 if the timer was inserted at the head of the queue, |
434 | causing the queue's next wakeup time to change. */ |
435 | |
436 | int |
437 | __timer_thread_queue_timer (struct thread_node *thread, |
438 | struct timer_node *insert) |
439 | { |
440 | struct list_head *iter; |
441 | int athead = 1; |
442 | |
443 | for (iter = list_first (list: &thread->timer_queue); |
444 | iter != list_null (list: &thread->timer_queue); |
445 | iter = list_next (list: iter)) |
446 | { |
447 | struct timer_node *timer = timer_links2ptr (list: iter); |
448 | |
449 | if (timespec_compare (left: &insert->expirytime, right: &timer->expirytime) < 0) |
450 | break; |
451 | athead = 0; |
452 | } |
453 | |
454 | list_insbefore (list: iter, newp: &insert->links); |
455 | return athead; |
456 | } |
457 | |
458 | |
459 | /* Start a thread and associate it with the given thread node. Global |
460 | lock must be held by caller. */ |
461 | int |
462 | __timer_thread_start (struct thread_node *thread) |
463 | { |
464 | int retval = 1; |
465 | sigset_t set, oset; |
466 | |
467 | assert (!thread->exists); |
468 | thread->exists = 1; |
469 | |
470 | sigfillset (&set); |
471 | pthread_sigmask (SIG_SETMASK, newmask: &set, oldmask: &oset); |
472 | |
473 | if (pthread_create (newthread: &thread->id, attr: &thread->attr, |
474 | start_routine: (void *(*) (void *)) thread_func, arg: thread) != 0) |
475 | { |
476 | thread->exists = 0; |
477 | retval = -1; |
478 | } |
479 | |
480 | pthread_sigmask (SIG_SETMASK, newmask: &oset, NULL); |
481 | |
482 | return retval; |
483 | } |
484 | |
485 | |
486 | void |
487 | __timer_thread_wakeup (struct thread_node *thread) |
488 | { |
489 | pthread_cond_broadcast (cond: &thread->cond); |
490 | } |
491 | |
492 | |
493 | |
494 | /* Search the list of active threads and find one which has matching |
495 | attributes. Global mutex lock must be held by caller. */ |
496 | struct thread_node * |
497 | __timer_thread_find_matching (const pthread_attr_t *desired_attr, |
498 | clockid_t desired_clock_id) |
499 | { |
500 | struct list_head *iter = list_first (list: &thread_active_list); |
501 | |
502 | while (iter != list_null (list: &thread_active_list)) |
503 | { |
504 | struct thread_node *candidate = thread_links2ptr (list: iter); |
505 | |
506 | if (thread_attr_compare (left: desired_attr, right: &candidate->attr) |
507 | && desired_clock_id == candidate->clock_id) |
508 | return candidate; |
509 | |
510 | iter = list_next (list: iter); |
511 | } |
512 | |
513 | return NULL; |
514 | } |
515 | |
516 | |
517 | /* Grab a free timer structure from the global free list. The global |
518 | lock must be held by the caller. */ |
519 | struct timer_node * |
520 | __timer_alloc (void) |
521 | { |
522 | struct list_head *node = list_first (list: &timer_free_list); |
523 | |
524 | if (node != list_null (list: &timer_free_list)) |
525 | { |
526 | struct timer_node *timer = timer_links2ptr (list: node); |
527 | list_unlink_ip (list: node); |
528 | timer->inuse = TIMER_INUSE; |
529 | timer->refcount = 1; |
530 | return timer; |
531 | } |
532 | |
533 | return NULL; |
534 | } |
535 | |
536 | |
537 | /* Return a timer structure to the global free list. The global lock |
538 | must be held by the caller. */ |
539 | void |
540 | __timer_dealloc (struct timer_node *timer) |
541 | { |
542 | assert (timer->refcount == 0); |
543 | timer->thread = NULL; /* Break association between timer and thread. */ |
544 | timer->inuse = TIMER_FREE; |
545 | list_append (list: &timer_free_list, newp: &timer->links); |
546 | } |
547 | |
548 | |
549 | /* Thread cancellation handler which unlocks a mutex. */ |
550 | void |
551 | __timer_mutex_cancel_handler (void *arg) |
552 | { |
553 | pthread_mutex_unlock (mutex: arg); |
554 | } |
555 | |