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
timer_thread(void * thread_data)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
loc_timer_start(unsigned int msec,loc_timer_callback cb_func,void * caller_data)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
loc_timer_stop(void * handle)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