blob: a53d04b57004bb91bc190a96a126f8084eae5185 [file] [log] [blame]
The Android Open Source Project4e468ed2008-12-17 18:03:48 -08001/*
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
86typedef struct thr_timer thr_timer_t;
87typedef 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 */
91typedef void (*thr_timer_func_t)( sigval_t );
92
93struct 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
116struct 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
125static void
126thr_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
142static thr_timer_t*
143thr_timer_table_alloc( thr_timer_table_t* t )
144{
145 thr_timer_t* timer;
146
147 pthread_mutex_lock(&t->lock);
148 timer = t->free_timer;
149 if (timer != NULL) {
150 t->free_timer = timer->next;
151 timer->next = NULL;
152 timer->id = TIMER_ID_WRAP((timer - t->timers));
153 }
154 pthread_mutex_unlock(&t->lock);
155 return timer;
156}
157
158
159static void
160thr_timer_table_free( thr_timer_table_t* t, thr_timer_t* timer )
161{
162 pthread_mutex_lock( &t->lock );
163 timer->id = TIMER_ID_NONE;
164 timer->thread = 0;
165 timer->next = t->free_timer;
166 t->free_timer = timer;
167 pthread_mutex_unlock( &t->lock );
168}
169
170
171static void
172thr_timer_table_start_stop( thr_timer_table_t* t, int stop )
173{
174 int nn;
175
176 pthread_mutex_lock(&t->lock);
177
178 for (nn = 0; nn < MAX_THREAD_TIMERS; nn++) {
179 thr_timer_t* timer = &t->timers[nn];
180
181 if (TIMER_ID_IS_VALID(timer->id)) {
182 /* tell the thread to start/stop */
183 pthread_mutex_lock(&timer->mutex);
184 timer->stopped = stop;
185 pthread_cond_signal( &timer->cond );
186 pthread_mutex_unlock(&timer->mutex);
187 }
188 }
189 pthread_mutex_unlock(&t->lock);
190}
191
192
193/* convert a timer_id into the corresponding thr_timer_t* pointer
194 * returns NULL if the id is not wrapped or is invalid/free
195 */
196static thr_timer_t*
197thr_timer_table_from_id( thr_timer_table_t* t,
198 timer_t id,
199 int remove )
200{
201 unsigned index;
202 thr_timer_t* timer;
203
204 if (!TIMER_ID_IS_WRAPPED(id))
205 return NULL;
206
207 index = (unsigned) TIMER_ID_UNWRAP(id);
208 if (index >= MAX_THREAD_TIMERS)
209 return NULL;
210
211 pthread_mutex_lock(&t->lock);
212
213 timer = &t->timers[index];
214
215 if (!TIMER_ID_IS_VALID(timer->id)) {
216 timer = NULL;
217 } else {
218 /* if we're removing this timer, clear the id
219 * right now to prevent another thread to
220 * use the same id after the unlock */
221 if (remove)
222 timer->id = TIMER_ID_NONE;
223 }
224 pthread_mutex_unlock(&t->lock);
225
226 return timer;
227}
228
229/* the static timer table */
230
231static pthread_once_t __timer_table_once = PTHREAD_ONCE_INIT;
232static thr_timer_table_t __timer_table[1];
233
234static void
235__timer_table_init( void )
236{
237 thr_timer_table_init( __timer_table );
238}
239
240static thr_timer_table_t*
241__timer_table_get(void)
242{
243 pthread_once( &__timer_table_once, __timer_table_init );
244 return __timer_table;
245}
246
247/** POSIX THREAD TIMERS CLEANUP ON FORK
248 **
249 ** this should be called from the 'fork()' wrapper to stop/start
250 ** all active thread timers. this is used to implement a Posix
251 ** requirements: the timers of fork child processes must be
252 ** disarmed but not deleted.
253 **/
254void
255__timer_table_start_stop( int stop )
256{
257 thr_timer_table_t* table = __timer_table_get();
258 thr_timer_table_start_stop(table, stop);
259}
260
261static thr_timer_t*
262thr_timer_from_id( timer_t id )
263{
264 thr_timer_table_t* table = __timer_table_get();
265 thr_timer_t* timer = thr_timer_table_from_id( table, id, 0 );
266
267 return timer;
268}
269
270
271static __inline__ void
272thr_timer_lock( thr_timer_t* t )
273{
274 pthread_mutex_lock(&t->mutex);
275}
276
277static __inline__ void
278thr_timer_unlock( thr_timer_t* t )
279{
280 pthread_mutex_unlock(&t->mutex);
281}
282
283/** POSIX TIMERS APIs */
284
285/* first, declare the syscall stubs */
286extern int __timer_create( clockid_t, struct sigevent*, timer_t* );
287extern int __timer_delete( timer_t );
288extern int __timer_gettime( timer_t, struct itimerspec* );
289extern int __timer_settime( timer_t, int, const struct itimerspec*, struct itimerspec* );
290extern int __timer_getoverrun(timer_t);
291
292static void* timer_thread_start( void* );
293
294/* then the wrappers themselves */
295int
296timer_create( clockid_t clockid, struct sigevent* evp, timer_t *ptimerid)
297{
298 /* if not a SIGEV_THREAD timer, direct creation by the kernel */
299 if (__likely(evp == NULL || evp->sigev_notify != SIGEV_THREAD))
300 return __timer_create( clockid, evp, ptimerid );
301
302 // check arguments
303 if (evp->sigev_notify_function == NULL) {
304 errno = EINVAL;
305 return -1;
306 }
307
308 {
309 struct timespec dummy;
310
311 /* check that the clock id is supported by the kernel */
312 if (clock_gettime( clockid, &dummy ) < 0 && errno == EINVAL )
313 return -1;
314 }
315
316 /* create a new timer and its thread */
317 {
318 thr_timer_table_t* table = __timer_table_get();
319 thr_timer_t* timer = thr_timer_table_alloc( table );
320 struct sigevent evp0;
321
322 if (timer == NULL) {
323 errno = ENOMEM;
324 return -1;
325 }
326
327 /* copy the thread attributes */
328 if (evp->sigev_notify_attributes == NULL) {
329 pthread_attr_init(&timer->attributes);
330 }
331 else {
332 timer->attributes = ((pthread_attr_t*)evp->sigev_notify_attributes)[0];
333 }
334
335 /* Posix says that the default is PTHREAD_CREATE_DETACHED and
336 * that PTHREAD_CREATE_JOINABLE has undefined behaviour.
337 * So simply always use DETACHED :-)
338 */
339 pthread_attr_setdetachstate(&timer->attributes, PTHREAD_CREATE_DETACHED);
340
341 timer->callback = evp->sigev_notify_function;
342 timer->value = evp->sigev_value;
343 timer->clock = clockid;
344
345 pthread_mutex_init( &timer->mutex, NULL );
346 pthread_cond_init( &timer->cond, NULL );
347
348 timer->done = 0;
349 timer->stopped = 0;
350 timer->expires.tv_sec = timer->expires.tv_nsec = 0;
351 timer->period.tv_sec = timer->period.tv_nsec = 0;
352 timer->overruns = 0;
353
354 /* create the thread */
355 if (pthread_create( &timer->thread, &timer->attributes, timer_thread_start, timer ) < 0) {
356 thr_timer_table_free( __timer_table, timer );
357 errno = ENOMEM;
358 return -1;
359 }
360
361 *ptimerid = timer->id;
362 return 0;
363 }
364}
365
366
367int
368timer_delete( timer_t id )
369{
370 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) )
371 return __timer_delete( id );
372 else
373 {
374 thr_timer_table_t* table = __timer_table_get();
375 thr_timer_t* timer = thr_timer_table_from_id(table, id, 1);
376
377 if (timer == NULL) {
378 errno = EINVAL;
379 return -1;
380 }
381
382 /* tell the timer's thread to stop */
383 thr_timer_lock(timer);
384 timer->done = 1;
385 pthread_cond_signal( &timer->cond );
386 thr_timer_unlock(timer);
387
388 /* NOTE: the thread will call __timer_table_free() to free the
389 * timer object. the '1' parameter to thr_timer_table_from_id
390 * above ensured that the object and its timer_id cannot be
391 * reused before that.
392 */
393 return 0;
394 }
395}
396
397/* return the relative time until the next expiration, or 0 if
398 * the timer is disarmed */
399static void
400timer_gettime_internal( thr_timer_t* timer,
401 struct itimerspec* spec)
402{
403 struct timespec diff;
404
405 diff = timer->expires;
406 if (!timespec_is_zero(&diff))
407 {
408 struct timespec now;
409
410 clock_gettime( timer->clock, &now );
411 timespec_sub(&diff, &now);
412
413 /* in case of overrun, return 0 */
414 if (timespec_cmp0(&diff) < 0) {
415 timespec_zero(&diff);
416 }
417 }
418
419 spec->it_value = diff;
420 spec->it_interval = timer->period;
421}
422
423
424int
425timer_gettime( timer_t id, struct itimerspec* ospec )
426{
427 if (ospec == NULL) {
428 errno = EINVAL;
429 return -1;
430 }
431
432 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) {
433 return __timer_gettime( id, ospec );
434 } else {
435 thr_timer_t* timer = thr_timer_from_id(id);
436
437 if (timer == NULL) {
438 errno = EINVAL;
439 return -1;
440 }
441 thr_timer_lock(timer);
442 timer_gettime_internal( timer, ospec );
443 thr_timer_unlock(timer);
444 }
445 return 0;
446}
447
448
449int
450timer_settime( timer_t id,
451 int flags,
452 const struct itimerspec* spec,
453 struct itimerspec* ospec )
454{
455 if (spec == NULL) {
456 errno = EINVAL;
457 return -1;
458 }
459
460 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) {
461 return __timer_gettime( id, ospec );
462 } else {
463 thr_timer_t* timer = thr_timer_from_id(id);
464 struct timespec expires, now;
465
466 if (timer == NULL) {
467 errno = EINVAL;
468 return -1;
469 }
470 thr_timer_lock(timer);
471
472 /* return current timer value if ospec isn't NULL */
473 if (ospec != NULL) {
474 timer_gettime_internal(timer, ospec );
475 }
476
477 /* compute next expiration time */
478 expires = spec->it_value;
479 clock_gettime( timer->clock, &now );
480 if (!(flags & TIMER_ABSTIME)) {
481 timespec_add(&expires, &now);
482 } else {
483 if (timespec_cmp(&expires, &now) < 0)
484 expires = now;
485 }
486
487 timer->expires = expires;
488 timer->period = spec->it_interval;
489 thr_timer_unlock( timer );
490
491 /* signal the change to the thread */
492 pthread_cond_signal( &timer->cond );
493 }
494 return 0;
495}
496
497
498int
499timer_getoverrun(timer_t id)
500{
501 if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) {
502 return __timer_getoverrun( id );
503 } else {
504 thr_timer_t* timer = thr_timer_from_id(id);
505 int result;
506
507 if (timer == NULL) {
508 errno = EINVAL;
509 return -1;
510 }
511
512 thr_timer_lock(timer);
513 result = timer->overruns;
514 thr_timer_unlock(timer);
515
516 return result;
517 }
518}
519
520
521static void*
522timer_thread_start( void* _arg )
523{
524 thr_timer_t* timer = _arg;
525
526 thr_timer_lock( timer );
527
528 /* we loop until timer->done is set in timer_delete() */
529 while (!timer->done)
530 {
531 struct timespec expires = timer->expires;
532 struct timespec period = timer->period;
533 struct timespec now;
534
535 /* if the timer is stopped or disarmed, wait indefinitely
536 * for a state change from timer_settime/_delete/_start_stop
537 */
538 if ( timer->stopped || timespec_is_zero(&expires) )
539 {
540 pthread_cond_wait( &timer->cond, &timer->mutex );
541 continue;
542 }
543
544 /* otherwise, we need to do a timed wait until either a
545 * state change of the timer expiration time.
546 */
547 clock_gettime(timer->clock, &now);
548
549 if (timespec_cmp( &expires, &now ) > 0)
550 {
551 /* cool, there was no overrun, so compute the
552 * relative timeout as 'now - expires', then wait
553 */
554 int ret;
555 struct timespec diff = now;
556 timespec_sub( &diff, &expires );
557
558 ret = __pthread_cond_timedwait_relative(
559 &timer->cond, &timer->mutex, &diff);
560
561 /* if we didn't timeout, it means that a state change
562 * occured, so reloop to take care of it.
563 */
564 if (ret != ETIMEDOUT)
565 continue;
566 }
567 else
568 {
569 /* overrun was detected before we could wait ! */
570 if (!timespec_is_zero( &period ) )
571 {
572 /* for periodic timers, compute total overrun count */
573 do {
574 timespec_add( &expires, &period );
575 if (timer->overruns < DELAYTIMER_MAX)
576 timer->overruns += 1;
577 } while ( timespec_cmp( &expires, &now ) < 0 );
578
579 /* backtrack the last one, because we're going to
580 * add the same value just a bit later */
581 timespec_sub( &expires, &period );
582 }
583 else
584 {
585 /* for non-periodic timer, things are simple */
586 timer->overruns = 1;
587 }
588 }
589
590 /* if we get there, a timeout was detected.
591 * first reload/disarm the timer has needed
592 */
593 if ( !timespec_is_zero(&period) ) {
594 timespec_add( &expires, &period );
595 } else {
596 timespec_zero( &expires );
597 }
598 timer->expires = expires;
599
600 /* now call the timer callback function. release the
601 * lock to allow the function to modify the timer setting
602 * or call timer_getoverrun().
603 *
604 * NOTE: at this point we trust the callback not to be a
605 * total moron and pthread_kill() the timer thread
606 */
607 thr_timer_unlock(timer);
608 timer->callback( timer->value );
609 thr_timer_lock(timer);
610
611 /* now clear the overruns counter. it only makes sense
612 * within the callback */
613 timer->overruns = 0;
614 }
615
616 thr_timer_unlock( timer );
617
618 /* free the timer object now. there is no need to call
619 * __timer_table_get() since we're guaranteed that __timer_table
620 * is initialized in this thread
621 */
622 thr_timer_table_free(__timer_table, timer);
623
624 return NULL;
625}