Home | History | Annotate | Download | only in bionic
      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
    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*
    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
    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
    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*
    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
    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*
    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
    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*
    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
    283 thr_timer_lock( thr_timer_t*  t )
    284 {
    285     pthread_mutex_lock(&t->mutex);
    286 }
    287 
    288 static __inline__ void
    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
    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
    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
    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
    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
    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
    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*
    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