1 /*
2  *    Copyright (C) 2013 SAMSUNG S.LSI
3  *
4  *   Licensed under the Apache License, Version 2.0 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at:
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  *
16  *
17  */
18 
19 /************************************************************************
20 ** OS interface for task handling
21 *************************************************************************/
22 #include <errno.h>
23 #include <pthread.h>
24 #include <string.h>
25 #include <sys/time.h>
26 #include "osi.h"
27 
28 /************************************************************************
29 ** Internal function prototype
30 *************************************************************************/
31 void timer_thread(void);
32 
33 /************************************************************************
34 ** Public functions
35 *************************************************************************/
OSI_timer_allocate(const char * timer_name)36 tOSI_TIMER_HANDLER OSI_timer_allocate(const char* timer_name) {
37   tOSI_TIMER_HANDLER free_timer = NULL;
38   int index;
39 
40   osi_lock();
41   for (index = 0; index < OSI_MAX_TIMER; index++) {
42     if (osi_info.timer[index].state == OSI_FREE) {
43       if (free_timer == NULL)
44         free_timer = (tOSI_TIMER_HANDLER)&osi_info.timer[index];
45     } else {
46       if ((char const*)osi_info.timer[index].name == NULL) continue;
47 
48       if (strcmp((char const*)osi_info.timer[index].name,
49                  (char const*)timer_name) == 0) {
50         OSI_loge("%s : %s timer is already allocated [%d]", __func__,
51                  timer_name, index);
52         free_timer = NULL;
53         break;
54       }
55     }
56   }
57 
58   if (free_timer == NULL) {
59     OSI_loge("%s : Failed to find free timer(max: %d)", __func__,
60              OSI_MAX_TIMER);
61   } else {
62     free_timer->timeout = 0;
63     free_timer->name = timer_name;
64     free_timer->callback = NULL;
65     free_timer->callback_param = NULL;
66     free_timer->state = OSI_ALLOCATED;
67   }
68   osi_unlock();
69 
70   return free_timer;
71 }
72 
OSI_timer_start(tOSI_TIMER_HANDLER timer,uint32_t timeout,tOSI_TIMER_CALLBACK callback,void * param)73 int OSI_timer_start(tOSI_TIMER_HANDLER timer, uint32_t timeout,
74                     tOSI_TIMER_CALLBACK callback, void* param) {
75   pthread_attr_t attr;
76   int ret_th;
77 
78   if (timer == NULL) {
79     OSI_loge("%s : Invalid parameters", __func__);
80     return 0;
81   } else if (timer->state == OSI_FREE) {
82     OSI_loge("%s : The timer is not allocated", __func__);
83     return 0;
84   } else {
85     osi_lock();
86     OSI_logt("enter,osi_lock");
87     timer->timeout = timeout;
88     timer->exact_time = OSI_timer_get_current_time();
89     timer->init_timeout = timeout - 10;
90     timer->callback = callback;
91     timer->callback_param = param;
92 
93     if (timer->state != OSI_RUN) {
94       timer->state = OSI_RUN;
95 
96       /* start timer thread */
97       if (osi_info.usingTimer < 1) {
98         osi_info.timer_thread_flag |= OSI_TIMER_THREAD_FLAG_DETACH;
99         //[START] S.LSI - To increase usingTimer prior to timer_thread
100         osi_info.usingTimer++;
101         //[END] S.LSI - To increase usingTimer prior to timer_thread
102         ret_th = pthread_attr_init(&attr);
103         if (ret_th != 0)
104           OSI_loge("%s : Error pthread_attr_init! ,erron: %d", __func__,
105                    ret_th);
106 
107         OSI_logt("before pthread_create for timer thread");
108         ret_th = pthread_create(&osi_info.timer_thread, &attr,
109                                 (void* (*)(void*))timer_thread, NULL);
110         OSI_logt("after pthread_create for timer thread");
111         if (ret_th != 0)
112           OSI_loge("%s : Error to create timer_thread! ,erron: %d", __func__,
113                    ret_th);
114 
115         ret_th = pthread_attr_destroy(&attr);
116         if (ret_th != 0)
117           OSI_loge("%s : Error pthread_arrt_destroy ,erron: %d", __func__,
118                    ret_th);
119       } else
120         osi_info.usingTimer++;
121     }
122     OSI_logt("before osi_unlock");
123     osi_unlock();
124     OSI_logt("exit");
125     return timeout;
126   }
127 }
128 
OSI_timer_stop(tOSI_TIMER_HANDLER timer)129 void OSI_timer_stop(tOSI_TIMER_HANDLER timer) {
130   if (timer == NULL) {
131     OSI_loge("%s : Invalid parameters", __func__);
132   } else if (timer->state != OSI_RUN) {
133     OSI_logd("%s : This timer is not running", __func__);
134   } else {
135     osi_lock();
136     timer->state = OSI_STOP;
137     osi_info.usingTimer--;
138     if (osi_info.usingTimer <= 0) {
139       /* Cancle pthread_detach */
140       osi_info.timer_thread_flag &= ~OSI_TIMER_THREAD_FLAG_DETACH;
141       osi_unlock();
142       pthread_join(osi_info.timer_thread, NULL);
143     } else
144       osi_unlock();
145   }
146 }
147 
OSI_timer_free(tOSI_TIMER_HANDLER timer)148 void OSI_timer_free(tOSI_TIMER_HANDLER timer) {
149   if (timer) {
150     osi_lock();
151 
152     if (timer->state == OSI_RUN) osi_info.usingTimer--;
153 
154     timer->state = OSI_FREE;
155     timer->name = NULL;
156     timer->callback = NULL;
157     timer->callback_param = NULL;
158 
159     osi_unlock();
160   }
161 }
162 
OSI_timer_get_handler(char * name)163 tOSI_TIMER_HANDLER OSI_timer_get_handler(char* name) {
164   tOSI_TIMER_HANDLER timer = NULL;
165   int index;
166 
167   if (name == NULL) return NULL;
168 
169   osi_lock();
170   for (index = 0; index < OSI_MAX_TIMER; index++) {
171     if ((char const*)osi_info.timer[index].name == NULL) continue;
172 
173     if (strcmp((char const*)osi_info.timer[index].name, (char const*)name) ==
174         0) {
175       timer = &osi_info.timer[index];
176       break;
177     }
178   }
179   osi_unlock();
180 
181   return timer;
182 }
183 
OSI_timer_get_current_time()184 int32_t OSI_timer_get_current_time() {
185   struct timeval sec;
186   struct tm* now;
187   time_t rawtime;
188 
189   gettimeofday(&sec, NULL);
190   time(&rawtime);
191   now = gmtime(&rawtime);
192 
193   return (((now->tm_hour * 3600) + (now->tm_min * 60) + (now->tm_sec)) * 1000) +
194          (sec.tv_usec / 1000);
195 }
196 /************************************************************************
197 ** Internal function
198 *************************************************************************/
OSI_timer_update(int32_t tick)199 void OSI_timer_update(int32_t tick) {
200   int index;
201 
202   osi_lock();
203 
204   /* timer is not using */
205   if (osi_info.usingTimer <= 0) {
206     osi_unlock();
207     return;
208   }
209 
210   for (index = 0; index < OSI_MAX_TIMER; index++) {
211     if (osi_info.timer[index].state == OSI_RUN) {
212       osi_info.timer[index].timeout -= tick;
213 
214       if (osi_info.timer[index].timeout <= 0) {
215         /* START [16051100] - RTCC Patch */
216         if (((OSI_timer_get_current_time() - osi_info.timer[index].exact_time) >
217              osi_info.timer[index].init_timeout) ||
218             (OSI_timer_get_current_time() < osi_info.timer[index].exact_time))
219         /* END [16051100] - RTCC Patch */
220         {
221           osi_info.timer[index].state = OSI_STOP;
222           osi_info.usingTimer--;
223 
224           if (osi_info.timer[index].callback != NULL)
225             osi_info.timer[index].callback(
226                 osi_info.timer[index].callback_param);
227         } else {
228           osi_info.timer[index].timeout =
229               osi_info.timer[index].init_timeout -
230               (OSI_timer_get_current_time() - osi_info.timer[index].exact_time);
231         }
232       }
233     }
234   }
235   osi_unlock();
236 }
237 
timer_thread(void)238 void timer_thread(void) {
239   struct timespec delay;
240   int err;
241 
242   while (osi_info.usingTimer > 0) {
243     /* delay */
244     // OSI_delay(1);
245     {
246       /* 1ms sleep for nanosleep()*/
247       delay.tv_sec = 0;
248       delay.tv_nsec = 1000 * 1000;
249 
250       do {
251         err = nanosleep(&delay, &delay);
252         if (err < 0) OSI_loge("%s:Fail nanosleep", __func__);
253       } while (err < 0 && errno == EINTR);
254     }
255 
256     OSI_timer_update(1);
257   }
258 
259   if (osi_info.timer_thread_flag & OSI_TIMER_THREAD_FLAG_DETACH)
260     pthread_detach(pthread_self());
261 
262   pthread_exit(NULL);
263 }
264