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