]> git.tdb.fi Git - libs/core.git/blobdiff - source/time/timer.cpp
Rename to libmspcore
[libs/core.git] / source / time / timer.cpp
diff --git a/source/time/timer.cpp b/source/time/timer.cpp
new file mode 100644 (file)
index 0000000..641d55f
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+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