00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #ifndef __TIMER_H__
00033 #define __TIMER_H__
00034
00035 #include "zmm/zmm.h"
00036 #include "zmmf/zmmf.h"
00037 #include "singleton.h"
00038 #include "sync.h"
00039 #include "tools.h"
00040
00041
00042 #define AS_TIMER_SUBSCRIBER_SINGLETON(obj) zmm::Ref<TimerSubscriberSingleton<Object> >((TimerSubscriberSingleton<Object>*)obj)
00043 #define AS_TIMER_SUBSCRIBER_SINGLETON_FROM_REF(obj) RefCast(obj, TimerSubscriberSingleton<Object>)
00044
00046
00047 class TimerSubscriber
00048 {
00049 public:
00050 virtual ~TimerSubscriber() { log_debug("TS destroyed\n"); }
00051 virtual void timerNotify(zmm::Ref<zmm::Object> parameter) = 0;
00052
00053
00054 };
00055
00056
00057 template <class T>
00058 class TimerSubscriberSingleton : public TimerSubscriber, public Singleton<T>
00059 {
00060 };
00061
00062 class TimerSubscriberObject : public TimerSubscriber, public zmm::Object
00063 {
00064 };
00065
00066
00067 class Timer : public Singleton<Timer>
00068 {
00069 public:
00070 Timer();
00071 virtual ~Timer() { log_debug("Timer destroyed!\n"); }
00072
00073
00074 virtual void shutdown();
00075
00076 template <class T>
00077 void addTimerSubscriber(zmm::Ref<T> timerSubscriber, unsigned int notifyInterval, zmm::Ref<zmm::Object> parameter = nil, bool once = false)
00078 {
00079 log_debug("adding subscriber...\n");
00080 if (notifyInterval <= 0)
00081 throw zmm::Exception(_("tried to add timer with illegal notifyInterval: ") + notifyInterval);
00082 AUTOLOCK(mutex);
00083
00084 zmm::Ref<TimerSubscriberElement<T> > element(new TimerSubscriberElement<T>(timerSubscriber, notifyInterval, parameter, once));
00085 for(int i = 0; i < getAppropriateSubscribers<T>()->size(); i++)
00086 {
00087 if (getAppropriateSubscribers<T>()->get(i)->equals(element))
00088 {
00089 throw zmm::Exception(_("tried to add same timer twice"));
00090 }
00091 }
00092 getAppropriateSubscribers<T>()->append(element);
00093 signal();
00094 }
00095
00096 template <class T>
00097 void removeTimerSubscriber(zmm::Ref<T> timerSubscriber, zmm::Ref<zmm::Object> parameter = nil, bool dontFail = false)
00098 {
00099 log_debug("removing subscriber...\n");
00100 AUTOLOCK(mutex);
00101 zmm::Ref<TimerSubscriberElement<T> > element(new TimerSubscriberElement<T>(timerSubscriber, 0, parameter));
00102 bool removed = false;
00103 for(int i = 0; i < getAppropriateSubscribers<T>()->size(); i++)
00104 {
00105 if (getAppropriateSubscribers<T>()->get(i)->equals(element))
00106 {
00107 getAppropriateSubscribers<T>()->removeUnordered(i);
00108 removed = true;
00109 break;
00110 }
00111 }
00112 if (! removed && ! dontFail)
00113 {
00114 throw zmm::Exception(_("tried to remove nonexistent timer"));
00115 }
00116 signal();
00117 }
00118
00119 void triggerWait();
00120
00121 inline void signal() { cond->signal(); }
00122
00123 protected:
00124 template <class T>
00125 class TimerSubscriberElement : public zmm::Object
00126 {
00127 public:
00128 TimerSubscriberElement(zmm::Ref<T> subscriber, unsigned int notifyInterval, zmm::Ref<zmm::Object> parameter, bool once = false)
00129 {
00130 this->subscriber = subscriber;
00131 this->notifyInterval = notifyInterval;
00132 this->parameter = parameter;
00133 this->once = once;
00134 notified();
00135 }
00136 inline unsigned int getNotifyInterval() { return notifyInterval; }
00137 inline zmm::Ref<T> getSubscriber() { return subscriber; }
00138 inline void notified() { getTimespecAfterMillis(notifyInterval * 1000, &nextNotify); }
00139 inline struct timespec *getNextNotify() { return &nextNotify; }
00140 inline zmm::Ref<zmm::Object> getParameter() { return parameter; }
00141 bool equals(zmm::Ref<TimerSubscriberElement> other) { return (subscriber == other->subscriber && parameter == other->parameter); }
00142 bool isOnce() { return once; }
00143 protected:
00144 zmm::Ref<T> subscriber;
00145 unsigned int notifyInterval;
00146 zmm::Ref<zmm::Object> parameter;
00147 struct timespec nextNotify;
00148 bool once;
00149 };
00150
00151
00152
00153
00154 zmm::Ref<Cond> cond;
00155
00156 zmm::Ref<zmm::Array<TimerSubscriberElement<TimerSubscriberSingleton<Object> > > > subscribersSingleton;
00157 zmm::Ref<zmm::Array<TimerSubscriberElement<TimerSubscriberObject> > > subscribersObject;
00158
00159 template <class T>
00160 zmm::Ref<zmm::Array<TimerSubscriberElement<T> > > getAppropriateSubscribers();
00161
00162 template <class T>
00163 void notify()
00164 {
00165 struct timespec now;
00166 getTimespecNow(&now);
00167 log_debug("notifying. - %d subscribers\n", getAppropriateSubscribers<T>()->size());
00168 for(int i = 0; i < getAppropriateSubscribers<T>()->size(); i++)
00169 {
00170 zmm::Ref<TimerSubscriberElement<T> > element = getAppropriateSubscribers<T>()->get(i);
00171 if (compareTimespecs(element->getNextNotify(), &now) >= 0)
00172 {
00173 log_debug("notifying %d\n", i);
00174 zmm::Ref<T> subscriber = element->getSubscriber();
00175 try
00176 {
00177 subscriber->timerNotify(element->getParameter());
00178 }
00179 catch (zmm::Exception e)
00180 {
00181 log_debug("timer caught exception!\n");
00182 e.printStackTrace();
00183 }
00184 element->notified();
00185 if (element->isOnce())
00186 {
00187 getAppropriateSubscribers<T>()->removeUnordered(i--);
00188 }
00189 }
00190 }
00191 }
00192
00193 struct timespec *getNextNotifyTime();
00194 };
00195
00196 #endif // __TIMER_H__