1//
2// Timer.cpp
3//
4// Library: Foundation
5// Package: Threading
6// Module: Timer
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Timer.h"
16#include "Poco/ThreadPool.h"
17#include "Poco/Exception.h"
18#include "Poco/ErrorHandler.h"
19
20
21namespace Poco {
22
23
24Timer::Timer(long startInterval, long periodicInterval):
25 _startInterval(startInterval),
26 _periodicInterval(periodicInterval),
27 _skipped(0),
28 _pCallback(0)
29{
30 poco_assert (startInterval >= 0 && periodicInterval >= 0);
31}
32
33
34Timer::~Timer()
35{
36 try
37 {
38 stop();
39 }
40 catch (...)
41 {
42 poco_unexpected();
43 }
44}
45
46
47void Timer::start(const AbstractTimerCallback& method)
48{
49 start(method, Thread::PRIO_NORMAL, ThreadPool::defaultPool());
50}
51
52
53void Timer::start(const AbstractTimerCallback& method, Thread::Priority priority)
54{
55 start(method, priority, ThreadPool::defaultPool());
56}
57
58
59void Timer::start(const AbstractTimerCallback& method, ThreadPool& threadPool)
60{
61 start(method, Thread::PRIO_NORMAL, threadPool);
62}
63
64
65void Timer::start(const AbstractTimerCallback& method, Thread::Priority priority, ThreadPool& threadPool)
66{
67 Clock nextInvocation;
68 nextInvocation += static_cast<Clock::ClockVal>(_startInterval)*1000;
69
70 FastMutex::ScopedLock lock(_mutex);
71
72 if (_pCallback)
73 {
74 throw Poco::IllegalStateException("Timer already running");
75 }
76
77 _nextInvocation = nextInvocation;
78 _pCallback = method.clone();
79 _wakeUp.reset();
80 try
81 {
82 threadPool.startWithPriority(priority, *this);
83 }
84 catch (...)
85 {
86 delete _pCallback;
87 _pCallback = 0;
88 throw;
89 }
90}
91
92
93void Timer::stop()
94{
95 FastMutex::ScopedLock lock(_mutex);
96 if (_pCallback)
97 {
98 _periodicInterval = 0;
99 _mutex.unlock();
100 _wakeUp.set();
101 _done.wait(); // warning: deadlock if called from timer callback
102 _mutex.lock();
103 delete _pCallback;
104 _pCallback = 0;
105 }
106}
107
108
109void Timer::restart()
110{
111 FastMutex::ScopedLock lock(_mutex);
112 if (_pCallback)
113 {
114 _wakeUp.set();
115 }
116}
117
118
119void Timer::restart(long milliseconds)
120{
121 poco_assert (milliseconds >= 0);
122 FastMutex::ScopedLock lock(_mutex);
123 if (_pCallback)
124 {
125 _periodicInterval = milliseconds;
126 _wakeUp.set();
127 }
128}
129
130
131long Timer::getStartInterval() const
132{
133 FastMutex::ScopedLock lock(_mutex);
134 return _startInterval;
135}
136
137
138void Timer::setStartInterval(long milliseconds)
139{
140 poco_assert (milliseconds >= 0);
141 FastMutex::ScopedLock lock(_mutex);
142 _startInterval = milliseconds;
143}
144
145
146long Timer::getPeriodicInterval() const
147{
148 FastMutex::ScopedLock lock(_mutex);
149 return _periodicInterval;
150}
151
152
153void Timer::setPeriodicInterval(long milliseconds)
154{
155 poco_assert (milliseconds >= 0);
156 FastMutex::ScopedLock lock(_mutex);
157 _periodicInterval = milliseconds;
158}
159
160
161void Timer::run()
162{
163 Poco::Clock now;
164 long interval(0);
165 do
166 {
167 long sleep(0);
168 do
169 {
170 now.update();
171 sleep = static_cast<long>((_nextInvocation - now)/1000);
172 if (sleep < 0)
173 {
174 if (interval == 0)
175 {
176 sleep = 0;
177 break;
178 }
179 _nextInvocation += static_cast<Clock::ClockVal>(interval)*1000;
180 ++_skipped;
181 }
182 }
183 while (sleep < 0);
184
185 if (_wakeUp.tryWait(sleep))
186 {
187 Poco::FastMutex::ScopedLock lock(_mutex);
188 _nextInvocation.update();
189 interval = _periodicInterval;
190 }
191 else
192 {
193 try
194 {
195 _pCallback->invoke(*this);
196 }
197 catch (Poco::Exception& exc)
198 {
199 Poco::ErrorHandler::handle(exc);
200 }
201 catch (std::exception& exc)
202 {
203 Poco::ErrorHandler::handle(exc);
204 }
205 catch (...)
206 {
207 Poco::ErrorHandler::handle();
208 }
209 Poco::FastMutex::ScopedLock lock(_mutex);
210 interval = _periodicInterval;
211 }
212 _nextInvocation += static_cast<Clock::ClockVal>(interval)*1000;
213 _skipped = 0;
214 }
215 while (interval > 0);
216 _done.set();
217}
218
219
220long Timer::skipped() const
221{
222 return _skipped;
223}
224
225
226AbstractTimerCallback::AbstractTimerCallback()
227{
228}
229
230
231AbstractTimerCallback::AbstractTimerCallback(const AbstractTimerCallback& /*callback*/)
232{
233}
234
235
236AbstractTimerCallback::~AbstractTimerCallback()
237{
238}
239
240
241AbstractTimerCallback& AbstractTimerCallback::operator = (const AbstractTimerCallback& /*callback*/)
242{
243 return *this;
244}
245
246
247} // namespace Poco
248