1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 #include "pthread_internal.h"
29 #include <linux/time.h>
30 #include <string.h>
31 #include <errno.h>
32
33 /* This file implements the support required to implement SIGEV_THREAD posix
34 * timers. See the following pages for additionnal details:
35 *
36 * www.opengroup.org/onlinepubs/000095399/functions/timer_create.html
37 * www.opengroup.org/onlinepubs/000095399/functions/timer_settime.html
38 * www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04.html#tag_02_04_01
39 *
40 * The Linux kernel doesn't support these, so we need to implement them in the
41 * C library. We use a very basic scheme where each timer is associated to a
42 * thread that will loop, waiting for timeouts or messages from the program
43 * corresponding to calls to timer_settime() and timer_delete().
44 *
45 * Note also an important thing: Posix mandates that in the case of fork(),
46 * the timers of the child process should be disarmed, but not deleted.
47 * this is implemented by providing a fork() wrapper (see bionic/fork.c) which
48 * stops all timers before the fork, and only re-start them in case of error
49 * or in the parent process.
50 *
51 * the stop/start is implemented by the __timer_table_start_stop() function
52 * below.
53 */
54
55 /* normal (i.e. non-SIGEV_THREAD) timer ids are created directly by the kernel
56 * and are passed as is to/from the caller.
57 *
58 * on the other hand, a SIGEV_THREAD timer ID will have its TIMER_ID_WRAP_BIT
59 * always set to 1. In this implementation, this is always bit 31, which is
60 * guaranteed to never be used by kernel-provided timer ids
61 *
62 * (see code in <kernel>/lib/idr.c, used to manage IDs, to see why)
63 */
64
65 #define TIMER_ID_WRAP_BIT 0x80000000
66 #define TIMER_ID_WRAP(id) ((timer_t)((id) | TIMER_ID_WRAP_BIT))
67 #define TIMER_ID_UNWRAP(id) ((timer_t)((id) & ~TIMER_ID_WRAP_BIT))
68 #define TIMER_ID_IS_WRAPPED(id) (((id) & TIMER_ID_WRAP_BIT) != 0)
69
70 /* this value is used internally to indicate a 'free' or 'zombie'
71 * thr_timer structure. Here, 'zombie' means that timer_delete()
72 * has been called, but that the corresponding thread hasn't
73 * exited yet.
74 */
75 #define TIMER_ID_NONE ((timer_t)0xffffffff)
76
77 /* True iff a timer id is valid */
78 #define TIMER_ID_IS_VALID(id) ((id) != TIMER_ID_NONE)
79
80 /* the maximum value of overrun counters */
81 #define DELAYTIMER_MAX 0x7fffffff
82
83 #define __likely(x) __builtin_expect(!!(x),1)
84 #define __unlikely(x) __builtin_expect(!!(x),0)
85
86 typedef struct thr_timer thr_timer_t;
87 typedef struct thr_timer_table thr_timer_table_t;
88
89 /* The Posix spec says the function receives an unsigned parameter, but
90 * it's really a 'union sigval' a.k.a. sigval_t */
91 typedef void (*thr_timer_func_t)( sigval_t );
92
93 struct thr_timer {
94 thr_timer_t* next; /* next in free list */
95 timer_t id; /* TIMER_ID_NONE iff free or dying */
96 clockid_t clock;
97 pthread_t thread;
98 pthread_attr_t attributes;
99 thr_timer_func_t callback;
100 sigval_t value;
101
102 /* the following are used to communicate between
103 * the timer thread and the timer_XXX() functions
104 */
105 pthread_mutex_t mutex; /* lock */
106 pthread_cond_t cond; /* signal a state change to thread */
107 int volatile done; /* set by timer_delete */
108 int volatile stopped; /* set by _start_stop() */
109 struct timespec volatile expires; /* next expiration time, or 0 */
110 struct timespec volatile period; /* reload value, or 0 */
111 int volatile overruns; /* current number of overruns */
112 };
113
114 #define MAX_THREAD_TIMERS 32
115
116 struct thr_timer_table {
117 pthread_mutex_t lock;
118 thr_timer_t* free_timer;
119 thr_timer_t timers[ MAX_THREAD_TIMERS ];
120 };
121
122 /** GLOBAL TABLE OF THREAD TIMERS
123 **/
124
125 static void
thr_timer_table_init(thr_timer_table_t * t)126 thr_timer_table_init( thr_timer_table_t* t )
127 {
128 int nn;
129
130 memset(t, 0, sizeof *t);
131 pthread_mutex_init( &t->lock, NULL );
132
133 for (nn = 0; nn < MAX_THREAD_TIMERS; nn++)
134 t->timers[nn].id = TIMER_ID_NONE;
135
136 t->free_timer = &t->timers[0];
137 for (nn = 1; nn < MAX_THREAD_TIMERS; nn++)
138 t->timers[nn-1].next = &t->timers[nn];
139 }
140
141
142 static thr_timer_t*
thr_timer_table_alloc(thr_timer_table_t * t)143 thr_timer_table_alloc( thr_timer_table_t* t )
144 {
145 thr_timer_t* timer;
146
147 if (t == NULL)
148 return NULL;
149
150 pthread_mutex_lock(&t->lock);
151 timer = t->free_timer;
152 if (timer != NULL) {
153 t->free_timer = timer->next;
154 timer->next = NULL;
155 timer->id = TIMER_ID_WRAP((timer - t->timers));
156 }
157 pthread_mutex_unlock(&t->lock);
158 return timer;
159 }
160
161
162 static void
thr_timer_table_free(thr_timer_table_t * t,thr_timer_t * timer)163 thr_timer_table_free( thr_timer_table_t* t, thr_timer_t* timer )
164 {
165 pthread_mutex_lock( &t->lock );
166 timer->id = TIMER_ID_NONE;
167 timer->thread = 0;
168 timer->next = t->free_timer;
169 t->free_timer = timer;
170 pthread_mutex_unlock( &t->lock );
171 }
172
173
174 static void
thr_timer_table_start_stop(thr_timer_table_t * t,int stop)175 thr_timer_table_start_stop( thr_timer_table_t* t, int stop )
176 {
177 int nn;
178
179 pthread_mutex_lock(&t->lock);
180
181 for (nn = 0; nn < MAX_THREAD_TIMERS; nn++) {
182 thr_timer_t* timer = &t->timers[nn];
183
184 if (TIMER_ID_IS_VALID(timer->id)) {
185 /* tell the thread to start/stop */
186 pthread_mutex_lock(&timer->mutex);
187 timer->stopped = stop;
188 pthread_cond_signal( &timer->cond );
189 pthread_mutex_unlock(&timer->mutex);
190 }
191 }
192 pthread_mutex_unlock(&t->lock);
193 }
194
195
196 /* convert a timer_id into the corresponding thr_timer_t* pointer
197 * returns NULL if the id is not wrapped or is invalid/free
198 */
199 static thr_timer_t*
thr_timer_table_from_id(thr_timer_table_t * t,timer_t id,int remove)200 thr_timer_table_from_id( thr_timer_table_t* t,
201 timer_t id,
202 int remove )
203 {
204 unsigned index;
205 thr_timer_t* timer;
206
207 if (t == NULL || !TIMER_ID_IS_WRAPPED(id))
208 return NULL;
209
210 index = (unsigned) TIMER_ID_UNWRAP(id);
211 if (index >= MAX_THREAD_TIMERS)
212 return NULL;
213
214 pthread_mutex_lock(&t->lock);
215
216 timer = &t->timers[index];
217
218 if (!TIMER_ID_IS_VALID(timer->id)) {
219 timer = NULL;
220 } else {
221 /* if we're removing this timer, clear the id
222 * right now to prevent another thread to
223 * use the same id after the unlock */
224 if (remove)
225 timer->id = TIMER_ID_NONE;
226 }
227 pthread_mutex_unlock(&t->lock);
228
229 return timer;
230 }
231
232 /* the static timer table - we only create it if the process
233 * really wants to use SIGEV_THREAD timers, which should be
234 * pretty infrequent
235 */
236
237 static pthread_once_t __timer_table_once = PTHREAD_ONCE_INIT;
238 static thr_timer_table_t* __timer_table;
239
240 static void
__timer_table_init(void)241 __timer_table_init( void )
242 {
243 __timer_table = calloc(1,sizeof(*__timer_table));
244
245 if (__timer_table != NULL)
246 thr_timer_table_init( __timer_table );
247 }
248
249 static thr_timer_table_t*
__timer_table_get(void)250 __timer_table_get(void)
251 {
252 pthread_once( &__timer_table_once, __timer_table_init );
253 return __timer_table;
254 }
255
256 /** POSIX THREAD TIMERS CLEANUP ON FORK
257 **
258 ** this should be called from the 'fork()' wrapper to stop/start
259 ** all active thread timers. this is used to implement a Posix
260 ** requirements: the timers of fork child processes must be
261 ** disarmed but not deleted.
262 **/
263 __LIBC_HIDDEN__ void
__timer_table_start_stop(int stop)264 __timer_table_start_stop( int stop )
265 {
266 if (__timer_table != NULL) {
267 thr_timer_table_t* table = __timer_table_get();
268 thr_timer_table_start_stop(table, stop);
269 }
270 }
271
272 static thr_timer_t*
thr_timer_from_id(timer_t id)273 thr_timer_from_id( timer_t id )
274 {
275 thr_timer_table_t* table = __timer_table_get();
276 thr_timer_t* timer = thr_timer_table_from_id( table, id, 0 );
277
278 return timer;
279 }
280
281
282 static __inline__ void
thr_timer_lock(thr_timer_t * t)283 thr_timer_lock( thr_timer_t* t )
284 {
285 pthread_mutex_lock(&t->mutex);
286 }
287
288 static __inline__ void
thr_timer_unlock(thr_timer_t * t)289 thr_timer_unlock( thr_timer_t* t )
290 {
291 pthread_mutex_unlock(&t->mutex);
292 }
293
294 /** POSIX TIMERS APIs */
295
296 /* first, declare the syscall stubs */
297 extern int __timer_create( clockid_t, struct sigevent*, timer_t* );
298 extern int __timer_delete( timer_t );
299 extern int __timer_gettime( timer_t, struct itimerspec* );
300 extern int __timer_settime( timer_t, int, const struct itimerspec*, struct itimerspec* );
301 extern int __timer_getoverrun(timer_t);
302
303 static void* timer_thread_start( void* );
304
305 /* then the wrappers themselves */
306 int
timer_create(clockid_t clockid,struct sigevent * evp,timer_t * ptimerid)307 timer_create( clockid_t clockid, struct sigevent* evp, timer_t *ptimerid)
308 {
309 /* if not a SIGEV_THREAD timer, direct creation by the kernel */
310 if (__likely(evp == NULL || evp->sigev_notify != SIGEV_THREAD))
311 return __timer_create( clockid, evp, ptimerid );
312
313 // check arguments
314 if (evp->sigev_notify_function == NULL) {
315 errno = EINVAL;
316 return -1;
317 }
318
319 {
320 struct timespec dummy;
321
322 /* check that the clock id is supported by the kernel */
323 if (clock_gettime( clockid, &dummy ) < 0 && errno == EINVAL )
324 return -1;
325 }
326
327 /* create a new timer and its thread */
328 {
329 thr_timer_table_t* table = __timer_table_get();
330 thr_timer_t* timer = thr_timer_table_alloc( table );
331 struct sigevent evp0;
332
333 if (timer == NULL) {
334 errno = ENOMEM;
335 return -1;
336 }
337
338 /* copy the thread attributes */
339 if (evp->sigev_notify_attributes == NULL) {
340 pthread_attr_init(&timer->attributes);
341 }
342 else {
343 timer->attributes = ((pthread_attr_t*)evp->sigev_notify_attributes)[0];
344 }
345
346 /* Posix says that the default is PTHREAD_CREATE_DETACHED and
347 * that PTHREAD_CREATE_JOINABLE has undefined behaviour.
348 * So simply always use DETACHED :-)
349 */
350 pthread_attr_setdetachstate(&timer->attributes, PTHREAD_CREATE_DETACHED);
351
352 timer->callback = evp->sigev_notify_function;
353 timer->value = evp->sigev_value;
354 timer->clock = clockid;
355
356 pthread_mutex_init( &timer->mutex, NULL );
357 pthread_cond_init( &timer->cond, NULL );
358
359 timer->done = 0;
360 timer->stopped = 0;
361 timer->expires.tv_sec = timer->expires.tv_nsec = 0;
362 timer->period.tv_sec = timer->period.tv_nsec = 0;
363 timer->overruns = 0;
364
365 /* create the thread */
366 if (pthread_create( &timer->thread, &timer->attributes, timer_thread_start, timer ) < 0) {
367 thr_timer_table_free( __timer_table, timer );
368 errno = ENOMEM;
369 return -1;
370 }
371
372 *ptimerid = timer->id;
373 return 0;
374 }
375 }
376
377
378 int
timer_delete(timer_t id)379 timer_delete( timer_t id )
380 {
381 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) )
382 return __timer_delete( id );
383 else
384 {
385 thr_timer_table_t* table = __timer_table_get();
386 thr_timer_t* timer = thr_timer_table_from_id(table, id, 1);
387
388 if (timer == NULL) {
389 errno = EINVAL;
390 return -1;
391 }
392
393 /* tell the timer's thread to stop */
394 thr_timer_lock(timer);
395 timer->done = 1;
396 pthread_cond_signal( &timer->cond );
397 thr_timer_unlock(timer);
398
399 /* NOTE: the thread will call __timer_table_free() to free the
400 * timer object. the '1' parameter to thr_timer_table_from_id
401 * above ensured that the object and its timer_id cannot be
402 * reused before that.
403 */
404 return 0;
405 }
406 }
407
408 /* return the relative time until the next expiration, or 0 if
409 * the timer is disarmed */
410 static void
timer_gettime_internal(thr_timer_t * timer,struct itimerspec * spec)411 timer_gettime_internal( thr_timer_t* timer,
412 struct itimerspec* spec)
413 {
414 struct timespec diff;
415
416 diff = timer->expires;
417 if (!timespec_is_zero(&diff))
418 {
419 struct timespec now;
420
421 clock_gettime( timer->clock, &now );
422 timespec_sub(&diff, &now);
423
424 /* in case of overrun, return 0 */
425 if (timespec_cmp0(&diff) < 0) {
426 timespec_zero(&diff);
427 }
428 }
429
430 spec->it_value = diff;
431 spec->it_interval = timer->period;
432 }
433
434
435 int
timer_gettime(timer_t id,struct itimerspec * ospec)436 timer_gettime( timer_t id, struct itimerspec* ospec )
437 {
438 if (ospec == NULL) {
439 errno = EINVAL;
440 return -1;
441 }
442
443 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) {
444 return __timer_gettime( id, ospec );
445 } else {
446 thr_timer_t* timer = thr_timer_from_id(id);
447
448 if (timer == NULL) {
449 errno = EINVAL;
450 return -1;
451 }
452 thr_timer_lock(timer);
453 timer_gettime_internal( timer, ospec );
454 thr_timer_unlock(timer);
455 }
456 return 0;
457 }
458
459
460 int
timer_settime(timer_t id,int flags,const struct itimerspec * spec,struct itimerspec * ospec)461 timer_settime( timer_t id,
462 int flags,
463 const struct itimerspec* spec,
464 struct itimerspec* ospec )
465 {
466 if (spec == NULL) {
467 errno = EINVAL;
468 return -1;
469 }
470
471 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) {
472 return __timer_settime( id, flags, spec, ospec );
473 } else {
474 thr_timer_t* timer = thr_timer_from_id(id);
475 struct timespec expires, now;
476
477 if (timer == NULL) {
478 errno = EINVAL;
479 return -1;
480 }
481 thr_timer_lock(timer);
482
483 /* return current timer value if ospec isn't NULL */
484 if (ospec != NULL) {
485 timer_gettime_internal(timer, ospec );
486 }
487
488 /* compute next expiration time. note that if the
489 * new it_interval is 0, we should disarm the timer
490 */
491 expires = spec->it_value;
492 if (!timespec_is_zero(&expires)) {
493 clock_gettime( timer->clock, &now );
494 if (!(flags & TIMER_ABSTIME)) {
495 timespec_add(&expires, &now);
496 } else {
497 if (timespec_cmp(&expires, &now) < 0)
498 expires = now;
499 }
500 }
501 timer->expires = expires;
502 timer->period = spec->it_interval;
503 thr_timer_unlock( timer );
504
505 /* signal the change to the thread */
506 pthread_cond_signal( &timer->cond );
507 }
508 return 0;
509 }
510
511
512 int
timer_getoverrun(timer_t id)513 timer_getoverrun(timer_t id)
514 {
515 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) {
516 return __timer_getoverrun( id );
517 } else {
518 thr_timer_t* timer = thr_timer_from_id(id);
519 int result;
520
521 if (timer == NULL) {
522 errno = EINVAL;
523 return -1;
524 }
525
526 thr_timer_lock(timer);
527 result = timer->overruns;
528 thr_timer_unlock(timer);
529
530 return result;
531 }
532 }
533
534
535 static void*
timer_thread_start(void * _arg)536 timer_thread_start( void* _arg )
537 {
538 thr_timer_t* timer = _arg;
539
540 thr_timer_lock( timer );
541
542 /* we loop until timer->done is set in timer_delete() */
543 while (!timer->done)
544 {
545 struct timespec expires = timer->expires;
546 struct timespec period = timer->period;
547 struct timespec now;
548
549 /* if the timer is stopped or disarmed, wait indefinitely
550 * for a state change from timer_settime/_delete/_start_stop
551 */
552 if ( timer->stopped || timespec_is_zero(&expires) )
553 {
554 pthread_cond_wait( &timer->cond, &timer->mutex );
555 continue;
556 }
557
558 /* otherwise, we need to do a timed wait until either a
559 * state change of the timer expiration time.
560 */
561 clock_gettime(timer->clock, &now);
562
563 if (timespec_cmp( &expires, &now ) > 0)
564 {
565 /* cool, there was no overrun, so compute the
566 * relative timeout as 'expires - now', then wait
567 */
568 int ret;
569 struct timespec diff = expires;
570 timespec_sub( &diff, &now );
571
572 ret = __pthread_cond_timedwait_relative(
573 &timer->cond, &timer->mutex, &diff);
574
575 /* if we didn't timeout, it means that a state change
576 * occured, so reloop to take care of it.
577 */
578 if (ret != ETIMEDOUT)
579 continue;
580 }
581 else
582 {
583 /* overrun was detected before we could wait ! */
584 if (!timespec_is_zero( &period ) )
585 {
586 /* for periodic timers, compute total overrun count */
587 do {
588 timespec_add( &expires, &period );
589 if (timer->overruns < DELAYTIMER_MAX)
590 timer->overruns += 1;
591 } while ( timespec_cmp( &expires, &now ) < 0 );
592
593 /* backtrack the last one, because we're going to
594 * add the same value just a bit later */
595 timespec_sub( &expires, &period );
596 }
597 else
598 {
599 /* for non-periodic timer, things are simple */
600 timer->overruns = 1;
601 }
602 }
603
604 /* if we get there, a timeout was detected.
605 * first reload/disarm the timer has needed
606 */
607 if ( !timespec_is_zero(&period) ) {
608 timespec_add( &expires, &period );
609 } else {
610 timespec_zero( &expires );
611 }
612 timer->expires = expires;
613
614 /* now call the timer callback function. release the
615 * lock to allow the function to modify the timer setting
616 * or call timer_getoverrun().
617 *
618 * NOTE: at this point we trust the callback not to be a
619 * total moron and pthread_kill() the timer thread
620 */
621 thr_timer_unlock(timer);
622 timer->callback( timer->value );
623 thr_timer_lock(timer);
624
625 /* now clear the overruns counter. it only makes sense
626 * within the callback */
627 timer->overruns = 0;
628 }
629
630 thr_timer_unlock( timer );
631
632 /* free the timer object now. there is no need to call
633 * __timer_table_get() since we're guaranteed that __timer_table
634 * is initialized in this thread
635 */
636 thr_timer_table_free(__timer_table, timer);
637
638 return NULL;
639 }
640