--- /dev/null
+/*
+This file is part of libmspframework
+Copyright © 2006 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include <signal.h>
+#include "timer.h"
+#include "utils.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Time {
+
+Timer::Timer(const Time::TimeDelta &d):
+ interval(d),
+ timeout(now()+d)
+{
+ MutexLock l(set_mutex);
+ timers.insert(this);
+ thread.nudge();
+}
+
+Timer::~Timer()
+{
+ MutexLock l(set_mutex);
+ timers.erase(this);
+ thread.nudge();
+}
+
+Timer::ThreadProxy Timer::thread;
+Mutex Timer::set_mutex;
+set<Timer *> Timer::timers;
+
+Timer::Thread::Thread():
+ done(false)
+{
+ launch();
+}
+
+/**
+Notifies the thread that a change in the timers occurred.
+*/
+void Timer::Thread::nudge()
+{
+ sem.signal();
+}
+
+/**
+Tells the thread to finish and terminate gracefully. This function will return
+after the thread has terminated.
+*/
+void Timer::Thread::finish()
+{
+ if(!done)
+ {
+ done=true;
+ sem.signal();
+ }
+
+ join();
+}
+
+void Timer::Thread::main()
+{
+ while(!done)
+ {
+ set_mutex.lock();
+ Timer *next=0;
+ TimeStamp next_ts;
+ for(set<Timer *>::iterator i=timers.begin(); i!=timers.end(); ++i)
+ {
+ const TimeStamp &ts=(*i)->get_timeout();
+ if(ts<next_ts || !next)
+ {
+ next_ts=ts;
+ next=*i;
+ }
+ }
+ set_mutex.unlock();
+
+ if(next)
+ {
+ const TimeStamp t=now();
+ if(next_ts<=t || sem.wait(next_ts-t)==1)
+ {
+ if(next->signal_timeout.emit())
+ next->timeout+=next->interval;
+ else
+ delete next;
+ }
+ }
+ else
+ pause();
+ }
+}
+
+/**
+Creates the thread if it doesn't exist, otherwise nudges it.
+*/
+void Timer::ThreadProxy::nudge()
+{
+ if(!thread)
+ thread=new Thread();
+ else
+ thread->nudge();
+}
+
+Timer::ThreadProxy::~ThreadProxy()
+{
+ if(thread)
+ {
+ thread->finish();
+ delete thread;
+ }
+}
+
+} // namespace Time
+} // namespace Msp