#ifndef __TimerQueue_h_ #define __TimerQueue_h_ #include #include "../shared/MiscSupport.h" class TimerQueue { public: class Listener { public: virtual void onTimeOut() =0; virtual ~Listener() { } }; private: struct Entry { TimeVal time; Listener *listener; bool operator <(Entry const &other) const { return (time < other.time) || ((time == other.time) && (listener < other.listener)); } bool operator ==(Entry const &other) const { return (time == other.time) && (listener == other.listener); } }; typedef std::set< Entry > ByTime; typedef std::map< Listener *, TimeVal > ByListener; ByTime _byTime; ByListener _byListener; timeval _nextTimeout; public: // If it's not in the list do nothing. Not an error. void erase(Listener *listener) { auto it = _byListener.find(listener); if (it == _byListener.end()) return; Entry entry; entry.listener = it->first; entry.time = it->second; _byTime.erase(entry); _byListener.erase(listener); }; // If it's already in the list, remove the old value. A listener cannot // be in the list more than once at a time. void add(Listener *listener, TimeVal time) { erase(listener); Entry entry; entry.listener = listener; entry.time = time; _byTime.insert(entry); _byListener[listener] = time; } // Same as the previous form of add, except for the input. The previous // function took an exact time. This function takes a relative time. void addMSFromNow(Listener *listener, int64_t ms) { TimeVal time(true); time.addMilliseconds(ms); add(listener, time); } // Return NULL to sleep forever. Or return the time until the first item // wants to wake up. This is the format used by the select() system calls. // Some of our libraries use the same format to be consistent. timeval const *nextTimeout() { if (_byTime.empty()) return NULL; TimeVal first = _byTime.begin()->time; _nextTimeout = first.waitTime(); return &_nextTimeout; } // Call every callback that is currently ready, and remove these from the // list so we don't call them again. void doAllCallbacks() { TimeVal now(true); while (true) { if (_byTime.empty()) return; Entry entry = *_byTime.begin(); if (entry.time > now) return; erase(entry.listener); entry.listener->onTimeOut(); } } TclList debugDump() { TclList result; TimeVal::Microseconds last = TimeVal(true).asMicroseconds(); for (auto it = _byTime.begin(); it != _byTime.end(); it++) { TimeVal::Microseconds current = it->time.asMicroseconds(); TclList entry; entry<listener) <<(ctimeString(it->time.tv_sec) + " " + ntoa(it->time.tv_usec / 1000000.0)) <<(current - last); result<