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