]> git.tdb.fi Git - libs/core.git/blob - source/time/timer.cpp
Merge branch 'fs-master'
[libs/core.git] / source / time / timer.cpp
1 #include <algorithm>
2 #include "timer.h"
3 #include "utils.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace Time {
9
10 Timer::~Timer()
11 {
12         for(vector<SlotProxy>::iterator i=slots.begin(); i!=slots.end(); ++i)
13                 delete i->slot;
14 }
15
16 Timer::Slot &Timer::add(const TimeDelta &td)
17 {
18         Slot *s = new Slot(td);
19         mutex.lock();
20         slots.push_back(s);
21         push_heap(slots.begin(), slots.end());
22         mutex.unlock();
23         sem.signal();
24         return *s;
25 }
26
27 Timer::Slot &Timer::add(const TimeStamp &ts)
28 {
29         Slot *s = new Slot(ts);
30         {
31                 MutexLock l(mutex);
32                 slots.push_back(s);
33                 push_heap(slots.begin(), slots.end());
34         }
35         sem.signal();
36         return *s;
37 }
38
39 void Timer::cancel(Slot &slot)
40 {
41         MutexLock l(mutex);
42         for(vector<SlotProxy>::iterator i=slots.begin(); i!=slots.end(); ++i)
43                 if(i->slot==&slot)
44                 {
45                         delete i->slot;
46                         slots.erase(i);
47                         make_heap(slots.begin(), slots.end());
48                         return;
49                 }
50 }
51
52 void Timer::tick(bool block)
53 {
54         Slot *next = 0;
55         {
56                 MutexLock l(mutex);
57                 while(1)
58                 {
59                         if(slots.empty())
60                         {
61                                 if(block)
62                                         sem.wait();
63                                 else
64                                         return;
65                         }
66
67                         next = slots.begin()->slot;
68                         const TimeStamp &stamp = next->get_timeout();
69                         const TimeStamp t = now();
70                         if(stamp<=t)
71                                 break;
72                         else if(block)
73                                 sem.wait(stamp-t);
74                         else
75                                 return;
76                 }
77
78                 pop_heap(slots.begin(), slots.end());
79                 slots.pop_back();
80         }
81
82         try
83         {
84                 if(next->signal_timeout.emit() && next->increment())
85                 {
86                         MutexLock l(mutex);
87                         slots.push_back(next);
88                         push_heap(slots.begin(), slots.end());
89                 }
90                 else
91                         delete next;
92         }
93         catch(...)
94         {
95                 delete next;
96                 throw;
97         }
98 }
99
100 TimeStamp Timer::get_next_timeout() const
101 {
102         if(slots.empty())
103                 return TimeStamp();
104         return slots.begin()->slot->get_timeout();
105 }
106
107
108 Timer::Slot::Slot(const TimeDelta &td):
109         interval(td),
110         timeout(now()+interval)
111 { }
112
113 Timer::Slot::Slot(const TimeStamp &ts):
114         timeout(ts)
115 { }
116
117 bool Timer::Slot::increment()
118 {
119         if(!interval)
120                 return false;
121         timeout += interval;
122         return true;
123 }
124
125
126 Timer::SlotProxy::SlotProxy(Slot *s):
127         slot(s)
128 { }
129
130 bool Timer::SlotProxy::operator<(const SlotProxy &sp) const
131 {
132         return slot->get_timeout()>sp.slot->get_timeout();
133 }
134
135 } // namespace Time
136 } // namespace Msp