update dev300-m58
[ooovba.git] / vos / source / timer.cxx
blob897c14cd3840ac1e4f91accb2923a568000f6cf9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: timer.cxx,v $
10 * $Revision: 1.8 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <osl/time.h>
33 #include <vos/timer.hxx>
34 #include <vos/diagnose.hxx>
35 #include <vos/ref.hxx>
36 #include <vos/thread.hxx>
37 #include <vos/conditn.hxx>
40 /////////////////////////////////////////////////////////////////////////////
42 // Timer manager
45 class OTimerManagerCleanup;
47 class NAMESPACE_VOS(OTimerManager) : public NAMESPACE_VOS(OThread)
50 public:
52 ///
53 OTimerManager();
55 ///
56 ~OTimerManager();
58 /// register timer
59 sal_Bool SAL_CALL registerTimer(NAMESPACE_VOS(OTimer)* pTimer);
61 /// unregister timer
62 sal_Bool SAL_CALL unregisterTimer(NAMESPACE_VOS(OTimer)* pTimer);
64 /// lookup timer
65 sal_Bool SAL_CALL lookupTimer(const NAMESPACE_VOS(OTimer)* pTimer);
67 /// retrieves the "Singleton" TimerManager Instance
68 static OTimerManager* SAL_CALL getTimerManager();
71 protected:
73 /// worker-function of thread
74 virtual void SAL_CALL run();
76 // Checking and triggering of a timer event
77 void SAL_CALL checkForTimeout();
79 // cleanup Method
80 virtual void SAL_CALL onTerminated();
82 // sorted-queue data
83 NAMESPACE_VOS(OTimer)* m_pHead;
84 // List Protection
85 NAMESPACE_VOS(OMutex) m_Lock;
86 // Signal the insertion of a timer
87 NAMESPACE_VOS(OCondition) m_notEmpty;
89 // Synchronize access to OTimerManager
90 static NAMESPACE_VOS(OMutex) m_Access;
92 // "Singleton Pattern"
93 static NAMESPACE_VOS(OTimerManager)* m_pManager;
95 friend class OTimerManagerCleanup;
99 using namespace vos;
101 /////////////////////////////////////////////////////////////////////////////
103 // Timer class
106 VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OTimer, vos),
107 VOS_NAMESPACE(OTimer, vos),
108 VOS_NAMESPACE(OObject, vos), 0);
110 OTimer::OTimer()
112 m_TimeOut = 0;
113 m_Expired = 0;
114 m_RepeatDelta = 0;
115 m_pNext = 0;
118 OTimer::OTimer(const TTimeValue& Time)
120 m_TimeOut = Time;
121 m_RepeatDelta = 0;
122 m_Expired = 0;
123 m_pNext = 0;
125 m_TimeOut.normalize();
128 OTimer::OTimer(const TTimeValue& Time, const TTimeValue& Repeat)
130 m_TimeOut = Time;
131 m_RepeatDelta = Repeat;
132 m_Expired = 0;
133 m_pNext = 0;
135 m_TimeOut.normalize();
136 m_RepeatDelta.normalize();
139 OTimer::~OTimer()
141 stop();
144 void OTimer::start()
146 if (! isTicking())
148 if (! m_TimeOut.isEmpty())
149 setRemainingTime(m_TimeOut);
151 OTimerManager *pManager = OTimerManager::getTimerManager();
153 VOS_ASSERT(pManager);
155 if ( pManager != 0 )
157 pManager->registerTimer(this);
162 void OTimer::stop()
164 OTimerManager *pManager = OTimerManager::getTimerManager();
166 VOS_ASSERT(pManager);
168 if ( pManager != 0 )
170 pManager->unregisterTimer(this);
174 sal_Bool OTimer::isTicking() const
176 OTimerManager *pManager = OTimerManager::getTimerManager();
178 VOS_ASSERT(pManager);
180 if (pManager)
181 return pManager->lookupTimer(this);
182 else
183 return sal_False;
187 sal_Bool OTimer::isExpired() const
189 TTimeValue Now;
191 osl_getSystemTime(&Now);
193 return !(Now < m_Expired);
196 sal_Bool OTimer::expiresBefore(const OTimer* pTimer) const
198 VOS_ASSERT(pTimer);
200 if ( pTimer != 0 )
202 return m_Expired < pTimer->m_Expired;
204 else
206 return sal_False;
210 void OTimer::setAbsoluteTime(const TTimeValue& Time)
212 m_TimeOut = 0;
213 m_Expired = Time;
214 m_RepeatDelta = 0;
216 m_Expired.normalize();
219 void OTimer::setRemainingTime(const TTimeValue& Remaining)
221 osl_getSystemTime(&m_Expired);
223 m_Expired.addTime(Remaining);
226 void OTimer::setRemainingTime(const TTimeValue& Remaining, const TTimeValue& Repeat)
228 osl_getSystemTime(&m_Expired);
230 m_Expired.addTime(Remaining);
232 m_RepeatDelta = Repeat;
235 void OTimer::addTime(const TTimeValue& Delta)
237 m_Expired.addTime(Delta);
240 TTimeValue OTimer::getRemainingTime() const
242 TTimeValue Now;
244 osl_getSystemTime(&Now);
246 sal_Int32 secs = m_Expired.Seconds - Now.Seconds;
248 if (secs < 0)
249 return TTimeValue(0, 0);
251 sal_Int32 nsecs = m_Expired.Nanosec - Now.Nanosec;
253 if (nsecs < 0)
255 if (secs > 0)
257 secs -= 1;
258 nsecs += 1000000000;
260 else
261 return TTimeValue(0, 0);
264 return TTimeValue(secs, nsecs);
268 /////////////////////////////////////////////////////////////////////////////
270 // Timer manager
273 OMutex NAMESPACE_VOS(OTimerManager)::m_Access;
274 OTimerManager* NAMESPACE_VOS(OTimerManager)::m_pManager=0;
276 OTimerManager::OTimerManager()
278 OGuard Guard(&m_Access);
280 VOS_ASSERT(m_pManager == 0);
282 m_pManager = this;
284 m_pHead= 0;
286 m_notEmpty.reset();
288 // start thread
289 create();
292 OTimerManager::~OTimerManager()
294 OGuard Guard(&m_Access);
296 if ( m_pManager == this )
297 m_pManager = 0;
300 void OTimerManager::onTerminated()
302 delete this; // mfe: AAARRRGGGHHH!!!
305 OTimerManager* OTimerManager::getTimerManager()
307 OGuard Guard(&m_Access);
309 if (! m_pManager)
310 new OTimerManager;
312 return (m_pManager);
315 sal_Bool OTimerManager::registerTimer(OTimer* pTimer)
317 VOS_ASSERT(pTimer);
319 if ( pTimer == 0 )
321 return sal_False;
324 OGuard Guard(&m_Lock);
326 // try to find one with equal or lower remaining time.
327 OTimer** ppIter = &m_pHead;
329 while (*ppIter)
331 if (pTimer->expiresBefore(*ppIter))
333 // next element has higher remaining time,
334 // => insert new timer before
335 break;
337 ppIter= &((*ppIter)->m_pNext);
340 // next element has higher remaining time,
341 // => insert new timer before
342 pTimer->m_pNext= *ppIter;
343 *ppIter = pTimer;
346 if (pTimer == m_pHead)
348 // it was inserted as new head
349 // signal it to TimerManager Thread
350 m_notEmpty.set();
353 return sal_True;
356 sal_Bool OTimerManager::unregisterTimer(OTimer* pTimer)
358 VOS_ASSERT(pTimer);
360 if ( pTimer == 0 )
362 return sal_False;
365 // lock access
366 OGuard Guard(&m_Lock);
368 OTimer** ppIter = &m_pHead;
370 while (*ppIter)
372 if (pTimer == (*ppIter))
374 // remove timer from list
375 *ppIter = (*ppIter)->m_pNext;
376 return sal_True;
378 ppIter= &((*ppIter)->m_pNext);
381 return sal_False;
384 sal_Bool OTimerManager::lookupTimer(const OTimer* pTimer)
386 VOS_ASSERT(pTimer);
388 if ( pTimer == 0 )
390 return sal_False;
393 // lock access
394 OGuard Guard(&m_Lock);
396 // check the list
397 for (OTimer* pIter = m_pHead; pIter != 0; pIter= pIter->m_pNext)
399 if (pIter == pTimer)
401 return sal_True;
405 return sal_False;
408 void OTimerManager::checkForTimeout()
411 m_Lock.acquire();
413 if ( m_pHead == 0 )
415 m_Lock.release();
416 return;
419 OTimer* pTimer = m_pHead;
421 if (pTimer->isExpired())
423 // remove expired timer
424 m_pHead = pTimer->m_pNext;
426 pTimer->acquire();
428 m_Lock.release();
430 pTimer->onShot();
432 // restart timer if specified
433 if ( ! pTimer->m_RepeatDelta.isEmpty() )
435 TTimeValue Now;
437 osl_getSystemTime(&Now);
439 Now.Seconds += pTimer->m_RepeatDelta.Seconds;
440 Now.Nanosec += pTimer->m_RepeatDelta.Nanosec;
442 pTimer->m_Expired = Now;
444 registerTimer(pTimer);
446 pTimer->release();
448 else
450 m_Lock.release();
454 return;
457 void OTimerManager::run()
459 setPriority(TPriority_BelowNormal);
461 while (schedule())
463 TTimeValue delay;
464 TTimeValue* pDelay=0;
467 m_Lock.acquire();
469 if (m_pHead != 0)
471 delay = m_pHead->getRemainingTime();
472 pDelay=&delay;
474 else
476 pDelay=0;
480 m_notEmpty.reset();
482 m_Lock.release();
485 m_notEmpty.wait(pDelay);
487 checkForTimeout();
493 /////////////////////////////////////////////////////////////////////////////
495 // Timer manager cleanup
498 // jbu:
499 // The timer manager cleanup has been removed (no thread is killed anymore).
500 // So the thread leaks.
501 // This will result in a GPF in case the vos-library gets unloaded before
502 // process termination.
503 // -> TODO : rewrite this file, so that the timerManager thread gets destroyed,
504 // when there are no timers anymore !