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/thread.hxx>
22 #include <osl/conditn.hxx>
23 #include <osl/mutex.hxx>
24 #include <rtl/instance.hxx>
26 using namespace salhelper
;
28 class salhelper::TimerManager
: public osl::Thread
33 virtual ~TimerManager() override
;
36 void registerTimer(salhelper::Timer
* pTimer
);
39 void unregisterTimer(salhelper::Timer
const * pTimer
);
42 bool lookupTimer(const salhelper::Timer
* pTimer
);
44 /// retrieves the "Singleton" TimerManager Instance
45 static TimerManager
* getTimerManager();
48 /// worker-function of thread
49 virtual void SAL_CALL
run() override
;
51 /// Checking and triggering of a timer event
52 void checkForTimeout();
55 virtual void SAL_CALL
onTerminated() override
;
58 salhelper::Timer
* m_pHead
;
61 /// Signal the insertion of a timer
62 osl::Condition m_notEmpty
;
64 /// "Singleton Pattern"
65 static salhelper::TimerManager
* m_pManager
;
77 Timer::Timer(const TTimeValue
& rTime
)
85 Timer::Timer(const TTimeValue
& rTime
, const TTimeValue
& Repeat
)
88 m_aRepeatDelta(Repeat
),
102 if (!m_aTimeOut
.isEmpty())
103 setRemainingTime(m_aTimeOut
);
105 TimerManager
*pManager
= TimerManager::getTimerManager();
108 pManager
->registerTimer(this);
114 TimerManager
*pManager
= TimerManager::getTimerManager();
117 pManager
->unregisterTimer(this);
120 sal_Bool
Timer::isTicking() const
122 TimerManager
*pManager
= TimerManager::getTimerManager();
125 return pManager
->lookupTimer(this);
130 sal_Bool
Timer::isExpired() const
134 osl_getSystemTime(&Now
);
136 return !(Now
< m_aExpired
);
139 sal_Bool
Timer::expiresBefore(const Timer
* pTimer
) const
142 return m_aExpired
< pTimer
->m_aExpired
;
147 void Timer::setAbsoluteTime(const TTimeValue
& Time
)
153 m_aExpired
.normalize();
156 void Timer::setRemainingTime(const TTimeValue
& Remaining
)
158 osl_getSystemTime(&m_aExpired
);
160 m_aExpired
.addTime(Remaining
);
163 void Timer::setRemainingTime(const TTimeValue
& Remaining
, const TTimeValue
& Repeat
)
165 osl_getSystemTime(&m_aExpired
);
167 m_aExpired
.addTime(Remaining
);
169 m_aRepeatDelta
= Repeat
;
172 void Timer::addTime(const TTimeValue
& Delta
)
174 m_aExpired
.addTime(Delta
);
177 TTimeValue
Timer::getRemainingTime() const
181 osl_getSystemTime(&Now
);
183 sal_Int32 secs
= m_aExpired
.Seconds
- Now
.Seconds
;
186 return TTimeValue(0, 0);
188 sal_Int32 nsecs
= m_aExpired
.Nanosec
- Now
.Nanosec
;
198 return TTimeValue(0, 0);
201 return TTimeValue(secs
, nsecs
);
206 // Synchronize access to TimerManager
207 struct theTimerManagerMutex
: public rtl::Static
< osl::Mutex
, theTimerManagerMutex
> {};
210 TimerManager
* salhelper::TimerManager::m_pManager
= nullptr;
212 /** The timer manager cleanup has been removed (no thread is killed anymore),
215 This will result in a GPF in case the salhelper-library gets unloaded before
218 @TODO : rewrite this file, so that the timerManager thread gets destroyed,
219 when there are no timers anymore !
222 TimerManager::TimerManager()
224 osl::MutexGuard
Guard(theTimerManagerMutex::get());
226 assert(m_pManager
== nullptr);
236 TimerManager::~TimerManager()
238 osl::MutexGuard
Guard(theTimerManagerMutex::get());
240 if (m_pManager
== this)
241 m_pManager
= nullptr;
244 void TimerManager::onTerminated()
246 delete this; // FIXME
249 TimerManager
* TimerManager::getTimerManager()
251 osl::MutexGuard
Guard(theTimerManagerMutex::get());
259 void TimerManager::registerTimer(Timer
* pTimer
)
264 osl::MutexGuard
Guard(m_Lock
);
266 // try to find one with equal or lower remaining time.
267 Timer
** ppIter
= &m_pHead
;
271 if (pTimer
->expiresBefore(*ppIter
))
273 // next element has higher remaining time,
274 // => insert new timer before
277 ppIter
= &((*ppIter
)->m_pNext
);
280 // next element has higher remaining time,
281 // => insert new timer before
282 pTimer
->m_pNext
= *ppIter
;
286 if (pTimer
== m_pHead
)
288 // it was inserted as new head
289 // signal it to TimerManager Thread
294 void TimerManager::unregisterTimer(Timer
const * pTimer
)
300 osl::MutexGuard
Guard(m_Lock
);
302 Timer
** ppIter
= &m_pHead
;
306 if (pTimer
== (*ppIter
))
308 // remove timer from list
309 *ppIter
= (*ppIter
)->m_pNext
;
312 ppIter
= &((*ppIter
)->m_pNext
);
316 bool TimerManager::lookupTimer(const Timer
* pTimer
)
322 osl::MutexGuard
Guard(m_Lock
);
325 for (Timer
* pIter
= m_pHead
; pIter
!= nullptr; pIter
= pIter
->m_pNext
)
334 void TimerManager::checkForTimeout()
344 Timer
* pTimer
= m_pHead
;
346 if (pTimer
->isExpired())
348 // remove expired timer
349 m_pHead
= pTimer
->m_pNext
;
357 // restart timer if specified
358 if (!pTimer
->m_aRepeatDelta
.isEmpty())
362 osl_getSystemTime(&Now
);
364 Now
.Seconds
+= pTimer
->m_aRepeatDelta
.Seconds
;
365 Now
.Nanosec
+= pTimer
->m_aRepeatDelta
.Nanosec
;
367 pTimer
->m_aExpired
= Now
;
369 registerTimer(pTimer
);
379 void TimerManager::run()
381 osl_setThreadName("salhelper::TimerManager");
383 setPriority( osl_Thread_PriorityBelowNormal
);
388 TTimeValue
* pDelay
=nullptr;
392 if (m_pHead
!= nullptr)
394 delay
= m_pHead
->getRemainingTime();
408 m_notEmpty
.wait(pDelay
);
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */