1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <salhelper/timer.hxx>
21 #include <osl/diagnose.h>
22 #include <salhelper/simplereferenceobject.hxx>
23 #include <osl/thread.hxx>
24 #include <osl/conditn.hxx>
25 #include <osl/mutex.hxx>
26 #include <rtl/instance.hxx>
28 using namespace salhelper
;
30 class salhelper::TimerManager
: public osl::Thread
42 sal_Bool SAL_CALL
registerTimer(salhelper::Timer
* pTimer
);
45 sal_Bool SAL_CALL
unregisterTimer(salhelper::Timer
* pTimer
);
48 sal_Bool SAL_CALL
lookupTimer(const salhelper::Timer
* pTimer
);
50 /// retrieves the "Singleton" TimerManager Instance
51 static TimerManager
* SAL_CALL
getTimerManager();
56 /// worker-function of thread
57 virtual void SAL_CALL
run();
59 // Checking and triggering of a timer event
60 void SAL_CALL
checkForTimeout();
63 virtual void SAL_CALL
onTerminated();
66 salhelper::Timer
* m_pHead
;
69 // Signal the insertion of a timer
70 osl::Condition m_notEmpty
;
72 // "Singleton Pattern"
73 static salhelper::TimerManager
* m_pManager
;
77 using namespace salhelper
;
79 /////////////////////////////////////////////////////////////////////////////
92 Timer::Timer( const TTimeValue
& Time
)
100 Timer::Timer( const TTimeValue
& Time
, const TTimeValue
& Repeat
)
101 : m_aTimeOut( Time
),
103 m_aRepeatDelta( Repeat
),
117 if (! m_aTimeOut
.isEmpty())
118 setRemainingTime(m_aTimeOut
);
120 TimerManager
*pManager
= TimerManager::getTimerManager();
122 OSL_ASSERT(pManager
);
126 pManager
->registerTimer(this);
133 TimerManager
*pManager
= TimerManager::getTimerManager();
135 OSL_ASSERT(pManager
);
139 pManager
->unregisterTimer(this);
143 sal_Bool
Timer::isTicking() const
145 TimerManager
*pManager
= TimerManager::getTimerManager();
147 OSL_ASSERT(pManager
);
150 return pManager
->lookupTimer(this);
156 sal_Bool
Timer::isExpired() const
160 osl_getSystemTime(&Now
);
162 return !(Now
< m_aExpired
);
165 sal_Bool
Timer::expiresBefore(const Timer
* pTimer
) const
171 return m_aExpired
< pTimer
->m_aExpired
;
179 void Timer::setAbsoluteTime(const TTimeValue
& Time
)
185 m_aExpired
.normalize();
188 void Timer::setRemainingTime(const TTimeValue
& Remaining
)
190 osl_getSystemTime(&m_aExpired
);
192 m_aExpired
.addTime(Remaining
);
195 void Timer::setRemainingTime(const TTimeValue
& Remaining
, const TTimeValue
& Repeat
)
197 osl_getSystemTime(&m_aExpired
);
199 m_aExpired
.addTime(Remaining
);
201 m_aRepeatDelta
= Repeat
;
204 void Timer::addTime(const TTimeValue
& Delta
)
206 m_aExpired
.addTime(Delta
);
209 TTimeValue
Timer::getRemainingTime() const
213 osl_getSystemTime(&Now
);
215 sal_Int32 secs
= m_aExpired
.Seconds
- Now
.Seconds
;
218 return TTimeValue(0, 0);
220 sal_Int32 nsecs
= m_aExpired
.Nanosec
- Now
.Nanosec
;
227 nsecs
+= 1000000000L;
230 return TTimeValue(0, 0);
233 return TTimeValue(secs
, nsecs
);
237 /////////////////////////////////////////////////////////////////////////////
243 // Synchronize access to TimerManager
244 struct theTimerManagerMutex
: public rtl::Static
< osl::Mutex
, theTimerManagerMutex
> {};
247 TimerManager
* salhelper::TimerManager::m_pManager
= NULL
;
249 TimerManager::TimerManager()
251 osl::MutexGuard
Guard(theTimerManagerMutex::get());
253 OSL_ASSERT(m_pManager
== 0);
265 TimerManager::~TimerManager()
267 osl::MutexGuard
Guard(theTimerManagerMutex::get());
269 if ( m_pManager
== this )
273 void TimerManager::onTerminated()
275 delete this; // mfe: AAARRRGGGHHH!!!
278 TimerManager
* TimerManager::getTimerManager()
280 osl::MutexGuard
Guard(theTimerManagerMutex::get());
288 sal_Bool
TimerManager::registerTimer(Timer
* pTimer
)
297 osl::MutexGuard
Guard(m_Lock
);
299 // try to find one with equal or lower remaining time.
300 Timer
** ppIter
= &m_pHead
;
304 if (pTimer
->expiresBefore(*ppIter
))
306 // next element has higher remaining time,
307 // => insert new timer before
310 ppIter
= &((*ppIter
)->m_pNext
);
313 // next element has higher remaining time,
314 // => insert new timer before
315 pTimer
->m_pNext
= *ppIter
;
319 if (pTimer
== m_pHead
)
321 // it was inserted as new head
322 // signal it to TimerManager Thread
329 sal_Bool
TimerManager::unregisterTimer(Timer
* pTimer
)
339 osl::MutexGuard
Guard(m_Lock
);
341 Timer
** ppIter
= &m_pHead
;
345 if (pTimer
== (*ppIter
))
347 // remove timer from list
348 *ppIter
= (*ppIter
)->m_pNext
;
351 ppIter
= &((*ppIter
)->m_pNext
);
357 sal_Bool
TimerManager::lookupTimer(const Timer
* pTimer
)
367 osl::MutexGuard
Guard(m_Lock
);
370 for (Timer
* pIter
= m_pHead
; pIter
!= 0; pIter
= pIter
->m_pNext
)
381 void TimerManager::checkForTimeout()
392 Timer
* pTimer
= m_pHead
;
394 if (pTimer
->isExpired())
396 // remove expired timer
397 m_pHead
= pTimer
->m_pNext
;
405 // restart timer if specified
406 if ( ! pTimer
->m_aRepeatDelta
.isEmpty() )
410 osl_getSystemTime(&Now
);
412 Now
.Seconds
+= pTimer
->m_aRepeatDelta
.Seconds
;
413 Now
.Nanosec
+= pTimer
->m_aRepeatDelta
.Nanosec
;
415 pTimer
->m_aExpired
= Now
;
417 registerTimer(pTimer
);
430 void TimerManager::run()
432 setPriority( osl_Thread_PriorityBelowNormal
);
437 TTimeValue
* pDelay
=0;
444 delay
= m_pHead
->getRemainingTime();
458 m_notEmpty
.wait(pDelay
);
466 /////////////////////////////////////////////////////////////////////////////
468 // Timer manager cleanup
472 // The timer manager cleanup has been removed (no thread is killed anymore).
473 // So the thread leaks.
474 // This will result in a GPF in case the salhelper-library gets unloaded before
475 // process termination.
476 // -> TODO : rewrite this file, so that the timerManager thread gets destroyed,
477 // when there are no timers anymore !
479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */