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 #define MAX_DELAY_RETRIES 3 38 39 typedef struct { 40 loc_timer_callback callback_func; 41 void *user_data; 42 unsigned int time_msec; 43 }timer_data; 44 45 static void *timer_thread(void *thread_data) 46 { 47 int ret; 48 unsigned char retries=0; 49 struct timespec ts; 50 struct timeval tv; 51 timer_data t; 52 t.callback_func = ((timer_data *)thread_data)->callback_func; 53 t.user_data = ((timer_data *)thread_data)->user_data; 54 t.time_msec = ((timer_data *)thread_data)->time_msec; 55 pthread_cond_t timer_cond; 56 pthread_mutex_t timer_mutex; 57 58 LOC_LOGD("%s:%d]: Enter. Delay = %d\n", __func__, __LINE__, t.time_msec); 59 //Copied over all info into local variable. Do not need allocated struct 60 free(thread_data); 61 62 if(pthread_cond_init(&timer_cond, NULL)) { 63 LOC_LOGE("%s:%d]: Pthread cond init failed\n", __func__, __LINE__); 64 ret = -1; 65 goto err; 66 } 67 if(pthread_mutex_init(&timer_mutex, NULL)) { 68 LOC_LOGE("%s:%d]: Pthread mutex init failed\n", __func__, __LINE__); 69 ret = -1; 70 goto mutex_err; 71 } 72 while(retries < MAX_DELAY_RETRIES) { 73 gettimeofday(&tv, NULL); 74 clock_gettime(CLOCK_REALTIME, &ts); 75 if(t.time_msec >= 1000) { 76 ts.tv_sec += t.time_msec/1000; 77 t.time_msec = t.time_msec % 1000; 78 } 79 if(t.time_msec) 80 ts.tv_nsec += t.time_msec * 1000000; 81 if(ts.tv_nsec > 999999999) { 82 LOC_LOGD("%s:%d]: Large nanosecs\n", __func__, __LINE__); 83 ts.tv_sec += 1; 84 ts.tv_nsec -= 1000000000; 85 } 86 LOC_LOGD("%s:%d]: ts.tv_sec:%d; ts.tv_nsec:%d\n", 87 __func__, __LINE__, (int)ts.tv_sec, (int)ts.tv_nsec); 88 LOC_LOGD("%s:%d]: Current time: %d sec; %d nsec\n", 89 __func__, __LINE__, (int)tv.tv_sec, (int)tv.tv_usec*1000); 90 pthread_mutex_lock(&(timer_mutex)); 91 ret = pthread_cond_timedwait(&timer_cond, &timer_mutex, &ts); 92 pthread_mutex_unlock(&(timer_mutex)); 93 if(ret != ETIMEDOUT) { 94 LOC_LOGE("%s:%d]: Call to pthread timedwait failed; ret=%d\n", 95 __func__, __LINE__,ret); 96 ret = -1; 97 retries++; 98 } 99 else { 100 ret = 0; 101 break; 102 } 103 } 104 105 pthread_mutex_destroy(&timer_mutex); 106 mutex_err: 107 pthread_cond_destroy(&timer_cond); 108 err: 109 if(!ret) 110 t.callback_func(t.user_data, ret); 111 LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__); 112 return NULL; 113 } 114 115 int loc_timer_start(unsigned int msec, loc_timer_callback cb_func, 116 void* caller_data) 117 { 118 int ret=0; 119 timer_data *t=NULL; 120 pthread_attr_t tattr; 121 pthread_t id; 122 LOC_LOGD("%s:%d]: Enter\n", __func__, __LINE__); 123 if(cb_func == NULL || msec == 0) { 124 LOC_LOGE("%s:%d]: Error: Wrong parameters\n", __func__, __LINE__); 125 ret = -1; 126 goto err; 127 } 128 t = (timer_data *)calloc(1, sizeof(timer_data)); 129 if(t == NULL) { 130 LOC_LOGE("%s:%d]: Could not allocate memory. Failing.\n", 131 __func__, __LINE__); 132 ret = -1; 133 goto err; 134 } 135 136 t->callback_func = cb_func; 137 t->user_data = caller_data; 138 t->time_msec = msec; 139 140 pthread_attr_init(&tattr); 141 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 142 if(pthread_create(&(id), &tattr, timer_thread, (void *)t)) { 143 LOC_LOGE("%s:%d]: Could not create thread\n", __func__, __LINE__); 144 ret = -1; 145 goto attr_err; 146 } 147 else { 148 LOC_LOGD("%s:%d]: Created thread with id: %d\n", 149 __func__, __LINE__, (int)id); 150 } 151 152 attr_err: 153 pthread_attr_destroy(&tattr); 154 err: 155 LOC_LOGD("%s:%d]: Exit\n", __func__, __LINE__); 156 return ret; 157 } 158