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 /////////////////////////////////////////////////////////////////////////////
90 Timer::Timer( const TTimeValue
& Time
)
98 Timer::Timer( const TTimeValue
& Time
, const TTimeValue
& Repeat
)
101 m_aRepeatDelta( Repeat
),
115 if (! m_aTimeOut
.isEmpty())
116 setRemainingTime(m_aTimeOut
);
118 TimerManager
*pManager
= TimerManager::getTimerManager();
120 OSL_ASSERT(pManager
);
124 pManager
->registerTimer(this);
131 TimerManager
*pManager
= TimerManager::getTimerManager();
133 OSL_ASSERT(pManager
);
137 pManager
->unregisterTimer(this);
141 sal_Bool
Timer::isTicking() const
143 TimerManager
*pManager
= TimerManager::getTimerManager();
145 OSL_ASSERT(pManager
);
148 return pManager
->lookupTimer(this);
154 sal_Bool
Timer::isExpired() const
158 osl_getSystemTime(&Now
);
160 return !(Now
< m_aExpired
);
163 sal_Bool
Timer::expiresBefore(const Timer
* pTimer
) const
169 return m_aExpired
< pTimer
->m_aExpired
;
177 void Timer::setAbsoluteTime(const TTimeValue
& Time
)
183 m_aExpired
.normalize();
186 void Timer::setRemainingTime(const TTimeValue
& Remaining
)
188 osl_getSystemTime(&m_aExpired
);
190 m_aExpired
.addTime(Remaining
);
193 void Timer::setRemainingTime(const TTimeValue
& Remaining
, const TTimeValue
& Repeat
)
195 osl_getSystemTime(&m_aExpired
);
197 m_aExpired
.addTime(Remaining
);
199 m_aRepeatDelta
= Repeat
;
202 void Timer::addTime(const TTimeValue
& Delta
)
204 m_aExpired
.addTime(Delta
);
207 TTimeValue
Timer::getRemainingTime() const
211 osl_getSystemTime(&Now
);
213 sal_Int32 secs
= m_aExpired
.Seconds
- Now
.Seconds
;
216 return TTimeValue(0, 0);
218 sal_Int32 nsecs
= m_aExpired
.Nanosec
- Now
.Nanosec
;
225 nsecs
+= 1000000000L;
228 return TTimeValue(0, 0);
231 return TTimeValue(secs
, nsecs
);
235 /////////////////////////////////////////////////////////////////////////////
241 // Synchronize access to TimerManager
242 struct theTimerManagerMutex
: public rtl::Static
< osl::Mutex
, theTimerManagerMutex
> {};
245 TimerManager
* salhelper::TimerManager::m_pManager
= NULL
;
247 TimerManager::TimerManager()
249 osl::MutexGuard
Guard(theTimerManagerMutex::get());
251 OSL_ASSERT(m_pManager
== 0);
263 TimerManager::~TimerManager()
265 osl::MutexGuard
Guard(theTimerManagerMutex::get());
267 if ( m_pManager
== this )
271 void TimerManager::onTerminated()
273 delete this; // mfe: AAARRRGGGHHH!!!
276 TimerManager
* TimerManager::getTimerManager()
278 osl::MutexGuard
Guard(theTimerManagerMutex::get());
286 sal_Bool
TimerManager::registerTimer(Timer
* pTimer
)
295 osl::MutexGuard
Guard(m_Lock
);
297 // try to find one with equal or lower remaining time.
298 Timer
** ppIter
= &m_pHead
;
302 if (pTimer
->expiresBefore(*ppIter
))
304 // next element has higher remaining time,
305 // => insert new timer before
308 ppIter
= &((*ppIter
)->m_pNext
);
311 // next element has higher remaining time,
312 // => insert new timer before
313 pTimer
->m_pNext
= *ppIter
;
317 if (pTimer
== m_pHead
)
319 // it was inserted as new head
320 // signal it to TimerManager Thread
327 sal_Bool
TimerManager::unregisterTimer(Timer
* pTimer
)
337 osl::MutexGuard
Guard(m_Lock
);
339 Timer
** ppIter
= &m_pHead
;
343 if (pTimer
== (*ppIter
))
345 // remove timer from list
346 *ppIter
= (*ppIter
)->m_pNext
;
349 ppIter
= &((*ppIter
)->m_pNext
);
355 sal_Bool
TimerManager::lookupTimer(const Timer
* pTimer
)
365 osl::MutexGuard
Guard(m_Lock
);
368 for (Timer
* pIter
= m_pHead
; pIter
!= 0; pIter
= pIter
->m_pNext
)
379 void TimerManager::checkForTimeout()
390 Timer
* pTimer
= m_pHead
;
392 if (pTimer
->isExpired())
394 // remove expired timer
395 m_pHead
= pTimer
->m_pNext
;
403 // restart timer if specified
404 if ( ! pTimer
->m_aRepeatDelta
.isEmpty() )
408 osl_getSystemTime(&Now
);
410 Now
.Seconds
+= pTimer
->m_aRepeatDelta
.Seconds
;
411 Now
.Nanosec
+= pTimer
->m_aRepeatDelta
.Nanosec
;
413 pTimer
->m_aExpired
= Now
;
415 registerTimer(pTimer
);
428 void TimerManager::run()
430 setPriority( osl_Thread_PriorityBelowNormal
);
435 TTimeValue
* pDelay
=0;
442 delay
= m_pHead
->getRemainingTime();
456 m_notEmpty
.wait(pDelay
);
464 /////////////////////////////////////////////////////////////////////////////
466 // Timer manager cleanup
470 // The timer manager cleanup has been removed (no thread is killed anymore).
471 // So the thread leaks.
472 // This will result in a GPF in case the salhelper-library gets unloaded before
473 // process termination.
474 // -> TODO : rewrite this file, so that the timerManager thread gets destroyed,
475 // when there are no timers anymore !
477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */