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