Home | History | Annotate | Download | only in utils
      1 /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions are
      5  * met:
      6  *     * Redistributions of source code must retain the above copyright
      7  *       notice, this list of conditions and the following disclaimer.
      8  *     * Redistributions in binary form must reproduce the above
      9  *       copyright notice, this list of conditions and the following
     10  *       disclaimer in the documentation and/or other materials provided
     11  *       with the distribution.
     12  *     * Neither the name of The Linux Foundation, nor the names of its
     13  *       contributors may be used to endorse or promote products derived
     14  *       from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  *
     28  */
     29 
     30 #include<stdio.h>
     31 #include<stdlib.h>
     32 #include<sys/time.h>
     33 #include "loc_timer.h"
     34 #include<time.h>
     35 #include<errno.h>
     36 
     37 enum timer_state {
     38     READY = 100,
     39     WAITING,
     40     DONE,
     41     ABORT
     42 };
     43 
     44 typedef struct {
     45     loc_timer_callback callback_func;
     46     void *user_data;
     47     unsigned int time_msec;
     48     pthread_cond_t timer_cond;
     49     pthread_mutex_t timer_mutex;
     50     enum timer_state state;
     51 }timer_data;
     52 
     53 static void *timer_thread(void *thread_data)
     54 {
     55     int ret = -ETIMEDOUT;
     56     struct timespec ts;
     57     struct timeval tv;
     58     timer_data* t = (timer_data*)thread_data;
     59 
     60     LOC_LOGD("%s:%d]: Enter. Delay = %d\n", __func__, __LINE__, t->time_msec);
     61 
     62     gettimeofday(&tv, NULL);
     63     clock_gettime(CLOCK_REALTIME, &ts);
     64     if(t->time_msec >= 1000) {
     65         ts.tv_sec += t->time_msec/1000;
     66         t->time_msec = t->time_msec % 1000;
     67     }
     68     if(t->time_msec)
     69         ts.tv_nsec += t->time_msec * 1000000;
     70     if(ts.tv_nsec > 999999999) {
     71         LOC_LOGD("%s:%d]: Large nanosecs\n", __func__, __LINE__);
     72         ts.tv_sec += 1;
     73         ts.tv_nsec -= 1000000000;
     74     }
     75     LOC_LOGD("%s:%d]: ts.tv_sec:%d; ts.tv_nsec:%d\n"
     76              "\t Current time: %d sec; %d nsec",
     77              __func__, __LINE__, (int)ts.tv_sec, (int)ts.tv_nsec,
     78              (int)tv.tv_sec, (int)tv.tv_usec*1000);
     79 
     80     pthread_mutex_lock(&(t->timer_mutex));
     81     if (READY == t->state) {
     82         t->state = WAITING;
     83         ret = pthread_cond_timedwait(&t->timer_cond, &t->timer_mutex, &ts);
     84         t->state = DONE;
     85     }
     86     pthread_mutex_unlock(&(t->timer_mutex));
     87 
     88     switch (ret) {
     89     case ETIMEDOUT:
     90         LOC_LOGV("%s:%d]: loc_timer timed out",  __func__, __LINE__);
     91         break;
     92     case 0:
     93         LOC_LOGV("%s:%d]: loc_timer stopped",  __func__, __LINE__);
     94         break;
     95     case -ETIMEDOUT:
     96         LOC_LOGV("%s:%d]: loc_timer cancelled",  __func__, __LINE__);
     97         break;
     98     default:
     99         LOC_LOGE("%s:%d]: Call to pthread timedwait failed; ret=%d\n",
    100                  __func__, __LINE__, ret);
    101         break;
    102     }
    103 
    104     pthread_mutex_destroy(&t->timer_mutex);
    105     pthread_cond_destroy(&t->timer_cond);
    106 
    107     if(ETIMEDOUT == ret)
    108         t->callback_func(t->user_data, ret);
    109 
    110     free(t);
    111     LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__);
    112     return NULL;
    113 }
    114 
    115 void* loc_timer_start(unsigned int msec, loc_timer_callback cb_func,
    116                       void* caller_data)
    117 {
    118     timer_data *t=NULL;
    119     pthread_attr_t tattr;
    120     pthread_t id;
    121     LOC_LOGD("%s:%d]: Enter\n", __func__, __LINE__);
    122     if(cb_func == NULL || msec == 0) {
    123         LOC_LOGE("%s:%d]: Error: Wrong parameters\n", __func__, __LINE__);
    124         goto _err;
    125     }
    126     t = (timer_data *)calloc(1, sizeof(timer_data));
    127     if(t == NULL) {
    128         LOC_LOGE("%s:%d]: Could not allocate memory. Failing.\n",
    129                  __func__, __LINE__);
    130         goto _err;
    131     }
    132 
    133     if(pthread_cond_init(&(t->timer_cond), NULL)) {
    134         LOC_LOGE("%s:%d]: Pthread cond init failed\n", __func__, __LINE__);
    135         goto t_err;
    136     }
    137     if(pthread_mutex_init(&(t->timer_mutex), NULL)) {
    138         LOC_LOGE("%s:%d]: Pthread mutex init failed\n", __func__, __LINE__);
    139         goto cond_err;
    140     }
    141 
    142     t->callback_func = cb_func;
    143     t->user_data = caller_data;
    144     t->time_msec = msec;
    145     t->state = READY;
    146 
    147     if (pthread_attr_init(&tattr)) {
    148         LOC_LOGE("%s:%d]: Pthread mutex init failed\n", __func__, __LINE__);
    149         goto mutex_err;
    150     }
    151     pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
    152 
    153     if(pthread_create(&(id), &tattr, timer_thread, (void *)t)) {
    154         LOC_LOGE("%s:%d]: Could not create thread\n", __func__, __LINE__);
    155         goto attr_err;
    156     }
    157 
    158     LOC_LOGD("%s:%d]: Created thread with id: %d\n",
    159              __func__, __LINE__, (int)id);
    160     goto _err;
    161 
    162 attr_err:
    163     pthread_attr_destroy(&tattr);
    164 mutex_err:
    165     pthread_mutex_destroy(&t->timer_mutex);
    166 cond_err:
    167     pthread_cond_destroy(&t->timer_cond);
    168 t_err:
    169     free(t);
    170 _err:
    171     LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__);
    172     return t;
    173 }
    174 
    175 void loc_timer_stop(void* handle) {
    176     timer_data* t = (timer_data*)handle;
    177 
    178     if (NULL != t && (READY == t->state || WAITING == t->state)) {
    179         pthread_mutex_lock(&(t->timer_mutex));
    180         if (READY == t->state || WAITING == t->state) {
    181             pthread_cond_signal(&t->timer_cond);
    182             t->state = ABORT;
    183         }
    184         pthread_mutex_unlock(&(t->timer_mutex));
    185     }
    186 }
    187