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