1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker * drawElements Utility Library
3*35238bceSAndroid Build Coastguard Worker * ----------------------------
4*35238bceSAndroid Build Coastguard Worker *
5*35238bceSAndroid Build Coastguard Worker * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker *
7*35238bceSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker *
11*35238bceSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker *
13*35238bceSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker *
19*35238bceSAndroid Build Coastguard Worker *//*!
20*35238bceSAndroid Build Coastguard Worker * \file
21*35238bceSAndroid Build Coastguard Worker * \brief Periodic timer.
22*35238bceSAndroid Build Coastguard Worker *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker
24*35238bceSAndroid Build Coastguard Worker #include "deTimer.h"
25*35238bceSAndroid Build Coastguard Worker #include "deMemory.h"
26*35238bceSAndroid Build Coastguard Worker #include "deThread.h"
27*35238bceSAndroid Build Coastguard Worker
28*35238bceSAndroid Build Coastguard Worker #if (DE_OS == DE_OS_WIN32)
29*35238bceSAndroid Build Coastguard Worker
30*35238bceSAndroid Build Coastguard Worker #define VC_EXTRALEAN
31*35238bceSAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN
32*35238bceSAndroid Build Coastguard Worker #include <windows.h>
33*35238bceSAndroid Build Coastguard Worker
34*35238bceSAndroid Build Coastguard Worker struct deTimer_s
35*35238bceSAndroid Build Coastguard Worker {
36*35238bceSAndroid Build Coastguard Worker deTimerCallback callback;
37*35238bceSAndroid Build Coastguard Worker void *callbackArg;
38*35238bceSAndroid Build Coastguard Worker
39*35238bceSAndroid Build Coastguard Worker HANDLE timer;
40*35238bceSAndroid Build Coastguard Worker };
41*35238bceSAndroid Build Coastguard Worker
timerCallback(PVOID lpParameter,BOOLEAN timerOrWaitFired)42*35238bceSAndroid Build Coastguard Worker static void CALLBACK timerCallback(PVOID lpParameter, BOOLEAN timerOrWaitFired)
43*35238bceSAndroid Build Coastguard Worker {
44*35238bceSAndroid Build Coastguard Worker const deTimer *timer = (const deTimer *)lpParameter;
45*35238bceSAndroid Build Coastguard Worker DE_UNREF(timerOrWaitFired);
46*35238bceSAndroid Build Coastguard Worker
47*35238bceSAndroid Build Coastguard Worker timer->callback(timer->callbackArg);
48*35238bceSAndroid Build Coastguard Worker }
49*35238bceSAndroid Build Coastguard Worker
deTimer_create(deTimerCallback callback,void * arg)50*35238bceSAndroid Build Coastguard Worker deTimer *deTimer_create(deTimerCallback callback, void *arg)
51*35238bceSAndroid Build Coastguard Worker {
52*35238bceSAndroid Build Coastguard Worker deTimer *timer = (deTimer *)deCalloc(sizeof(deTimer));
53*35238bceSAndroid Build Coastguard Worker
54*35238bceSAndroid Build Coastguard Worker if (!timer)
55*35238bceSAndroid Build Coastguard Worker return DE_NULL;
56*35238bceSAndroid Build Coastguard Worker
57*35238bceSAndroid Build Coastguard Worker timer->callback = callback;
58*35238bceSAndroid Build Coastguard Worker timer->callbackArg = arg;
59*35238bceSAndroid Build Coastguard Worker timer->timer = 0;
60*35238bceSAndroid Build Coastguard Worker
61*35238bceSAndroid Build Coastguard Worker return timer;
62*35238bceSAndroid Build Coastguard Worker }
63*35238bceSAndroid Build Coastguard Worker
deTimer_destroy(deTimer * timer)64*35238bceSAndroid Build Coastguard Worker void deTimer_destroy(deTimer *timer)
65*35238bceSAndroid Build Coastguard Worker {
66*35238bceSAndroid Build Coastguard Worker DE_ASSERT(timer);
67*35238bceSAndroid Build Coastguard Worker
68*35238bceSAndroid Build Coastguard Worker if (deTimer_isActive(timer))
69*35238bceSAndroid Build Coastguard Worker deTimer_disable(timer);
70*35238bceSAndroid Build Coastguard Worker
71*35238bceSAndroid Build Coastguard Worker deFree(timer);
72*35238bceSAndroid Build Coastguard Worker }
73*35238bceSAndroid Build Coastguard Worker
deTimer_isActive(const deTimer * timer)74*35238bceSAndroid Build Coastguard Worker bool deTimer_isActive(const deTimer *timer)
75*35238bceSAndroid Build Coastguard Worker {
76*35238bceSAndroid Build Coastguard Worker return timer->timer != 0;
77*35238bceSAndroid Build Coastguard Worker }
78*35238bceSAndroid Build Coastguard Worker
deTimer_scheduleSingle(deTimer * timer,int milliseconds)79*35238bceSAndroid Build Coastguard Worker bool deTimer_scheduleSingle(deTimer *timer, int milliseconds)
80*35238bceSAndroid Build Coastguard Worker {
81*35238bceSAndroid Build Coastguard Worker BOOL ret;
82*35238bceSAndroid Build Coastguard Worker
83*35238bceSAndroid Build Coastguard Worker DE_ASSERT(timer && milliseconds > 0);
84*35238bceSAndroid Build Coastguard Worker
85*35238bceSAndroid Build Coastguard Worker if (deTimer_isActive(timer))
86*35238bceSAndroid Build Coastguard Worker return false;
87*35238bceSAndroid Build Coastguard Worker
88*35238bceSAndroid Build Coastguard Worker ret = CreateTimerQueueTimer(&timer->timer, NULL, timerCallback, timer, (DWORD)milliseconds, 0, WT_EXECUTEDEFAULT);
89*35238bceSAndroid Build Coastguard Worker
90*35238bceSAndroid Build Coastguard Worker if (!ret)
91*35238bceSAndroid Build Coastguard Worker {
92*35238bceSAndroid Build Coastguard Worker DE_ASSERT(!timer->timer);
93*35238bceSAndroid Build Coastguard Worker return false;
94*35238bceSAndroid Build Coastguard Worker }
95*35238bceSAndroid Build Coastguard Worker
96*35238bceSAndroid Build Coastguard Worker return true;
97*35238bceSAndroid Build Coastguard Worker }
98*35238bceSAndroid Build Coastguard Worker
deTimer_scheduleInterval(deTimer * timer,int milliseconds)99*35238bceSAndroid Build Coastguard Worker bool deTimer_scheduleInterval(deTimer *timer, int milliseconds)
100*35238bceSAndroid Build Coastguard Worker {
101*35238bceSAndroid Build Coastguard Worker BOOL ret;
102*35238bceSAndroid Build Coastguard Worker
103*35238bceSAndroid Build Coastguard Worker DE_ASSERT(timer && milliseconds > 0);
104*35238bceSAndroid Build Coastguard Worker
105*35238bceSAndroid Build Coastguard Worker if (deTimer_isActive(timer))
106*35238bceSAndroid Build Coastguard Worker return false;
107*35238bceSAndroid Build Coastguard Worker
108*35238bceSAndroid Build Coastguard Worker ret = CreateTimerQueueTimer(&timer->timer, NULL, timerCallback, timer, (DWORD)milliseconds, (DWORD)milliseconds,
109*35238bceSAndroid Build Coastguard Worker WT_EXECUTEDEFAULT);
110*35238bceSAndroid Build Coastguard Worker
111*35238bceSAndroid Build Coastguard Worker if (!ret)
112*35238bceSAndroid Build Coastguard Worker {
113*35238bceSAndroid Build Coastguard Worker DE_ASSERT(!timer->timer);
114*35238bceSAndroid Build Coastguard Worker return false;
115*35238bceSAndroid Build Coastguard Worker }
116*35238bceSAndroid Build Coastguard Worker
117*35238bceSAndroid Build Coastguard Worker return true;
118*35238bceSAndroid Build Coastguard Worker }
119*35238bceSAndroid Build Coastguard Worker
deTimer_disable(deTimer * timer)120*35238bceSAndroid Build Coastguard Worker void deTimer_disable(deTimer *timer)
121*35238bceSAndroid Build Coastguard Worker {
122*35238bceSAndroid Build Coastguard Worker if (timer->timer)
123*35238bceSAndroid Build Coastguard Worker {
124*35238bceSAndroid Build Coastguard Worker const int maxTries = 100;
125*35238bceSAndroid Build Coastguard Worker HANDLE waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
126*35238bceSAndroid Build Coastguard Worker int tryNdx = 0;
127*35238bceSAndroid Build Coastguard Worker DE_ASSERT(waitEvent);
128*35238bceSAndroid Build Coastguard Worker
129*35238bceSAndroid Build Coastguard Worker for (tryNdx = 0; tryNdx < maxTries; tryNdx++)
130*35238bceSAndroid Build Coastguard Worker {
131*35238bceSAndroid Build Coastguard Worker BOOL success = DeleteTimerQueueTimer(NULL, timer->timer, waitEvent);
132*35238bceSAndroid Build Coastguard Worker if (success)
133*35238bceSAndroid Build Coastguard Worker {
134*35238bceSAndroid Build Coastguard Worker /* Wait for all callbacks to complete. */
135*35238bceSAndroid Build Coastguard Worker DWORD res = WaitForSingleObject(waitEvent, INFINITE);
136*35238bceSAndroid Build Coastguard Worker DE_ASSERT(res == WAIT_OBJECT_0);
137*35238bceSAndroid Build Coastguard Worker DE_UNREF(res);
138*35238bceSAndroid Build Coastguard Worker break;
139*35238bceSAndroid Build Coastguard Worker }
140*35238bceSAndroid Build Coastguard Worker else
141*35238bceSAndroid Build Coastguard Worker {
142*35238bceSAndroid Build Coastguard Worker DWORD err = GetLastError();
143*35238bceSAndroid Build Coastguard Worker if (err == ERROR_IO_PENDING)
144*35238bceSAndroid Build Coastguard Worker break; /* \todo [2013-03-21 pyry] Does this mean that callback is still in progress? */
145*35238bceSAndroid Build Coastguard Worker deYield();
146*35238bceSAndroid Build Coastguard Worker }
147*35238bceSAndroid Build Coastguard Worker }
148*35238bceSAndroid Build Coastguard Worker
149*35238bceSAndroid Build Coastguard Worker DE_ASSERT(tryNdx < maxTries);
150*35238bceSAndroid Build Coastguard Worker
151*35238bceSAndroid Build Coastguard Worker CloseHandle(waitEvent);
152*35238bceSAndroid Build Coastguard Worker timer->timer = 0;
153*35238bceSAndroid Build Coastguard Worker }
154*35238bceSAndroid Build Coastguard Worker }
155*35238bceSAndroid Build Coastguard Worker
156*35238bceSAndroid Build Coastguard Worker #elif (DE_OS == DE_OS_UNIX || DE_OS == DE_OS_ANDROID || DE_OS == DE_OS_SYMBIAN || DE_OS == DE_OS_QNX)
157*35238bceSAndroid Build Coastguard Worker
158*35238bceSAndroid Build Coastguard Worker #include <signal.h>
159*35238bceSAndroid Build Coastguard Worker #include <time.h>
160*35238bceSAndroid Build Coastguard Worker
161*35238bceSAndroid Build Coastguard Worker struct deTimer_s
162*35238bceSAndroid Build Coastguard Worker {
163*35238bceSAndroid Build Coastguard Worker deTimerCallback callback;
164*35238bceSAndroid Build Coastguard Worker void *callbackArg;
165*35238bceSAndroid Build Coastguard Worker
166*35238bceSAndroid Build Coastguard Worker timer_t timer;
167*35238bceSAndroid Build Coastguard Worker
168*35238bceSAndroid Build Coastguard Worker bool isActive;
169*35238bceSAndroid Build Coastguard Worker };
170*35238bceSAndroid Build Coastguard Worker
timerCallback(union sigval val)171*35238bceSAndroid Build Coastguard Worker static void timerCallback(union sigval val)
172*35238bceSAndroid Build Coastguard Worker {
173*35238bceSAndroid Build Coastguard Worker const deTimer *timer = (const deTimer *)val.sival_ptr;
174*35238bceSAndroid Build Coastguard Worker timer->callback(timer->callbackArg);
175*35238bceSAndroid Build Coastguard Worker }
176*35238bceSAndroid Build Coastguard Worker
deTimer_create(deTimerCallback callback,void * arg)177*35238bceSAndroid Build Coastguard Worker deTimer *deTimer_create(deTimerCallback callback, void *arg)
178*35238bceSAndroid Build Coastguard Worker {
179*35238bceSAndroid Build Coastguard Worker deTimer *timer = (deTimer *)deCalloc(sizeof(deTimer));
180*35238bceSAndroid Build Coastguard Worker struct sigevent sevp;
181*35238bceSAndroid Build Coastguard Worker
182*35238bceSAndroid Build Coastguard Worker if (!timer)
183*35238bceSAndroid Build Coastguard Worker return DE_NULL;
184*35238bceSAndroid Build Coastguard Worker
185*35238bceSAndroid Build Coastguard Worker deMemset(&sevp, 0, sizeof(sevp));
186*35238bceSAndroid Build Coastguard Worker sevp.sigev_notify = SIGEV_THREAD;
187*35238bceSAndroid Build Coastguard Worker sevp.sigev_value.sival_ptr = timer;
188*35238bceSAndroid Build Coastguard Worker sevp.sigev_notify_function = timerCallback;
189*35238bceSAndroid Build Coastguard Worker
190*35238bceSAndroid Build Coastguard Worker if (timer_create(CLOCK_REALTIME, &sevp, &timer->timer) != 0)
191*35238bceSAndroid Build Coastguard Worker {
192*35238bceSAndroid Build Coastguard Worker deFree(timer);
193*35238bceSAndroid Build Coastguard Worker return DE_NULL;
194*35238bceSAndroid Build Coastguard Worker }
195*35238bceSAndroid Build Coastguard Worker
196*35238bceSAndroid Build Coastguard Worker timer->callback = callback;
197*35238bceSAndroid Build Coastguard Worker timer->callbackArg = arg;
198*35238bceSAndroid Build Coastguard Worker timer->isActive = false;
199*35238bceSAndroid Build Coastguard Worker
200*35238bceSAndroid Build Coastguard Worker return timer;
201*35238bceSAndroid Build Coastguard Worker }
202*35238bceSAndroid Build Coastguard Worker
deTimer_destroy(deTimer * timer)203*35238bceSAndroid Build Coastguard Worker void deTimer_destroy(deTimer *timer)
204*35238bceSAndroid Build Coastguard Worker {
205*35238bceSAndroid Build Coastguard Worker DE_ASSERT(timer);
206*35238bceSAndroid Build Coastguard Worker
207*35238bceSAndroid Build Coastguard Worker timer_delete(timer->timer);
208*35238bceSAndroid Build Coastguard Worker deFree(timer);
209*35238bceSAndroid Build Coastguard Worker }
210*35238bceSAndroid Build Coastguard Worker
deTimer_isActive(const deTimer * timer)211*35238bceSAndroid Build Coastguard Worker bool deTimer_isActive(const deTimer *timer)
212*35238bceSAndroid Build Coastguard Worker {
213*35238bceSAndroid Build Coastguard Worker return timer->isActive;
214*35238bceSAndroid Build Coastguard Worker }
215*35238bceSAndroid Build Coastguard Worker
deTimer_scheduleSingle(deTimer * timer,int milliseconds)216*35238bceSAndroid Build Coastguard Worker bool deTimer_scheduleSingle(deTimer *timer, int milliseconds)
217*35238bceSAndroid Build Coastguard Worker {
218*35238bceSAndroid Build Coastguard Worker struct itimerspec tspec;
219*35238bceSAndroid Build Coastguard Worker
220*35238bceSAndroid Build Coastguard Worker DE_ASSERT(timer && milliseconds > 0);
221*35238bceSAndroid Build Coastguard Worker
222*35238bceSAndroid Build Coastguard Worker if (timer->isActive)
223*35238bceSAndroid Build Coastguard Worker return false;
224*35238bceSAndroid Build Coastguard Worker
225*35238bceSAndroid Build Coastguard Worker tspec.it_value.tv_sec = milliseconds / 1000;
226*35238bceSAndroid Build Coastguard Worker tspec.it_value.tv_nsec = (milliseconds % 1000) * 1000;
227*35238bceSAndroid Build Coastguard Worker tspec.it_interval.tv_sec = 0;
228*35238bceSAndroid Build Coastguard Worker tspec.it_interval.tv_nsec = 0;
229*35238bceSAndroid Build Coastguard Worker
230*35238bceSAndroid Build Coastguard Worker if (timer_settime(timer->timer, 0, &tspec, DE_NULL) != 0)
231*35238bceSAndroid Build Coastguard Worker return false;
232*35238bceSAndroid Build Coastguard Worker
233*35238bceSAndroid Build Coastguard Worker timer->isActive = true;
234*35238bceSAndroid Build Coastguard Worker return true;
235*35238bceSAndroid Build Coastguard Worker }
236*35238bceSAndroid Build Coastguard Worker
deTimer_scheduleInterval(deTimer * timer,int milliseconds)237*35238bceSAndroid Build Coastguard Worker bool deTimer_scheduleInterval(deTimer *timer, int milliseconds)
238*35238bceSAndroid Build Coastguard Worker {
239*35238bceSAndroid Build Coastguard Worker struct itimerspec tspec;
240*35238bceSAndroid Build Coastguard Worker
241*35238bceSAndroid Build Coastguard Worker DE_ASSERT(timer && milliseconds > 0);
242*35238bceSAndroid Build Coastguard Worker
243*35238bceSAndroid Build Coastguard Worker if (timer->isActive)
244*35238bceSAndroid Build Coastguard Worker return false;
245*35238bceSAndroid Build Coastguard Worker
246*35238bceSAndroid Build Coastguard Worker tspec.it_value.tv_sec = milliseconds / 1000;
247*35238bceSAndroid Build Coastguard Worker tspec.it_value.tv_nsec = (milliseconds % 1000) * 1000;
248*35238bceSAndroid Build Coastguard Worker tspec.it_interval.tv_sec = tspec.it_value.tv_sec;
249*35238bceSAndroid Build Coastguard Worker tspec.it_interval.tv_nsec = tspec.it_value.tv_nsec;
250*35238bceSAndroid Build Coastguard Worker
251*35238bceSAndroid Build Coastguard Worker if (timer_settime(timer->timer, 0, &tspec, DE_NULL) != 0)
252*35238bceSAndroid Build Coastguard Worker return false;
253*35238bceSAndroid Build Coastguard Worker
254*35238bceSAndroid Build Coastguard Worker timer->isActive = true;
255*35238bceSAndroid Build Coastguard Worker return true;
256*35238bceSAndroid Build Coastguard Worker }
257*35238bceSAndroid Build Coastguard Worker
deTimer_disable(deTimer * timer)258*35238bceSAndroid Build Coastguard Worker void deTimer_disable(deTimer *timer)
259*35238bceSAndroid Build Coastguard Worker {
260*35238bceSAndroid Build Coastguard Worker struct itimerspec tspec;
261*35238bceSAndroid Build Coastguard Worker
262*35238bceSAndroid Build Coastguard Worker DE_ASSERT(timer);
263*35238bceSAndroid Build Coastguard Worker
264*35238bceSAndroid Build Coastguard Worker tspec.it_value.tv_sec = 0;
265*35238bceSAndroid Build Coastguard Worker tspec.it_value.tv_nsec = 0;
266*35238bceSAndroid Build Coastguard Worker tspec.it_interval.tv_sec = 0;
267*35238bceSAndroid Build Coastguard Worker tspec.it_interval.tv_nsec = 0;
268*35238bceSAndroid Build Coastguard Worker
269*35238bceSAndroid Build Coastguard Worker timer_settime(timer->timer, 0, &tspec, DE_NULL);
270*35238bceSAndroid Build Coastguard Worker
271*35238bceSAndroid Build Coastguard Worker /* \todo [2012-07-10 pyry] How to wait until all pending callbacks have finished? */
272*35238bceSAndroid Build Coastguard Worker
273*35238bceSAndroid Build Coastguard Worker timer->isActive = false;
274*35238bceSAndroid Build Coastguard Worker }
275*35238bceSAndroid Build Coastguard Worker
276*35238bceSAndroid Build Coastguard Worker #else
277*35238bceSAndroid Build Coastguard Worker
278*35238bceSAndroid Build Coastguard Worker /* Generic thread-based implementation for OSes that lack proper timers. */
279*35238bceSAndroid Build Coastguard Worker
280*35238bceSAndroid Build Coastguard Worker #include "deThread.h"
281*35238bceSAndroid Build Coastguard Worker #include "deMutex.h"
282*35238bceSAndroid Build Coastguard Worker #include "deClock.h"
283*35238bceSAndroid Build Coastguard Worker
284*35238bceSAndroid Build Coastguard Worker typedef enum TimerState_e
285*35238bceSAndroid Build Coastguard Worker {
286*35238bceSAndroid Build Coastguard Worker TIMERSTATE_INTERVAL = 0, /*!< Active interval timer. */
287*35238bceSAndroid Build Coastguard Worker TIMERSTATE_SINGLE, /*!< Single callback timer. */
288*35238bceSAndroid Build Coastguard Worker TIMERSTATE_DISABLED, /*!< Disabled timer. */
289*35238bceSAndroid Build Coastguard Worker
290*35238bceSAndroid Build Coastguard Worker TIMERSTATE_LAST
291*35238bceSAndroid Build Coastguard Worker } TimerState;
292*35238bceSAndroid Build Coastguard Worker
293*35238bceSAndroid Build Coastguard Worker typedef struct deTimerThread_s
294*35238bceSAndroid Build Coastguard Worker {
295*35238bceSAndroid Build Coastguard Worker deTimerCallback callback; /*!< Callback function. */
296*35238bceSAndroid Build Coastguard Worker void *callbackArg; /*!< User pointer. */
297*35238bceSAndroid Build Coastguard Worker
298*35238bceSAndroid Build Coastguard Worker deThread thread; /*!< Thread. */
299*35238bceSAndroid Build Coastguard Worker int interval; /*!< Timer interval. */
300*35238bceSAndroid Build Coastguard Worker
301*35238bceSAndroid Build Coastguard Worker deMutex lock; /*!< State lock. */
302*35238bceSAndroid Build Coastguard Worker volatile TimerState state; /*!< Timer state. */
303*35238bceSAndroid Build Coastguard Worker } deTimerThread;
304*35238bceSAndroid Build Coastguard Worker
305*35238bceSAndroid Build Coastguard Worker struct deTimer_s
306*35238bceSAndroid Build Coastguard Worker {
307*35238bceSAndroid Build Coastguard Worker deTimerCallback callback; /*!< Callback function. */
308*35238bceSAndroid Build Coastguard Worker void *callbackArg; /*!< User pointer. */
309*35238bceSAndroid Build Coastguard Worker deTimerThread *curThread; /*!< Current timer thread. */
310*35238bceSAndroid Build Coastguard Worker };
311*35238bceSAndroid Build Coastguard Worker
timerThread(void * arg)312*35238bceSAndroid Build Coastguard Worker static void timerThread(void *arg)
313*35238bceSAndroid Build Coastguard Worker {
314*35238bceSAndroid Build Coastguard Worker deTimerThread *thread = (deTimerThread *)arg;
315*35238bceSAndroid Build Coastguard Worker int numCallbacks = 0;
316*35238bceSAndroid Build Coastguard Worker bool destroy = true;
317*35238bceSAndroid Build Coastguard Worker int64_t lastCallback = (int64_t)deGetMicroseconds();
318*35238bceSAndroid Build Coastguard Worker
319*35238bceSAndroid Build Coastguard Worker for (;;)
320*35238bceSAndroid Build Coastguard Worker {
321*35238bceSAndroid Build Coastguard Worker int sleepTime = 0;
322*35238bceSAndroid Build Coastguard Worker
323*35238bceSAndroid Build Coastguard Worker deMutex_lock(thread->lock);
324*35238bceSAndroid Build Coastguard Worker
325*35238bceSAndroid Build Coastguard Worker if (thread->state == TIMERSTATE_SINGLE && numCallbacks > 0)
326*35238bceSAndroid Build Coastguard Worker {
327*35238bceSAndroid Build Coastguard Worker destroy = false; /* Will be destroyed by deTimer_disable(). */
328*35238bceSAndroid Build Coastguard Worker thread->state = TIMERSTATE_DISABLED;
329*35238bceSAndroid Build Coastguard Worker break;
330*35238bceSAndroid Build Coastguard Worker }
331*35238bceSAndroid Build Coastguard Worker else if (thread->state == TIMERSTATE_DISABLED)
332*35238bceSAndroid Build Coastguard Worker break;
333*35238bceSAndroid Build Coastguard Worker
334*35238bceSAndroid Build Coastguard Worker deMutex_unlock(thread->lock);
335*35238bceSAndroid Build Coastguard Worker
336*35238bceSAndroid Build Coastguard Worker sleepTime = thread->interval - (int)(((int64_t)deGetMicroseconds() - lastCallback) / 1000);
337*35238bceSAndroid Build Coastguard Worker if (sleepTime > 0)
338*35238bceSAndroid Build Coastguard Worker deSleep(sleepTime);
339*35238bceSAndroid Build Coastguard Worker
340*35238bceSAndroid Build Coastguard Worker lastCallback = (int64_t)deGetMicroseconds();
341*35238bceSAndroid Build Coastguard Worker thread->callback(thread->callbackArg);
342*35238bceSAndroid Build Coastguard Worker numCallbacks += 1;
343*35238bceSAndroid Build Coastguard Worker }
344*35238bceSAndroid Build Coastguard Worker
345*35238bceSAndroid Build Coastguard Worker /* State lock is held when loop is exited. */
346*35238bceSAndroid Build Coastguard Worker deMutex_unlock(thread->lock);
347*35238bceSAndroid Build Coastguard Worker
348*35238bceSAndroid Build Coastguard Worker if (destroy)
349*35238bceSAndroid Build Coastguard Worker {
350*35238bceSAndroid Build Coastguard Worker /* Destroy thread except thread->thread. */
351*35238bceSAndroid Build Coastguard Worker deMutex_destroy(thread->lock);
352*35238bceSAndroid Build Coastguard Worker deFree(thread);
353*35238bceSAndroid Build Coastguard Worker }
354*35238bceSAndroid Build Coastguard Worker }
355*35238bceSAndroid Build Coastguard Worker
deTimerThread_create(deTimerCallback callback,void * arg,int interval,TimerState state)356*35238bceSAndroid Build Coastguard Worker static deTimerThread *deTimerThread_create(deTimerCallback callback, void *arg, int interval, TimerState state)
357*35238bceSAndroid Build Coastguard Worker {
358*35238bceSAndroid Build Coastguard Worker deTimerThread *thread = (deTimerThread *)deCalloc(sizeof(deTimerThread));
359*35238bceSAndroid Build Coastguard Worker
360*35238bceSAndroid Build Coastguard Worker DE_ASSERT(state == TIMERSTATE_INTERVAL || state == TIMERSTATE_SINGLE);
361*35238bceSAndroid Build Coastguard Worker
362*35238bceSAndroid Build Coastguard Worker if (!thread)
363*35238bceSAndroid Build Coastguard Worker return DE_NULL;
364*35238bceSAndroid Build Coastguard Worker
365*35238bceSAndroid Build Coastguard Worker thread->callback = callback;
366*35238bceSAndroid Build Coastguard Worker thread->callbackArg = arg;
367*35238bceSAndroid Build Coastguard Worker thread->interval = interval;
368*35238bceSAndroid Build Coastguard Worker thread->lock = deMutex_create(DE_NULL);
369*35238bceSAndroid Build Coastguard Worker thread->state = state;
370*35238bceSAndroid Build Coastguard Worker
371*35238bceSAndroid Build Coastguard Worker thread->thread = deThread_create(timerThread, thread, DE_NULL);
372*35238bceSAndroid Build Coastguard Worker if (!thread->thread)
373*35238bceSAndroid Build Coastguard Worker {
374*35238bceSAndroid Build Coastguard Worker deMutex_destroy(thread->lock);
375*35238bceSAndroid Build Coastguard Worker deFree(thread);
376*35238bceSAndroid Build Coastguard Worker return DE_NULL;
377*35238bceSAndroid Build Coastguard Worker }
378*35238bceSAndroid Build Coastguard Worker
379*35238bceSAndroid Build Coastguard Worker return thread;
380*35238bceSAndroid Build Coastguard Worker }
381*35238bceSAndroid Build Coastguard Worker
deTimer_create(deTimerCallback callback,void * arg)382*35238bceSAndroid Build Coastguard Worker deTimer *deTimer_create(deTimerCallback callback, void *arg)
383*35238bceSAndroid Build Coastguard Worker {
384*35238bceSAndroid Build Coastguard Worker deTimer *timer = (deTimer *)deCalloc(sizeof(deTimer));
385*35238bceSAndroid Build Coastguard Worker
386*35238bceSAndroid Build Coastguard Worker if (!timer)
387*35238bceSAndroid Build Coastguard Worker return DE_NULL;
388*35238bceSAndroid Build Coastguard Worker
389*35238bceSAndroid Build Coastguard Worker timer->callback = callback;
390*35238bceSAndroid Build Coastguard Worker timer->callbackArg = arg;
391*35238bceSAndroid Build Coastguard Worker
392*35238bceSAndroid Build Coastguard Worker return timer;
393*35238bceSAndroid Build Coastguard Worker }
394*35238bceSAndroid Build Coastguard Worker
deTimer_destroy(deTimer * timer)395*35238bceSAndroid Build Coastguard Worker void deTimer_destroy(deTimer *timer)
396*35238bceSAndroid Build Coastguard Worker {
397*35238bceSAndroid Build Coastguard Worker if (timer->curThread)
398*35238bceSAndroid Build Coastguard Worker deTimer_disable(timer);
399*35238bceSAndroid Build Coastguard Worker deFree(timer);
400*35238bceSAndroid Build Coastguard Worker }
401*35238bceSAndroid Build Coastguard Worker
deTimer_isActive(const deTimer * timer)402*35238bceSAndroid Build Coastguard Worker bool deTimer_isActive(const deTimer *timer)
403*35238bceSAndroid Build Coastguard Worker {
404*35238bceSAndroid Build Coastguard Worker if (timer->curThread)
405*35238bceSAndroid Build Coastguard Worker {
406*35238bceSAndroid Build Coastguard Worker bool isActive = false;
407*35238bceSAndroid Build Coastguard Worker
408*35238bceSAndroid Build Coastguard Worker deMutex_lock(timer->curThread->lock);
409*35238bceSAndroid Build Coastguard Worker isActive = timer->curThread->state != TIMERSTATE_LAST;
410*35238bceSAndroid Build Coastguard Worker deMutex_unlock(timer->curThread->lock);
411*35238bceSAndroid Build Coastguard Worker
412*35238bceSAndroid Build Coastguard Worker return isActive;
413*35238bceSAndroid Build Coastguard Worker }
414*35238bceSAndroid Build Coastguard Worker else
415*35238bceSAndroid Build Coastguard Worker return false;
416*35238bceSAndroid Build Coastguard Worker }
417*35238bceSAndroid Build Coastguard Worker
deTimer_scheduleSingle(deTimer * timer,int milliseconds)418*35238bceSAndroid Build Coastguard Worker bool deTimer_scheduleSingle(deTimer *timer, int milliseconds)
419*35238bceSAndroid Build Coastguard Worker {
420*35238bceSAndroid Build Coastguard Worker if (timer->curThread)
421*35238bceSAndroid Build Coastguard Worker deTimer_disable(timer);
422*35238bceSAndroid Build Coastguard Worker
423*35238bceSAndroid Build Coastguard Worker DE_ASSERT(!timer->curThread);
424*35238bceSAndroid Build Coastguard Worker timer->curThread = deTimerThread_create(timer->callback, timer->callbackArg, milliseconds, TIMERSTATE_SINGLE);
425*35238bceSAndroid Build Coastguard Worker
426*35238bceSAndroid Build Coastguard Worker return timer->curThread != DE_NULL;
427*35238bceSAndroid Build Coastguard Worker }
428*35238bceSAndroid Build Coastguard Worker
deTimer_scheduleInterval(deTimer * timer,int milliseconds)429*35238bceSAndroid Build Coastguard Worker bool deTimer_scheduleInterval(deTimer *timer, int milliseconds)
430*35238bceSAndroid Build Coastguard Worker {
431*35238bceSAndroid Build Coastguard Worker if (timer->curThread)
432*35238bceSAndroid Build Coastguard Worker deTimer_disable(timer);
433*35238bceSAndroid Build Coastguard Worker
434*35238bceSAndroid Build Coastguard Worker DE_ASSERT(!timer->curThread);
435*35238bceSAndroid Build Coastguard Worker timer->curThread = deTimerThread_create(timer->callback, timer->callbackArg, milliseconds, TIMERSTATE_INTERVAL);
436*35238bceSAndroid Build Coastguard Worker
437*35238bceSAndroid Build Coastguard Worker return timer->curThread != DE_NULL;
438*35238bceSAndroid Build Coastguard Worker }
439*35238bceSAndroid Build Coastguard Worker
deTimer_disable(deTimer * timer)440*35238bceSAndroid Build Coastguard Worker void deTimer_disable(deTimer *timer)
441*35238bceSAndroid Build Coastguard Worker {
442*35238bceSAndroid Build Coastguard Worker if (!timer->curThread)
443*35238bceSAndroid Build Coastguard Worker return;
444*35238bceSAndroid Build Coastguard Worker
445*35238bceSAndroid Build Coastguard Worker deMutex_lock(timer->curThread->lock);
446*35238bceSAndroid Build Coastguard Worker
447*35238bceSAndroid Build Coastguard Worker if (timer->curThread->state != TIMERSTATE_DISABLED)
448*35238bceSAndroid Build Coastguard Worker {
449*35238bceSAndroid Build Coastguard Worker /* Just set state to disabled and destroy thread handle. */
450*35238bceSAndroid Build Coastguard Worker /* \note Assumes that deThread_destroy() can be called while thread is still running
451*35238bceSAndroid Build Coastguard Worker * and it will not terminate the thread.
452*35238bceSAndroid Build Coastguard Worker */
453*35238bceSAndroid Build Coastguard Worker timer->curThread->state = TIMERSTATE_DISABLED;
454*35238bceSAndroid Build Coastguard Worker deThread_destroy(timer->curThread->thread);
455*35238bceSAndroid Build Coastguard Worker timer->curThread->thread = 0;
456*35238bceSAndroid Build Coastguard Worker deMutex_unlock(timer->curThread->lock);
457*35238bceSAndroid Build Coastguard Worker
458*35238bceSAndroid Build Coastguard Worker /* Thread will destroy timer->curThread. */
459*35238bceSAndroid Build Coastguard Worker }
460*35238bceSAndroid Build Coastguard Worker else
461*35238bceSAndroid Build Coastguard Worker {
462*35238bceSAndroid Build Coastguard Worker /* Single timer has expired - we must destroy whole thread structure. */
463*35238bceSAndroid Build Coastguard Worker deMutex_unlock(timer->curThread->lock);
464*35238bceSAndroid Build Coastguard Worker deThread_destroy(timer->curThread->thread);
465*35238bceSAndroid Build Coastguard Worker deMutex_destroy(timer->curThread->lock);
466*35238bceSAndroid Build Coastguard Worker deFree(timer->curThread);
467*35238bceSAndroid Build Coastguard Worker }
468*35238bceSAndroid Build Coastguard Worker
469*35238bceSAndroid Build Coastguard Worker timer->curThread = DE_NULL;
470*35238bceSAndroid Build Coastguard Worker }
471*35238bceSAndroid Build Coastguard Worker
472*35238bceSAndroid Build Coastguard Worker #endif
473