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