]> git.tdb.fi Git - libs/core.git/blob - source/time/timer.cpp
Throw out anything polling related - they will go to libmspio eventually
[libs/core.git] / source / time / timer.cpp
1 /*
2 This file is part of libmspcore     
3 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
4 Distributed under the LGPL
5 */
6 #include "timer.h"
7 #include "utils.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace Time {
13
14 Timer::Timer(const Time::TimeDelta &d):
15         interval(d),
16         timeout(now()+d)
17 {
18         MutexLock l(set_mutex);
19         timers.insert(this);
20         thread.nudge();
21 }
22
23 Timer::~Timer()
24 {
25         MutexLock l(set_mutex);
26         timers.erase(this);
27         thread.nudge();
28 }
29
30 Timer::ThreadProxy Timer::thread;
31 Mutex Timer::set_mutex;
32 set<Timer *> Timer::timers;
33
34 Timer::Thread::Thread():
35         done(false)
36 {
37         launch();
38 }
39
40 /**
41 Notifies the thread that a change in the timers occurred.
42 */
43 void Timer::Thread::nudge()
44 {
45         sem.signal();
46 }
47
48 /**
49 Tells the thread to finish and terminate gracefully.  This function will return
50 after the thread has terminated.
51 */
52 void Timer::Thread::finish()
53 {
54         if(!done)
55         {
56                 done=true;
57                 sem.signal();
58         }
59
60         join();
61 }
62
63 void Timer::Thread::main()
64 {
65         while(!done)
66         {
67                 set_mutex.lock();
68                 Timer     *next=0;
69                 TimeStamp next_ts;
70                 for(set<Timer *>::iterator i=timers.begin(); i!=timers.end(); ++i)
71                 {
72                         const TimeStamp &ts=(*i)->get_timeout();
73                         if(ts<next_ts || !next)
74                         {
75                                 next_ts=ts;
76                                 next=*i;
77                         }
78                 }
79                 set_mutex.unlock();
80
81                 if(next)
82                 {
83                         const TimeStamp t=now();
84                         if(next_ts<=t || sem.wait(next_ts-t)==1)
85                         {
86                                 if(next->signal_timeout.emit())
87                                         next->timeout+=next->interval;
88                                 else
89                                         delete next;
90                         }
91                 }
92                 else
93                         sem.wait();
94         }
95 }
96
97 /**
98 Creates the thread if it doesn't exist, otherwise nudges it.
99 */
100 void Timer::ThreadProxy::nudge()
101 {
102         if(!thread)
103                 thread=new Thread();
104         else
105                 thread->nudge();
106 }
107
108 Timer::ThreadProxy::~ThreadProxy()
109 {
110         if(thread)
111         {
112                 thread->finish();
113                 delete thread;
114         }
115 }
116
117 } // namespace Time
118 } // namespace Msp