18c2d3d5afc51d3f35150f748f263870367771b6fEd Tam/* Copyright (c) 2013, The Linux Foundation. All rights reserved. 28c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * 38c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * Redistribution and use in source and binary forms, with or without 48c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * modification, are permitted provided that the following conditions are 58c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * met: 68c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * * Redistributions of source code must retain the above copyright 78c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * notice, this list of conditions and the following disclaimer. 88c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * * Redistributions in binary form must reproduce the above 98c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * copyright notice, this list of conditions and the following 108c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * disclaimer in the documentation and/or other materials provided 118c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * with the distribution. 128c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * * Neither the name of The Linux Foundation, nor the names of its 138c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * contributors may be used to endorse or promote products derived 148c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * from this software without specific prior written permission. 158c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * 168c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 178c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 188c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 198c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 208c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 218c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 228c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 238c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 248c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 258c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 268c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278c2d3d5afc51d3f35150f748f263870367771b6fEd Tam * 288c2d3d5afc51d3f35150f748f263870367771b6fEd Tam */ 298c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 308c2d3d5afc51d3f35150f748f263870367771b6fEd Tam#include<stdio.h> 318c2d3d5afc51d3f35150f748f263870367771b6fEd Tam#include<stdlib.h> 328c2d3d5afc51d3f35150f748f263870367771b6fEd Tam#include<sys/time.h> 338c2d3d5afc51d3f35150f748f263870367771b6fEd Tam#include "loc_timer.h" 348c2d3d5afc51d3f35150f748f263870367771b6fEd Tam#include<time.h> 358c2d3d5afc51d3f35150f748f263870367771b6fEd Tam#include<errno.h> 368c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 378c2d3d5afc51d3f35150f748f263870367771b6fEd Tamenum timer_state { 388c2d3d5afc51d3f35150f748f263870367771b6fEd Tam READY = 100, 398c2d3d5afc51d3f35150f748f263870367771b6fEd Tam WAITING, 408c2d3d5afc51d3f35150f748f263870367771b6fEd Tam DONE, 418c2d3d5afc51d3f35150f748f263870367771b6fEd Tam ABORT 428c2d3d5afc51d3f35150f748f263870367771b6fEd Tam}; 438c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 448c2d3d5afc51d3f35150f748f263870367771b6fEd Tamtypedef struct { 458c2d3d5afc51d3f35150f748f263870367771b6fEd Tam loc_timer_callback callback_func; 468c2d3d5afc51d3f35150f748f263870367771b6fEd Tam void *user_data; 478c2d3d5afc51d3f35150f748f263870367771b6fEd Tam unsigned int time_msec; 488c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_cond_t timer_cond; 498c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_mutex_t timer_mutex; 508c2d3d5afc51d3f35150f748f263870367771b6fEd Tam enum timer_state state; 518c2d3d5afc51d3f35150f748f263870367771b6fEd Tam}timer_data; 528c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 538c2d3d5afc51d3f35150f748f263870367771b6fEd Tamstatic void *timer_thread(void *thread_data) 548c2d3d5afc51d3f35150f748f263870367771b6fEd Tam{ 558c2d3d5afc51d3f35150f748f263870367771b6fEd Tam int ret = -ETIMEDOUT; 568c2d3d5afc51d3f35150f748f263870367771b6fEd Tam struct timespec ts; 578c2d3d5afc51d3f35150f748f263870367771b6fEd Tam struct timeval tv; 588c2d3d5afc51d3f35150f748f263870367771b6fEd Tam timer_data* t = (timer_data*)thread_data; 598c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 608c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGD("%s:%d]: Enter. Delay = %d\n", __func__, __LINE__, t->time_msec); 618c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 628c2d3d5afc51d3f35150f748f263870367771b6fEd Tam gettimeofday(&tv, NULL); 638c2d3d5afc51d3f35150f748f263870367771b6fEd Tam clock_gettime(CLOCK_REALTIME, &ts); 648c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(t->time_msec >= 1000) { 658c2d3d5afc51d3f35150f748f263870367771b6fEd Tam ts.tv_sec += t->time_msec/1000; 668c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->time_msec = t->time_msec % 1000; 678c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 688c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(t->time_msec) 698c2d3d5afc51d3f35150f748f263870367771b6fEd Tam ts.tv_nsec += t->time_msec * 1000000; 708c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(ts.tv_nsec > 999999999) { 718c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGD("%s:%d]: Large nanosecs\n", __func__, __LINE__); 728c2d3d5afc51d3f35150f748f263870367771b6fEd Tam ts.tv_sec += 1; 738c2d3d5afc51d3f35150f748f263870367771b6fEd Tam ts.tv_nsec -= 1000000000; 748c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 758c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGD("%s:%d]: ts.tv_sec:%d; ts.tv_nsec:%d\n" 768c2d3d5afc51d3f35150f748f263870367771b6fEd Tam "\t Current time: %d sec; %d nsec", 778c2d3d5afc51d3f35150f748f263870367771b6fEd Tam __func__, __LINE__, (int)ts.tv_sec, (int)ts.tv_nsec, 788c2d3d5afc51d3f35150f748f263870367771b6fEd Tam (int)tv.tv_sec, (int)tv.tv_usec*1000); 798c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 808c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_mutex_lock(&(t->timer_mutex)); 818c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if (READY == t->state) { 828c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->state = WAITING; 838c2d3d5afc51d3f35150f748f263870367771b6fEd Tam ret = pthread_cond_timedwait(&t->timer_cond, &t->timer_mutex, &ts); 848c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->state = DONE; 858c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 868c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_mutex_unlock(&(t->timer_mutex)); 878c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 888c2d3d5afc51d3f35150f748f263870367771b6fEd Tam switch (ret) { 898c2d3d5afc51d3f35150f748f263870367771b6fEd Tam case ETIMEDOUT: 908c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGV("%s:%d]: loc_timer timed out", __func__, __LINE__); 918c2d3d5afc51d3f35150f748f263870367771b6fEd Tam break; 928c2d3d5afc51d3f35150f748f263870367771b6fEd Tam case 0: 938c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGV("%s:%d]: loc_timer stopped", __func__, __LINE__); 948c2d3d5afc51d3f35150f748f263870367771b6fEd Tam break; 958c2d3d5afc51d3f35150f748f263870367771b6fEd Tam case -ETIMEDOUT: 968c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGV("%s:%d]: loc_timer cancelled", __func__, __LINE__); 978c2d3d5afc51d3f35150f748f263870367771b6fEd Tam break; 988c2d3d5afc51d3f35150f748f263870367771b6fEd Tam default: 998c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGE("%s:%d]: Call to pthread timedwait failed; ret=%d\n", 1008c2d3d5afc51d3f35150f748f263870367771b6fEd Tam __func__, __LINE__, ret); 1018c2d3d5afc51d3f35150f748f263870367771b6fEd Tam break; 1028c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1038c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1048c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(ETIMEDOUT == ret) 1058c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->callback_func(t->user_data, ret); 1068c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1078c2d3d5afc51d3f35150f748f263870367771b6fEd Tam // A (should be rare) race condition is that, when the loc_time_stop is called 1088c2d3d5afc51d3f35150f748f263870367771b6fEd Tam // and acquired mutex, we reach here. pthread_mutex_destroy will fail with 1098c2d3d5afc51d3f35150f748f263870367771b6fEd Tam // error code EBUSY. We give it 6 tries in 5 seconds. Should be eanough time 1108c2d3d5afc51d3f35150f748f263870367771b6fEd Tam // for loc_timer_stop to complete. With the 7th try, we also perform unlock 1118c2d3d5afc51d3f35150f748f263870367771b6fEd Tam // prior to destroy. 1128c2d3d5afc51d3f35150f748f263870367771b6fEd Tam { 1138c2d3d5afc51d3f35150f748f263870367771b6fEd Tam int i; 1148c2d3d5afc51d3f35150f748f263870367771b6fEd Tam for (i = 0; EBUSY == pthread_mutex_destroy(&t->timer_mutex) && i <= 5; i++) { 1158c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if (i < 5) { 1168c2d3d5afc51d3f35150f748f263870367771b6fEd Tam sleep(1); 1178c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } else { 1188c2d3d5afc51d3f35150f748f263870367771b6fEd Tam // nah, forget it, something is seriously wrong. Mutex has been 1198c2d3d5afc51d3f35150f748f263870367771b6fEd Tam // held too long. Unlock the mutext here. 1208c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_mutex_unlock(&t->timer_mutex); 1218c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1228c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1238c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1248c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_cond_destroy(&t->timer_cond); 1258c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1268c2d3d5afc51d3f35150f748f263870367771b6fEd Tam free(t); 1278c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__); 1288c2d3d5afc51d3f35150f748f263870367771b6fEd Tam return NULL; 1298c2d3d5afc51d3f35150f748f263870367771b6fEd Tam} 1308c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1318c2d3d5afc51d3f35150f748f263870367771b6fEd Tamvoid* loc_timer_start(unsigned int msec, loc_timer_callback cb_func, 1328c2d3d5afc51d3f35150f748f263870367771b6fEd Tam void* caller_data) 1338c2d3d5afc51d3f35150f748f263870367771b6fEd Tam{ 1348c2d3d5afc51d3f35150f748f263870367771b6fEd Tam timer_data *t=NULL; 1358c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_attr_t tattr; 1368c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_t id; 1378c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGD("%s:%d]: Enter\n", __func__, __LINE__); 1388c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(cb_func == NULL || msec == 0) { 1398c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGE("%s:%d]: Error: Wrong parameters\n", __func__, __LINE__); 1408c2d3d5afc51d3f35150f748f263870367771b6fEd Tam goto _err; 1418c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1428c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t = (timer_data *)calloc(1, sizeof(timer_data)); 1438c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(t == NULL) { 1448c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGE("%s:%d]: Could not allocate memory. Failing.\n", 1458c2d3d5afc51d3f35150f748f263870367771b6fEd Tam __func__, __LINE__); 1468c2d3d5afc51d3f35150f748f263870367771b6fEd Tam goto _err; 1478c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1488c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1498c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(pthread_cond_init(&(t->timer_cond), NULL)) { 1508c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGE("%s:%d]: Pthread cond init failed\n", __func__, __LINE__); 1518c2d3d5afc51d3f35150f748f263870367771b6fEd Tam goto t_err; 1528c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1538c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(pthread_mutex_init(&(t->timer_mutex), NULL)) { 1548c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGE("%s:%d]: Pthread mutex init failed\n", __func__, __LINE__); 1558c2d3d5afc51d3f35150f748f263870367771b6fEd Tam goto cond_err; 1568c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1578c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1588c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->callback_func = cb_func; 1598c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->user_data = caller_data; 1608c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->time_msec = msec; 1618c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->state = READY; 1628c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1638c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if (pthread_attr_init(&tattr)) { 1648c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGE("%s:%d]: Pthread mutex init failed\n", __func__, __LINE__); 1658c2d3d5afc51d3f35150f748f263870367771b6fEd Tam goto mutex_err; 1668c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1678c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 1688c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1698c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if(pthread_create(&(id), &tattr, timer_thread, (void *)t)) { 1708c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGE("%s:%d]: Could not create thread\n", __func__, __LINE__); 1718c2d3d5afc51d3f35150f748f263870367771b6fEd Tam goto attr_err; 1728c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 1738c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1748c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGD("%s:%d]: Created thread with id: %d\n", 1758c2d3d5afc51d3f35150f748f263870367771b6fEd Tam __func__, __LINE__, (int)id); 1768c2d3d5afc51d3f35150f748f263870367771b6fEd Tam goto _err; 1778c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1788c2d3d5afc51d3f35150f748f263870367771b6fEd Tamattr_err: 1798c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_attr_destroy(&tattr); 1808c2d3d5afc51d3f35150f748f263870367771b6fEd Tammutex_err: 1818c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_mutex_destroy(&t->timer_mutex); 1828c2d3d5afc51d3f35150f748f263870367771b6fEd Tamcond_err: 1838c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_cond_destroy(&t->timer_cond); 1848c2d3d5afc51d3f35150f748f263870367771b6fEd Tamt_err: 1858c2d3d5afc51d3f35150f748f263870367771b6fEd Tam free(t); 1868c2d3d5afc51d3f35150f748f263870367771b6fEd Tam_err: 1878c2d3d5afc51d3f35150f748f263870367771b6fEd Tam LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__); 1888c2d3d5afc51d3f35150f748f263870367771b6fEd Tam return t; 1898c2d3d5afc51d3f35150f748f263870367771b6fEd Tam} 1908c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1918c2d3d5afc51d3f35150f748f263870367771b6fEd Tamvoid loc_timer_stop(void* handle) { 1928c2d3d5afc51d3f35150f748f263870367771b6fEd Tam timer_data* t = (timer_data*)handle; 1938c2d3d5afc51d3f35150f748f263870367771b6fEd Tam 1948c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if (NULL != t && (READY == t->state || WAITING == t->state) && 1958c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_mutex_lock(&(t->timer_mutex)) == 0) { 1968c2d3d5afc51d3f35150f748f263870367771b6fEd Tam if (READY == t->state || WAITING == t->state) { 1978c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_cond_signal(&t->timer_cond); 1988c2d3d5afc51d3f35150f748f263870367771b6fEd Tam t->state = ABORT; 1998c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 2008c2d3d5afc51d3f35150f748f263870367771b6fEd Tam pthread_mutex_unlock(&(t->timer_mutex)); 2018c2d3d5afc51d3f35150f748f263870367771b6fEd Tam } 2028c2d3d5afc51d3f35150f748f263870367771b6fEd Tam} 203