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