1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: timer.cxx,v $
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 ************************************************************************/
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 /////////////////////////////////////////////////////////////////////////////
45 class OTimerManagerCleanup
;
47 class NAMESPACE_VOS(OTimerManager
) : public NAMESPACE_VOS(OThread
)
59 sal_Bool SAL_CALL
registerTimer(NAMESPACE_VOS(OTimer
)* pTimer
);
62 sal_Bool SAL_CALL
unregisterTimer(NAMESPACE_VOS(OTimer
)* pTimer
);
65 sal_Bool SAL_CALL
lookupTimer(const NAMESPACE_VOS(OTimer
)* pTimer
);
67 /// retrieves the "Singleton" TimerManager Instance
68 static OTimerManager
* SAL_CALL
getTimerManager();
73 /// worker-function of thread
74 virtual void SAL_CALL
run();
76 // Checking and triggering of a timer event
77 void SAL_CALL
checkForTimeout();
80 virtual void SAL_CALL
onTerminated();
83 NAMESPACE_VOS(OTimer
)* m_pHead
;
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
;
101 /////////////////////////////////////////////////////////////////////////////
106 VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OTimer
, vos
),
107 VOS_NAMESPACE(OTimer
, vos
),
108 VOS_NAMESPACE(OObject
, vos
), 0);
118 OTimer::OTimer(const TTimeValue
& Time
)
125 m_TimeOut
.normalize();
128 OTimer::OTimer(const TTimeValue
& Time
, const TTimeValue
& Repeat
)
131 m_RepeatDelta
= Repeat
;
135 m_TimeOut
.normalize();
136 m_RepeatDelta
.normalize();
148 if (! m_TimeOut
.isEmpty())
149 setRemainingTime(m_TimeOut
);
151 OTimerManager
*pManager
= OTimerManager::getTimerManager();
153 VOS_ASSERT(pManager
);
157 pManager
->registerTimer(this);
164 OTimerManager
*pManager
= OTimerManager::getTimerManager();
166 VOS_ASSERT(pManager
);
170 pManager
->unregisterTimer(this);
174 sal_Bool
OTimer::isTicking() const
176 OTimerManager
*pManager
= OTimerManager::getTimerManager();
178 VOS_ASSERT(pManager
);
181 return pManager
->lookupTimer(this);
187 sal_Bool
OTimer::isExpired() const
191 osl_getSystemTime(&Now
);
193 return !(Now
< m_Expired
);
196 sal_Bool
OTimer::expiresBefore(const OTimer
* pTimer
) const
202 return m_Expired
< pTimer
->m_Expired
;
210 void OTimer::setAbsoluteTime(const TTimeValue
& Time
)
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
244 osl_getSystemTime(&Now
);
246 sal_Int32 secs
= m_Expired
.Seconds
- Now
.Seconds
;
249 return TTimeValue(0, 0);
251 sal_Int32 nsecs
= m_Expired
.Nanosec
- Now
.Nanosec
;
261 return TTimeValue(0, 0);
264 return TTimeValue(secs
, nsecs
);
268 /////////////////////////////////////////////////////////////////////////////
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);
292 OTimerManager::~OTimerManager()
294 OGuard
Guard(&m_Access
);
296 if ( m_pManager
== this )
300 void OTimerManager::onTerminated()
302 delete this; // mfe: AAARRRGGGHHH!!!
305 OTimerManager
* OTimerManager::getTimerManager()
307 OGuard
Guard(&m_Access
);
315 sal_Bool
OTimerManager::registerTimer(OTimer
* pTimer
)
324 OGuard
Guard(&m_Lock
);
326 // try to find one with equal or lower remaining time.
327 OTimer
** ppIter
= &m_pHead
;
331 if (pTimer
->expiresBefore(*ppIter
))
333 // next element has higher remaining time,
334 // => insert new timer before
337 ppIter
= &((*ppIter
)->m_pNext
);
340 // next element has higher remaining time,
341 // => insert new timer before
342 pTimer
->m_pNext
= *ppIter
;
346 if (pTimer
== m_pHead
)
348 // it was inserted as new head
349 // signal it to TimerManager Thread
356 sal_Bool
OTimerManager::unregisterTimer(OTimer
* pTimer
)
366 OGuard
Guard(&m_Lock
);
368 OTimer
** ppIter
= &m_pHead
;
372 if (pTimer
== (*ppIter
))
374 // remove timer from list
375 *ppIter
= (*ppIter
)->m_pNext
;
378 ppIter
= &((*ppIter
)->m_pNext
);
384 sal_Bool
OTimerManager::lookupTimer(const OTimer
* pTimer
)
394 OGuard
Guard(&m_Lock
);
397 for (OTimer
* pIter
= m_pHead
; pIter
!= 0; pIter
= pIter
->m_pNext
)
408 void OTimerManager::checkForTimeout()
419 OTimer
* pTimer
= m_pHead
;
421 if (pTimer
->isExpired())
423 // remove expired timer
424 m_pHead
= pTimer
->m_pNext
;
432 // restart timer if specified
433 if ( ! pTimer
->m_RepeatDelta
.isEmpty() )
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
);
457 void OTimerManager::run()
459 setPriority(TPriority_BelowNormal
);
464 TTimeValue
* pDelay
=0;
471 delay
= m_pHead
->getRemainingTime();
485 m_notEmpty
.wait(pDelay
);
493 /////////////////////////////////////////////////////////////////////////////
495 // Timer manager cleanup
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 !