1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include <osl/time.h>
25
26 #include <vos/timer.hxx>
27 #include <vos/diagnose.hxx>
28 #include <vos/ref.hxx>
29 #include <vos/thread.hxx>
30 #include <vos/conditn.hxx>
31
32
33 /////////////////////////////////////////////////////////////////////////////
34 //
35 // Timer manager
36 //
37
38 class OTimerManagerCleanup;
39
40 class vos::OTimerManager : public vos::OThread
41 {
42
43 public:
44
45 ///
46 OTimerManager();
47
48 ///
49 ~OTimerManager();
50
51 /// register timer
52 sal_Bool SAL_CALL registerTimer(vos::OTimer* pTimer);
53
54 /// unregister timer
55 sal_Bool SAL_CALL unregisterTimer(vos::OTimer* pTimer);
56
57 /// lookup timer
58 sal_Bool SAL_CALL lookupTimer(const vos::OTimer* pTimer);
59
60 /// retrieves the "Singleton" TimerManager Instance
61 static OTimerManager* SAL_CALL getTimerManager();
62
63
64 protected:
65
66 /// worker-function of thread
67 virtual void SAL_CALL run();
68
69 // Checking and triggering of a timer event
70 void SAL_CALL checkForTimeout();
71
72 // cleanup Method
73 virtual void SAL_CALL onTerminated();
74
75 // sorted-queue data
76 vos::OTimer* m_pHead;
77 // List Protection
78 vos::OMutex m_Lock;
79 // Signal the insertion of a timer
80 vos::OCondition m_notEmpty;
81
82 // Synchronize access to OTimerManager
83 static vos::OMutex m_Access;
84
85 // "Singleton Pattern"
86 static vos::OTimerManager* m_pManager;
87
88 friend class OTimerManagerCleanup;
89
90 };
91
92 using namespace vos;
93
94 /////////////////////////////////////////////////////////////////////////////
95 //
96 // Timer class
97 //
98
99 VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OTimer, vos),
100 VOS_NAMESPACE(OTimer, vos),
101 VOS_NAMESPACE(OObject, vos), 0);
102
OTimer()103 OTimer::OTimer()
104 {
105 m_TimeOut = 0;
106 m_Expired = 0;
107 m_RepeatDelta = 0;
108 m_pNext = 0;
109 }
110
OTimer(const TTimeValue & Time)111 OTimer::OTimer(const TTimeValue& Time)
112 {
113 m_TimeOut = Time;
114 m_RepeatDelta = 0;
115 m_Expired = 0;
116 m_pNext = 0;
117
118 m_TimeOut.normalize();
119 }
120
OTimer(const TTimeValue & Time,const TTimeValue & Repeat)121 OTimer::OTimer(const TTimeValue& Time, const TTimeValue& Repeat)
122 {
123 m_TimeOut = Time;
124 m_RepeatDelta = Repeat;
125 m_Expired = 0;
126 m_pNext = 0;
127
128 m_TimeOut.normalize();
129 m_RepeatDelta.normalize();
130 }
131
~OTimer()132 OTimer::~OTimer()
133 {
134 stop();
135 }
136
start()137 void OTimer::start()
138 {
139 if (! isTicking())
140 {
141 if (! m_TimeOut.isEmpty())
142 setRemainingTime(m_TimeOut);
143
144 OTimerManager *pManager = OTimerManager::getTimerManager();
145
146 VOS_ASSERT(pManager);
147
148 if ( pManager != 0 )
149 {
150 pManager->registerTimer(this);
151 }
152 }
153 }
154
stop()155 void OTimer::stop()
156 {
157 OTimerManager *pManager = OTimerManager::getTimerManager();
158
159 VOS_ASSERT(pManager);
160
161 if ( pManager != 0 )
162 {
163 pManager->unregisterTimer(this);
164 }
165 }
166
isTicking() const167 sal_Bool OTimer::isTicking() const
168 {
169 OTimerManager *pManager = OTimerManager::getTimerManager();
170
171 VOS_ASSERT(pManager);
172
173 if (pManager)
174 return pManager->lookupTimer(this);
175 else
176 return sal_False;
177
178 }
179
isExpired() const180 sal_Bool OTimer::isExpired() const
181 {
182 TTimeValue Now;
183
184 osl_getSystemTime(&Now);
185
186 return !(Now < m_Expired);
187 }
188
expiresBefore(const OTimer * pTimer) const189 sal_Bool OTimer::expiresBefore(const OTimer* pTimer) const
190 {
191 VOS_ASSERT(pTimer);
192
193 if ( pTimer != 0 )
194 {
195 return m_Expired < pTimer->m_Expired;
196 }
197 else
198 {
199 return sal_False;
200 }
201 }
202
setAbsoluteTime(const TTimeValue & Time)203 void OTimer::setAbsoluteTime(const TTimeValue& Time)
204 {
205 m_TimeOut = 0;
206 m_Expired = Time;
207 m_RepeatDelta = 0;
208
209 m_Expired.normalize();
210 }
211
setRemainingTime(const TTimeValue & Remaining)212 void OTimer::setRemainingTime(const TTimeValue& Remaining)
213 {
214 osl_getSystemTime(&m_Expired);
215
216 m_Expired.addTime(Remaining);
217 }
218
setRemainingTime(const TTimeValue & Remaining,const TTimeValue & Repeat)219 void OTimer::setRemainingTime(const TTimeValue& Remaining, const TTimeValue& Repeat)
220 {
221 osl_getSystemTime(&m_Expired);
222
223 m_Expired.addTime(Remaining);
224
225 m_RepeatDelta = Repeat;
226 }
227
addTime(const TTimeValue & Delta)228 void OTimer::addTime(const TTimeValue& Delta)
229 {
230 m_Expired.addTime(Delta);
231 }
232
getRemainingTime() const233 TTimeValue OTimer::getRemainingTime() const
234 {
235 TTimeValue Now;
236
237 osl_getSystemTime(&Now);
238
239 sal_Int32 secs = m_Expired.Seconds - Now.Seconds;
240
241 if (secs < 0)
242 return TTimeValue(0, 0);
243
244 sal_Int32 nsecs = m_Expired.Nanosec - Now.Nanosec;
245
246 if (nsecs < 0)
247 {
248 if (secs > 0)
249 {
250 secs -= 1;
251 nsecs += 1000000000;
252 }
253 else
254 return TTimeValue(0, 0);
255 }
256
257 return TTimeValue(secs, nsecs);
258 }
259
260
261 /////////////////////////////////////////////////////////////////////////////
262 //
263 // Timer manager
264 //
265
266 OMutex vos::OTimerManager::m_Access;
267 OTimerManager* vos::OTimerManager::m_pManager=0;
268
OTimerManager()269 OTimerManager::OTimerManager()
270 {
271 OGuard Guard(&m_Access);
272
273 VOS_ASSERT(m_pManager == 0);
274
275 m_pManager = this;
276
277 m_pHead= 0;
278
279 m_notEmpty.reset();
280
281 // start thread
282 create();
283 }
284
~OTimerManager()285 OTimerManager::~OTimerManager()
286 {
287 OGuard Guard(&m_Access);
288
289 if ( m_pManager == this )
290 m_pManager = 0;
291 }
292
onTerminated()293 void OTimerManager::onTerminated()
294 {
295 delete this; // mfe: AAARRRGGGHHH!!!
296 }
297
getTimerManager()298 OTimerManager* OTimerManager::getTimerManager()
299 {
300 OGuard Guard(&m_Access);
301
302 if (! m_pManager)
303 new OTimerManager;
304
305 return (m_pManager);
306 }
307
registerTimer(OTimer * pTimer)308 sal_Bool OTimerManager::registerTimer(OTimer* pTimer)
309 {
310 VOS_ASSERT(pTimer);
311
312 if ( pTimer == 0 )
313 {
314 return sal_False;
315 }
316
317 OGuard Guard(&m_Lock);
318
319 // try to find one with equal or lower remaining time.
320 OTimer** ppIter = &m_pHead;
321
322 while (*ppIter)
323 {
324 if (pTimer->expiresBefore(*ppIter))
325 {
326 // next element has higher remaining time,
327 // => insert new timer before
328 break;
329 }
330 ppIter= &((*ppIter)->m_pNext);
331 }
332
333 // next element has higher remaining time,
334 // => insert new timer before
335 pTimer->m_pNext= *ppIter;
336 *ppIter = pTimer;
337
338
339 if (pTimer == m_pHead)
340 {
341 // it was inserted as new head
342 // signal it to TimerManager Thread
343 m_notEmpty.set();
344 }
345
346 return sal_True;
347 }
348
unregisterTimer(OTimer * pTimer)349 sal_Bool OTimerManager::unregisterTimer(OTimer* pTimer)
350 {
351 VOS_ASSERT(pTimer);
352
353 if ( pTimer == 0 )
354 {
355 return sal_False;
356 }
357
358 // lock access
359 OGuard Guard(&m_Lock);
360
361 OTimer** ppIter = &m_pHead;
362
363 while (*ppIter)
364 {
365 if (pTimer == (*ppIter))
366 {
367 // remove timer from list
368 *ppIter = (*ppIter)->m_pNext;
369 return sal_True;
370 }
371 ppIter= &((*ppIter)->m_pNext);
372 }
373
374 return sal_False;
375 }
376
lookupTimer(const OTimer * pTimer)377 sal_Bool OTimerManager::lookupTimer(const OTimer* pTimer)
378 {
379 VOS_ASSERT(pTimer);
380
381 if ( pTimer == 0 )
382 {
383 return sal_False;
384 }
385
386 // lock access
387 OGuard Guard(&m_Lock);
388
389 // check the list
390 for (OTimer* pIter = m_pHead; pIter != 0; pIter= pIter->m_pNext)
391 {
392 if (pIter == pTimer)
393 {
394 return sal_True;
395 }
396 }
397
398 return sal_False;
399 }
400
checkForTimeout()401 void OTimerManager::checkForTimeout()
402 {
403
404 m_Lock.acquire();
405
406 if ( m_pHead == 0 )
407 {
408 m_Lock.release();
409 return;
410 }
411
412 OTimer* pTimer = m_pHead;
413
414 if (pTimer->isExpired())
415 {
416 // remove expired timer
417 m_pHead = pTimer->m_pNext;
418
419 pTimer->acquire();
420
421 m_Lock.release();
422
423 pTimer->onShot();
424
425 // restart timer if specified
426 if ( ! pTimer->m_RepeatDelta.isEmpty() )
427 {
428 TTimeValue Now;
429
430 osl_getSystemTime(&Now);
431
432 Now.Seconds += pTimer->m_RepeatDelta.Seconds;
433 Now.Nanosec += pTimer->m_RepeatDelta.Nanosec;
434
435 pTimer->m_Expired = Now;
436
437 registerTimer(pTimer);
438 }
439 pTimer->release();
440 }
441 else
442 {
443 m_Lock.release();
444 }
445
446
447 return;
448 }
449
run()450 void OTimerManager::run()
451 {
452 setPriority(TPriority_BelowNormal);
453
454 while (schedule())
455 {
456 TTimeValue delay;
457 TTimeValue* pDelay=0;
458
459
460 m_Lock.acquire();
461
462 if (m_pHead != 0)
463 {
464 delay = m_pHead->getRemainingTime();
465 pDelay=&delay;
466 }
467 else
468 {
469 pDelay=0;
470 }
471
472
473 m_notEmpty.reset();
474
475 m_Lock.release();
476
477
478 m_notEmpty.wait(pDelay);
479
480 checkForTimeout();
481 }
482
483 }
484
485
486 /////////////////////////////////////////////////////////////////////////////
487 //
488 // Timer manager cleanup
489 //
490
491 // jbu:
492 // The timer manager cleanup has been removed (no thread is killed anymore).
493 // So the thread leaks.
494 // This will result in a GPF in case the vos-library gets unloaded before
495 // process termination.
496 // -> TODO : rewrite this file, so that the timerManager thread gets destroyed,
497 // when there are no timers anymore !
498