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