11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved. 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions 71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met: 81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions of source code must retain the above copyright 91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer. 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions in binary form must reproduce the above copyright 111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer in 12470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes * the documentation and/or other materials provided with the 131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * distribution. 141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE. 271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 28470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "pthread_internal.h" 30470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 31470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes#include <errno.h> 321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <linux/time.h> 33470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes#include <stdio.h> 341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h> 351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 36470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// Normal (i.e. non-SIGEV_THREAD) timers are created directly by the kernel 37470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// and are passed as is to/from the caller. 38470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// 39470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// This file also implements the support required for SIGEV_THREAD ("POSIX interval") 40470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// timers. See the following pages for additional details: 41470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// 42470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// www.opengroup.org/onlinepubs/000095399/functions/timer_create.html 43470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// www.opengroup.org/onlinepubs/000095399/functions/timer_settime.html 44470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04.html#tag_02_04_01 45470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// 46470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// The Linux kernel doesn't support these, so we need to implement them in the 47470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// C library. We use a very basic scheme where each timer is associated to a 48470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// thread that will loop, waiting for timeouts or messages from the program 49470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// corresponding to calls to timer_settime() and timer_delete(). 50470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// 51470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// Note also an important thing: Posix mandates that in the case of fork(), 52470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// the timers of the child process should be disarmed, but not deleted. 53470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// this is implemented by providing a fork() wrapper (see bionic/fork.c) which 54470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// stops all timers before the fork, and only re-start them in case of error 55470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// or in the parent process. 56470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// 57470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// This stop/start is implemented by the __timer_table_start_stop() function 58470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// below. 59470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// 60470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// A SIGEV_THREAD timer ID will always have its TIMER_ID_WRAP_BIT 61470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// set to 1. In this implementation, this is always bit 31, which is 62470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// guaranteed to never be used by kernel-provided timer ids 63470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// 64470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes// (See code in <kernel>/lib/idr.c, used to manage IDs, to see why.) 651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TIMER_ID_WRAP_BIT 0x80000000 671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TIMER_ID_WRAP(id) ((timer_t)((id) | TIMER_ID_WRAP_BIT)) 681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TIMER_ID_UNWRAP(id) ((timer_t)((id) & ~TIMER_ID_WRAP_BIT)) 691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TIMER_ID_IS_WRAPPED(id) (((id) & TIMER_ID_WRAP_BIT) != 0) 701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 71470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes/* this value is used internally to indicate a 'free' or 'zombie' 721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * thr_timer structure. Here, 'zombie' means that timer_delete() 731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * has been called, but that the corresponding thread hasn't 741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * exited yet. 751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TIMER_ID_NONE ((timer_t)0xffffffff) 771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* True iff a timer id is valid */ 791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define TIMER_ID_IS_VALID(id) ((id) != TIMER_ID_NONE) 801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* the maximum value of overrun counters */ 821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define DELAYTIMER_MAX 0x7fffffff 831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define __likely(x) __builtin_expect(!!(x),1) 851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define __unlikely(x) __builtin_expect(!!(x),0) 861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef struct thr_timer thr_timer_t; 881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef struct thr_timer_table thr_timer_table_t; 891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* The Posix spec says the function receives an unsigned parameter, but 911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * it's really a 'union sigval' a.k.a. sigval_t */ 921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef void (*thr_timer_func_t)( sigval_t ); 931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct thr_timer { 951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* next; /* next in free list */ 961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer_t id; /* TIMER_ID_NONE iff free or dying */ 971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project clockid_t clock; 981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_t thread; 991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_attr_t attributes; 1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_func_t callback; 1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project sigval_t value; 1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* the following are used to communicate between 1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the timer thread and the timer_XXX() functions 1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_t mutex; /* lock */ 1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_cond_t cond; /* signal a state change to thread */ 1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int volatile done; /* set by timer_delete */ 1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int volatile stopped; /* set by _start_stop() */ 1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec volatile expires; /* next expiration time, or 0 */ 1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec volatile period; /* reload value, or 0 */ 1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int volatile overruns; /* current number of overruns */ 1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}; 1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define MAX_THREAD_TIMERS 32 1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct thr_timer_table { 1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_t lock; 1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* free_timer; 1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t timers[ MAX_THREAD_TIMERS ]; 1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}; 1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/** GLOBAL TABLE OF THREAD TIMERS 1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project **/ 1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void 1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectthr_timer_table_init( thr_timer_table_t* t ) 1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int nn; 1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project memset(t, 0, sizeof *t); 1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_init( &t->lock, NULL ); 1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for (nn = 0; nn < MAX_THREAD_TIMERS; nn++) 1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project t->timers[nn].id = TIMER_ID_NONE; 1361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project t->free_timer = &t->timers[0]; 1381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for (nn = 1; nn < MAX_THREAD_TIMERS; nn++) 1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project t->timers[nn-1].next = &t->timers[nn]; 1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic thr_timer_t* 1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectthr_timer_table_alloc( thr_timer_table_t* t ) 1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* timer; 1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (t == NULL) 1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return NULL; 1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&t->lock); 1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer = t->free_timer; 1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (timer != NULL) { 1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project t->free_timer = timer->next; 1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->next = NULL; 1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->id = TIMER_ID_WRAP((timer - t->timers)); 1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&t->lock); 1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return timer; 1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void 1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectthr_timer_table_free( thr_timer_table_t* t, thr_timer_t* timer ) 1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock( &t->lock ); 1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->id = TIMER_ID_NONE; 1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->thread = 0; 1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->next = t->free_timer; 1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project t->free_timer = timer; 1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock( &t->lock ); 1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 175470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesstatic void thr_timer_table_start_stop(thr_timer_table_t* t, int stop) { 176470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (t == NULL) { 177470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return; 178470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 179470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 180470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_mutex_lock(&t->lock); 181470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes for (int nn = 0; nn < MAX_THREAD_TIMERS; ++nn) { 182470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_t* timer = &t->timers[nn]; 183470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (TIMER_ID_IS_VALID(timer->id)) { 184470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Tell the thread to start/stop. 185470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_mutex_lock(&timer->mutex); 186470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->stopped = stop; 187470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_cond_signal( &timer->cond ); 188470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_mutex_unlock(&timer->mutex); 1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 190470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 191470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_mutex_unlock(&t->lock); 1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* convert a timer_id into the corresponding thr_timer_t* pointer 1961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * returns NULL if the id is not wrapped or is invalid/free 1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic thr_timer_t* 1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectthr_timer_table_from_id( thr_timer_table_t* t, 2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer_t id, 2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int remove ) 2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project unsigned index; 2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* timer; 2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (t == NULL || !TIMER_ID_IS_WRAPPED(id)) 2071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return NULL; 2081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project index = (unsigned) TIMER_ID_UNWRAP(id); 2101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (index >= MAX_THREAD_TIMERS) 2111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return NULL; 2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&t->lock); 2141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer = &t->timers[index]; 2161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!TIMER_ID_IS_VALID(timer->id)) { 2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer = NULL; 2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* if we're removing this timer, clear the id 2211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * right now to prevent another thread to 2221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * use the same id after the unlock */ 2231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (remove) 2241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->id = TIMER_ID_NONE; 2251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&t->lock); 2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return timer; 2291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* the static timer table - we only create it if the process 2321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * really wants to use SIGEV_THREAD timers, which should be 2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * pretty infrequent 2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 2351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 236470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesstatic pthread_once_t __timer_table_once = PTHREAD_ONCE_INIT; 237470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesstatic thr_timer_table_t* __timer_table; 2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 239470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesstatic void __timer_table_init(void) { 240470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes __timer_table = calloc(1, sizeof(*__timer_table)); 241470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (__timer_table != NULL) { 242470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_table_init(__timer_table); 243470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 246470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesstatic thr_timer_table_t* __timer_table_get(void) { 247470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_once(&__timer_table_once, __timer_table_init); 248470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return __timer_table; 2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/** POSIX THREAD TIMERS CLEANUP ON FORK 2521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ** 2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ** this should be called from the 'fork()' wrapper to stop/start 2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ** all active thread timers. this is used to implement a Posix 2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ** requirements: the timers of fork child processes must be 2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project ** disarmed but not deleted. 2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project **/ 258470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes__LIBC_HIDDEN__ void __timer_table_start_stop(int stop) { 259470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // We access __timer_table directly so we don't create it if it doesn't yet exist. 260470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_table_start_stop(__timer_table, stop); 2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic thr_timer_t* 2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectthr_timer_from_id( timer_t id ) 2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_table_t* table = __timer_table_get(); 2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* timer = thr_timer_table_from_id( table, id, 0 ); 2681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return timer; 2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ void 2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectthr_timer_lock( thr_timer_t* t ) 2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_lock(&t->mutex); 2771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic __inline__ void 2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectthr_timer_unlock( thr_timer_t* t ) 2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_mutex_unlock(&t->mutex); 2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/** POSIX TIMERS APIs */ 2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 287470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesextern int __timer_create(clockid_t, struct sigevent*, timer_t*); 288470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesextern int __timer_delete(timer_t); 289470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesextern int __timer_gettime(timer_t, struct itimerspec*); 290470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesextern int __timer_settime(timer_t, int, const struct itimerspec*, struct itimerspec*); 2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern int __timer_getoverrun(timer_t); 2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 293470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesstatic void* timer_thread_start(void*); 294470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 295470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesint timer_create(clockid_t clock_id, struct sigevent* evp, timer_t* timer_id) { 296470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // If not a SIGEV_THREAD timer, the kernel can handle it without our help. 297470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (__likely(evp == NULL || evp->sigev_notify != SIGEV_THREAD)) { 298470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return __timer_create(clock_id, evp, timer_id); 299470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 300470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 301470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Check arguments. 302470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (evp->sigev_notify_function == NULL) { 303470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes errno = EINVAL; 304470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return -1; 305470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 306470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 307470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Check that the clock id is supported by the kernel. 308470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes struct timespec dummy; 309470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (clock_gettime(clock_id, &dummy) < 0 && errno == EINVAL) { 310470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return -1; 311470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 312470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 313470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Create a new timer and its thread. 314470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // TODO: use a single global thread for all timers. 315470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_table_t* table = __timer_table_get(); 316470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_t* timer = thr_timer_table_alloc(table); 317470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (timer == NULL) { 318470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes errno = ENOMEM; 319470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return -1; 320470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 321470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 322470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Copy the thread attributes. 323470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (evp->sigev_notify_attributes == NULL) { 324470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_attr_init(&timer->attributes); 325470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } else { 326470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->attributes = ((pthread_attr_t*) evp->sigev_notify_attributes)[0]; 327470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 328470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 329470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Posix says that the default is PTHREAD_CREATE_DETACHED and 330470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // that PTHREAD_CREATE_JOINABLE has undefined behavior. 331470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // So simply always use DETACHED :-) 332470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_attr_setdetachstate(&timer->attributes, PTHREAD_CREATE_DETACHED); 333470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 334470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->callback = evp->sigev_notify_function; 335470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->value = evp->sigev_value; 336470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->clock = clock_id; 337470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 338470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_mutex_init(&timer->mutex, NULL); 339470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_cond_init(&timer->cond, NULL); 340470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 341470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->done = 0; 342470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->stopped = 0; 343470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->expires.tv_sec = timer->expires.tv_nsec = 0; 344470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->period.tv_sec = timer->period.tv_nsec = 0; 345470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->overruns = 0; 346470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 347470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Create the thread. 348470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes int rc = pthread_create(&timer->thread, &timer->attributes, timer_thread_start, timer); 349470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (rc != 0) { 350470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_table_free(table, timer); 351470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes errno = rc; 352470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return -1; 353470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 354470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 355470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes *timer_id = timer->id; 356470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return 0; 3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint 3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttimer_delete( timer_t id ) 3621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) 3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return __timer_delete( id ); 3651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project else 3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project { 3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_table_t* table = __timer_table_get(); 3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* timer = thr_timer_table_from_id(table, id, 1); 3691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (timer == NULL) { 3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = EINVAL; 3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return -1; 3731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* tell the timer's thread to stop */ 3761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_lock(timer); 3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->done = 1; 3781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_cond_signal( &timer->cond ); 3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_unlock(timer); 3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* NOTE: the thread will call __timer_table_free() to free the 3821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * timer object. the '1' parameter to thr_timer_table_from_id 3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * above ensured that the object and its timer_id cannot be 3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * reused before that. 3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 3861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 3891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* return the relative time until the next expiration, or 0 if 3911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the timer is disarmed */ 3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void 3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttimer_gettime_internal( thr_timer_t* timer, 3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct itimerspec* spec) 3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec diff; 3971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project diff = timer->expires; 399470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (!timespec_is_zero(&diff)) 4001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project { 4011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec now; 4021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project clock_gettime( timer->clock, &now ); 4041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timespec_sub(&diff, &now); 4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* in case of overrun, return 0 */ 4071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (timespec_cmp0(&diff) < 0) { 4081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timespec_zero(&diff); 4091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project spec->it_value = diff; 4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project spec->it_interval = timer->period; 4141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint 4181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttimer_gettime( timer_t id, struct itimerspec* ospec ) 4191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (ospec == NULL) { 4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = EINVAL; 4221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return -1; 4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) { 4261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return __timer_gettime( id, ospec ); 4271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* timer = thr_timer_from_id(id); 4291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (timer == NULL) { 4311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = EINVAL; 4321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return -1; 4331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_lock(timer); 4351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer_gettime_internal( timer, ospec ); 4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_unlock(timer); 4371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint 4431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttimer_settime( timer_t id, 4441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int flags, 4451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project const struct itimerspec* spec, 4461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct itimerspec* ospec ) 4471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (spec == NULL) { 4491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = EINVAL; 4501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return -1; 4511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) { 4541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return __timer_settime( id, flags, spec, ospec ); 4551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 4561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* timer = thr_timer_from_id(id); 4571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project struct timespec expires, now; 4581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (timer == NULL) { 4601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = EINVAL; 4611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return -1; 4621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_lock(timer); 4641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* return current timer value if ospec isn't NULL */ 4661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (ospec != NULL) { 4671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer_gettime_internal(timer, ospec ); 4681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* compute next expiration time. note that if the 4711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * new it_interval is 0, we should disarm the timer 4721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 4731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project expires = spec->it_value; 4741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!timespec_is_zero(&expires)) { 4751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project clock_gettime( timer->clock, &now ); 4761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (!(flags & TIMER_ABSTIME)) { 4771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timespec_add(&expires, &now); 4781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 4791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (timespec_cmp(&expires, &now) < 0) 4801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project expires = now; 4811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->expires = expires; 4841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project timer->period = spec->it_interval; 4851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_unlock( timer ); 4861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* signal the change to the thread */ 4881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project pthread_cond_signal( &timer->cond ); 4891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 4901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return 0; 4911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 4921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint 4951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttimer_getoverrun(timer_t id) 4961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 4971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) { 4981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return __timer_getoverrun( id ); 4991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { 5001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_t* timer = thr_timer_from_id(id); 5011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int result; 5021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (timer == NULL) { 5041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project errno = EINVAL; 5051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return -1; 5061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 5071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_lock(timer); 5091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project result = timer->overruns; 5101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project thr_timer_unlock(timer); 5111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return result; 5131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 5141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 5151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 517470631ed79538ce912edb94505dee3e24af8db89Elliott Hughesstatic void* timer_thread_start(void* arg) { 518470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_t* timer = arg; 5191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 520470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_lock(timer); 5211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 522470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Give this thread a meaningful name. 523470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes char name[32]; 524470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes snprintf(name, sizeof(name), "POSIX interval timer 0x%08x", timer->id); 525470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_setname_np(pthread_self(), name); 5261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 527470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // We loop until timer->done is set in timer_delete(). 528470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes while (!timer->done) { 529470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes struct timespec expires = timer->expires; 530470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes struct timespec period = timer->period; 5311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 532470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // If the timer is stopped or disarmed, wait indefinitely 533470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // for a state change from timer_settime/_delete/_start_stop. 534470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (timer->stopped || timespec_is_zero(&expires)) { 535470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes pthread_cond_wait(&timer->cond, &timer->mutex); 536470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes continue; 537470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 5381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 539470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Otherwise, we need to do a timed wait until either a 540470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // state change of the timer expiration time. 541470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes struct timespec now; 542470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes clock_gettime(timer->clock, &now); 5431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 544470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (timespec_cmp(&expires, &now) > 0) { 545470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Cool, there was no overrun, so compute the 546470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // relative timeout as 'expires - now', then wait. 547470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes struct timespec diff = expires; 548470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timespec_sub(&diff, &now); 549470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 550470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes int ret = __pthread_cond_timedwait_relative(&timer->cond, &timer->mutex, &diff); 551470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 552470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // If we didn't time out, it means that a state change 553470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // occurred, so loop to take care of it. 554470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (ret != ETIMEDOUT) { 555470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes continue; 556470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 557470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } else { 558470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Overrun was detected before we could wait! 559470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (!timespec_is_zero(&period)) { 560470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // For periodic timers, compute total overrun count. 561470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes do { 562470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timespec_add(&expires, &period); 563470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (timer->overruns < DELAYTIMER_MAX) { 564470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->overruns += 1; 565470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 566470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } while (timespec_cmp(&expires, &now) < 0); 567470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 568470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Backtrack the last one, because we're going to 569470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // add the same value just a bit later. 570470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timespec_sub(&expires, &period); 571470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } else { 572470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // For non-periodic timers, things are simple. 573470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->overruns = 1; 574470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 575470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 5761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 577470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // If we get here, a timeout was detected. 578470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // First reload/disarm the timer as needed. 579470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes if (!timespec_is_zero(&period)) { 580470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timespec_add(&expires, &period); 581470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } else { 582470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timespec_zero(&expires); 5831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 584470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->expires = expires; 5851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 586470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Now call the timer callback function. Release the 587470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // lock to allow the function to modify the timer setting 588470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // or call timer_getoverrun(). 589470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // NOTE: at this point we trust the callback not to be a 590470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // total moron and pthread_kill() the timer thread 591470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_unlock(timer); 592470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->callback(timer->value); 593470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_lock(timer); 5941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 595470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Now clear the overruns counter. it only makes sense 596470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // within the callback. 597470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes timer->overruns = 0; 598470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes } 599470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 600470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_unlock(timer); 601470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes 602470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes // Free the timer object. 603470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes thr_timer_table_free(__timer_table_get(), timer); 6041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 605470631ed79538ce912edb94505dee3e24af8db89Elliott Hughes return NULL; 6061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 607