xref: /aosp_15_r20/external/deqp/framework/delibs/deutil/deTimer.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
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