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