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