1 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This file is part of GNU uCommon C++.
5 //
6 // GNU uCommon C++ is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Lesser General Public License as published
8 // by the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // GNU uCommon C++ is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with GNU uCommon C++.  If not, see <http://www.gnu.org/licenses/>.
18 
19 #include <ucommon-config.h>
20 #include <ucommon/export.h>
21 #include <ucommon/timers.h>
22 #include <ucommon/thread.h>
23 #include <ucommon/cpr.h>
24 
25 namespace ucommon {
26 
27 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
28 extern int _posix_clocking;
29 #endif
30 
_difftime(time_t ref)31 static long _difftime(time_t ref)
32 {
33     time_t now;
34     time(&now);
35 
36     return (long)difftime(ref, now);
37 }
38 
39 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
adj(struct timespec * ts)40 static void adj(struct timespec *ts)
41 {
42     assert(ts != NULL);
43 
44     if(ts->tv_nsec >= 1000000000l)
45         ts->tv_sec += (ts->tv_nsec / 1000000000l);
46     ts->tv_nsec %= 1000000000l;
47     if(ts->tv_nsec < 0)
48         ts->tv_nsec = -ts->tv_nsec;
49 }
50 #else
adj(struct timeval * ts)51 static void adj(struct timeval *ts)
52 {
53     assert(ts != NULL);
54 
55     if(ts->tv_usec >= 1000000l)
56         ts->tv_sec += (ts->tv_usec / 1000000l);
57     ts->tv_usec %= 1000000l;
58     if(ts->tv_usec < 0)
59         ts->tv_usec = -ts->tv_usec;
60 }
61 #endif
62 
event(timeout_t timeout)63 TimerQueue::event::event(timeout_t timeout) :
64 Timer(), DLinkedObject()
65 {
66     set(timeout);
67 }
68 
event(TimerQueue * tq,timeout_t timeout)69 TimerQueue::event::event(TimerQueue *tq, timeout_t timeout) :
70 Timer(), DLinkedObject()
71 {
72     set(timeout);
73     Timer::update();
74     attach(tq);
75 }
76 
~event()77 TimerQueue::event::~event()
78 {
79     detach();
80 }
81 
Timer()82 Timer::Timer()
83 {
84     clear();
85 }
86 
Timer(timeout_t in)87 Timer::Timer(timeout_t in)
88 {
89     set();
90     operator+=(in);
91 }
92 
Timer(const Timer & copy)93 Timer::Timer(const Timer& copy)
94 {
95     timer = copy.timer;
96 }
97 
Timer(time_t in)98 Timer::Timer(time_t in)
99 {
100     set();
101     timer.tv_sec += _difftime(in);
102 }
103 
104 #ifdef  _MSWINDOWS_
105 
ticks(void)106 Timer::tick_t Timer::ticks(void)
107 {
108     ULARGE_INTEGER timer;
109 
110     GetSystemTimeAsFileTime((FILETIME*)&timer);
111     timer.QuadPart +=
112         (tick_t) (6893856000000000);
113     return timer.QuadPart;
114 }
115 
116 #else
117 
ticks(void)118 Timer::tick_t Timer::ticks(void)
119 {
120     struct timeval tv;
121     gettimeofday(&tv, NULL);
122     return ((tick_t)tv.tv_sec * (tick_t)10000000) +
123         ((tick_t)tv.tv_usec * 10) + (((tick_t)0x01B21DD2) << 32) + (tick_t)0x13814000;
124 }
125 #endif
126 
set(timeout_t timeout)127 void Timer::set(timeout_t timeout)
128 {
129     set();
130     operator+=(timeout);
131 }
132 
set(time_t time)133 void Timer::set(time_t time)
134 {
135     set();
136     timer.tv_sec += _difftime(time);
137 }
138 
attach(TimerQueue * tq)139 void TimerQueue::event::attach(TimerQueue *tq)
140 {
141     if(tq == list())
142         return;
143 
144     detach();
145     if(!tq)
146         return;
147 
148     tq->modify();
149     enlist(tq);
150     Timer::update();
151     tq->update();
152 }
153 
arm(timeout_t timeout)154 void TimerQueue::event::arm(timeout_t timeout)
155 {
156     TimerQueue *tq = list();
157     if(tq)
158         tq->modify();
159     set(timeout);
160     if(tq)
161         tq->update();
162 }
163 
disarm(void)164 void TimerQueue::event::disarm(void)
165 {
166     TimerQueue *tq = list();
167     bool flag = is_active();
168 
169     if(tq && flag)
170         tq->modify();
171     clear();
172     if(tq && flag)
173         tq->update();
174 }
175 
update(void)176 void TimerQueue::event::update(void)
177 {
178     TimerQueue *tq = list();
179     if(Timer::update() && tq) {
180         tq->modify();
181         tq->update();
182     }
183 }
184 
detach(void)185 void TimerQueue::event::detach(void)
186 {
187     TimerQueue *tq = list();
188     if(tq) {
189         tq->modify();
190         clear();
191         delist();
192         tq->update();
193     }
194 }
195 
set(void)196 void Timer::set(void)
197 {
198 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
199     clock_gettime(_posix_clocking, &timer);
200 #else
201     gettimeofday(&timer, NULL);
202 #endif
203     updated = true;
204 }
205 
clear(void)206 void Timer::clear(void)
207 {
208     timer.tv_sec = 0;
209 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
210     timer.tv_nsec = 0;
211 #else
212     timer.tv_usec = 0;
213 #endif
214     updated = false;
215 }
216 
update(void)217 bool Timer::update(void)
218 {
219     bool rtn = updated;
220     updated = false;
221     return rtn;
222 }
223 
is_active(void) const224 bool Timer::is_active(void) const
225 {
226 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
227     if(!timer.tv_sec && !timer.tv_nsec)
228         return false;
229 #else
230     if(!timer.tv_sec && !timer.tv_usec)
231         return false;
232 #endif
233     return true;
234 }
235 
get(void) const236 timeout_t Timer::get(void) const
237 {
238     timeout_t diff;
239 #if _POSIX_TIMERS > 0 && POSIX_TIMERS
240     struct timespec current;
241 
242     clock_gettime(_posix_clocking, &current);
243     adj(&current);
244     if(current.tv_sec > timer.tv_sec)
245         return 0;
246     if(current.tv_sec == timer.tv_sec && current.tv_nsec > timer.tv_nsec)
247         return 0;
248     diff = (timer.tv_sec - current.tv_sec) * 1000;
249     diff += ((timer.tv_nsec - current.tv_nsec) / 1000000l);
250 #else
251     struct timeval current;
252     gettimeofday(&current, NULL);
253     adj(&current);
254     if(current.tv_sec > timer.tv_sec)
255         return 0;
256     if(current.tv_sec == timer.tv_sec && current.tv_usec > timer.tv_usec)
257         return 0;
258     diff = (timer.tv_sec - current.tv_sec) * 1000;
259     diff += ((timer.tv_usec - current.tv_usec) / 1000);
260 #endif
261     return diff;
262 }
263 
operator bool() const264 Timer::operator bool() const
265 {
266     if(get())
267         return false;
268 
269     return true;
270 }
271 
operator !() const272 bool Timer::operator!() const
273 {
274     if(get())
275         return true;
276 
277     return false;
278 }
279 
operator -(const Timer & source)280 timeout_t Timer::operator-(const Timer& source)
281 {
282     timeout_t tv = get(), dv = source.get();
283     if(!tv)
284         return 0;
285 
286     if(tv == Timer::inf)
287         return Timer::inf;
288 
289     if(dv == Timer::inf)
290         return tv;
291 
292     if(dv > tv)
293         return 0;
294 
295     return tv - dv;
296 }
297 
operator ==(const Timer & source) const298 bool Timer::operator==(const Timer& source) const
299 {
300     return get() == source.get();
301 }
302 
operator !=(const Timer & source) const303 bool Timer::operator!=(const Timer& source) const
304 {
305     return get() != source.get();
306 }
307 
operator <(const Timer & source) const308 bool Timer::operator<(const Timer& source) const
309 {
310     return get() < source.get();
311 }
312 
operator <=(const Timer & source) const313 bool Timer::operator<=(const Timer& source) const
314 {
315     return get() <= source.get();
316 }
317 
operator >(const Timer & source) const318 bool Timer::operator>(const Timer& source) const
319 {
320     return get() > source.get();
321 }
322 
operator >=(const Timer & source) const323 bool Timer::operator>=(const Timer& source) const
324 {
325     return get() >= source.get();
326 }
327 
operator =(timeout_t to)328 Timer& Timer::operator=(timeout_t to)
329 {
330 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
331     clock_gettime(_posix_clocking, &timer);
332 #else
333     gettimeofday(&timer, NULL);
334 #endif
335     operator+=(to);
336     return *this;
337 }
338 
operator +=(timeout_t to)339 Timer& Timer::operator+=(timeout_t to)
340 {
341     if(!is_active())
342         set();
343 
344     timer.tv_sec += (to / 1000);
345 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
346     timer.tv_nsec += (to % 1000l) * 1000000l;
347 #else
348     timer.tv_usec += (to % 1000l) * 1000l;
349 #endif
350     adj(&timer);
351     updated = true;
352     return *this;
353 }
354 
operator -=(timeout_t to)355 Timer& Timer::operator-=(timeout_t to)
356 {
357     if(!is_active())
358         set();
359     timer.tv_sec -= (to / 1000);
360 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
361     timer.tv_nsec -= (to % 1000l) * 1000000l;
362 #else
363     timer.tv_usec -= (to % 1000l) * 1000l;
364 #endif
365     adj(&timer);
366     return *this;
367 }
368 
369 
operator +=(time_t abs)370 Timer& Timer::operator+=(time_t abs)
371 {
372     if(!is_active())
373         set();
374     timer.tv_sec += _difftime(abs);
375     updated = true;
376     return *this;
377 }
378 
operator -=(time_t abs)379 Timer& Timer::operator-=(time_t abs)
380 {
381     if(!is_active())
382         set();
383     timer.tv_sec -= _difftime(abs);
384     return *this;
385 }
386 
operator =(time_t abs)387 Timer& Timer::operator=(time_t abs)
388 {
389 #if _POSIX_TIMERS > 0 && defined(POSIX_TIMERS)
390     clock_gettime(_posix_clocking, &timer);
391 #else
392     gettimeofday(&timer, NULL);
393 #endif
394     if(!abs)
395         return *this;
396 
397     timer.tv_sec += _difftime(abs);
398     updated = true;
399     return *this;
400 }
401 
sync(Timer & t)402 void Timer::sync(Timer &t)
403 {
404 #if _POSIX_TIMERS > 0 && defined(HAVE_CLOCK_NANOSLEEP) && defined(POSIX_TIMERS)
405     clock_nanosleep(_posix_clocking, TIMER_ABSTIME, &t.timer, NULL);
406 #elif defined(_MSWINDOWS_)
407     SleepEx(t.get(), FALSE);
408 #else
409     usleep(t.get());
410 #endif
411 }
412 
413 
timeout(void)414 timeout_t TQEvent::timeout(void)
415 {
416     timeout_t timeout = get();
417     if(is_active() && !timeout) {
418         disarm();
419         expired();
420         timeout = get();
421         Timer::update();
422     }
423     return timeout;
424 }
425 
TimerQueue()426 TimerQueue::TimerQueue() : OrderedIndex()
427 {
428 }
429 
~TimerQueue()430 TimerQueue::~TimerQueue()
431 {
432 }
433 
expire(void)434 timeout_t TimerQueue::expire(void)
435 {
436     timeout_t first = Timer::inf, next;
437     linked_pointer<TimerQueue::event> timer = begin();
438     TimerQueue::event *tp;
439 
440     while(timer) {
441         tp = *timer;
442         timer.next();
443         next = tp->timeout();
444         if(next && next < first)
445             first = next;
446     }
447     return first;
448 }
449 
operator +=(event & te)450 void TimerQueue::operator+=(event &te) { te.attach(this); }
451 
operator -=(event & te)452 void TimerQueue::operator-=(event &te)
453 {
454     if(te.list() == this)
455         te.detach();
456 }
457 
458 } // namespace ucommon
459