/*MT* MediaTomb - http://www.mediatomb.cc/ timer.h - this file is part of MediaTomb. Copyright (C) 2005 Gena Batyan , Sergey 'Jin' Bostandzhyan Copyright (C) 2006-2007 Gena Batyan , Sergey 'Jin' Bostandzhyan , Leonhard Wimmer MediaTomb is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. MediaTomb is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License version 2 along with MediaTomb; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. $Id: timer.h 1174 2007-02-25 17:19:44Z lww $ */ /// \file timer.h #ifndef __TIMER_H__ #define __TIMER_H__ #include "zmm/zmm.h" #include "zmmf/zmmf.h" #include "singleton.h" #include "sync.h" #include "tools.h" //#define AS_TIMER_SUBSCRIBER(klass, object) RefCast(Ref > >(object), TimerSubscriber) #define AS_TIMER_SUBSCRIBER_SINGLETON(obj) zmm::Ref >((TimerSubscriberSingleton*)obj) #define AS_TIMER_SUBSCRIBER_SINGLETON_FROM_REF(obj) RefCast(obj, TimerSubscriberSingleton) /// \todo Leo: please add doxygen documentation! class TimerSubscriber { public: virtual ~TimerSubscriber() { log_debug("TS destroyed\n"); } virtual void timerNotify(int id) = 0; // void addTimerSubscriber(unsigned int notifyInterval, int id = 0, bool once = false); // void removeTimerSubscriber(int id = 0, bool dontFail = false); }; template class TimerSubscriberSingleton : public TimerSubscriber, public Singleton { }; class TimerSubscriberObject : public TimerSubscriber, public zmm::Object { }; class Timer : public Singleton { public: Timer(); virtual ~Timer() { log_debug("Timer destroyed!\n"); } //static zmm::Ref getInstance(); virtual void shutdown(); template void addTimerSubscriber(zmm::Ref timerSubscriber, unsigned int notifyInterval, int id = 0, bool once = false) { log_debug("adding subscriber...\n"); if (notifyInterval <= 0) throw zmm::Exception(_("tried to add timer with illegal notifyInterval: ") + notifyInterval); AUTOLOCK(mutex); //timerSubscriber->timerNotify(id); zmm::Ref > element(new TimerSubscriberElement(timerSubscriber, notifyInterval, id, once)); for(int i = 0; i < getAppropriateSubscribers()->size(); i++) { if (getAppropriateSubscribers()->get(i)->equals(element)) { throw zmm::Exception(_("tried to add same timer twice")); } } getAppropriateSubscribers()->append(element); signal(); } template void removeTimerSubscriber(zmm::Ref timerSubscriber, int id = 0, bool dontFail = false) { log_debug("removing subscriber...\n"); AUTOLOCK(mutex); zmm::Ref > element(new TimerSubscriberElement(timerSubscriber, 0, id)); bool removed = false; for(int i = 0; i < getAppropriateSubscribers()->size(); i++) { if (getAppropriateSubscribers()->get(i)->equals(element)) { getAppropriateSubscribers()->removeUnordered(i); removed = true; break; } } if (! removed && ! dontFail) { throw zmm::Exception(_("tried to remove nonexistent timer")); } signal(); } void triggerWait(); inline void signal() { cond->signal(); } protected: template class TimerSubscriberElement : public zmm::Object { public: TimerSubscriberElement(zmm::Ref subscriber, unsigned int notifyInterval, int id, bool once = false) { this->subscriber = subscriber; this->notifyInterval = notifyInterval; this->id = id; this->once = once; notified(); } inline unsigned int getNotifyInterval() { return notifyInterval; } inline zmm::Ref getSubscriber() { return subscriber; } inline void notified() { getTimespecAfterMillis(notifyInterval * 1000, &nextNotify); } inline struct timespec *getNextNotify() { return &nextNotify; } inline int getID() { return id; } bool equals(zmm::Ref other) { return (subscriber == other->subscriber && id == other->id); } bool isOnce() { return once; } protected: zmm::Ref subscriber; unsigned int notifyInterval; int id; struct timespec nextNotify; bool once; }; //static zmm::Ref instance; //static zmm::Ref mutex; zmm::Ref cond; zmm::Ref > > > subscribersSingleton; zmm::Ref > > subscribersObject; template zmm::Ref > > getAppropriateSubscribers(); template void notify() { struct timespec now; getTimespecNow(&now); log_debug("notifying. - %d subscribers\n", getAppropriateSubscribers()->size()); for(int i = 0; i < getAppropriateSubscribers()->size(); i++) { zmm::Ref > element = getAppropriateSubscribers()->get(i); if (compareTimespecs(element->getNextNotify(), &now) >= 0) { log_debug("notifying %d\n", i); zmm::Ref subscriber = element->getSubscriber(); try { subscriber->timerNotify(element->getID()); } catch (zmm::Exception e) { log_debug("timer caught exception!\n"); e.printStackTrace(); } element->notified(); if (element->isOnce()) { getAppropriateSubscribers()->removeUnordered(i--); } } } } struct timespec *getNextNotifyTime(); }; #endif // __TIMER_H__