LogCabin
|
00001 /* Copyright (c) 2011-2014 Stanford University 00002 * Copyright (c) 2015 Diego Ongaro 00003 * 00004 * Permission to use, copy, modify, and distribute this software for any 00005 * purpose with or without fee is hereby granted, provided that the above 00006 * copyright notice and this permission notice appear in all copies. 00007 * 00008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 */ 00016 00017 #ifndef LOGCABIN_EVENT_TIMER_H 00018 #define LOGCABIN_EVENT_TIMER_H 00019 00020 #include "Core/Time.h" 00021 #include "Event/File.h" 00022 00023 namespace LogCabin { 00024 namespace Event { 00025 00026 // forward declaration 00027 class Loop; 00028 00029 /** 00030 * A Timer is called by the Event::Loop when time has elapsed. 00031 * The client should inherit from this and implement the trigger method for 00032 * when the timer expires. 00033 * 00034 * Timers can be added and scheduled from any thread, but they will always fire 00035 * on the thread running the Event::Loop. 00036 */ 00037 class Timer : private File { 00038 public: 00039 00040 /** 00041 * Registers a Timer handler to be monitored by the Event::Loop. Once this 00042 * is constructed, the Event::Loop will call the Timer's event handler 00043 * appropriately. 00044 * 00045 * This object must be destroyed or disableForever() called BEFORE the 00046 * Timer object can be destroyed safely. 00047 */ 00048 class Monitor : private File::Monitor { 00049 public: 00050 /// See File::Monitor::Monitor. 00051 Monitor(Event::Loop& eventLoop, Timer& timer); 00052 /// See File::Monitor::~Monitor. 00053 ~Monitor(); 00054 /// See File::Monitor::disableForever. 00055 using File::Monitor::disableForever; 00056 }; 00057 00058 /** 00059 * Construct a timer but do not schedule it to trigger. 00060 * After this is constructed, you'll want to create an 00061 * Event::Timer::Monitor for it and also schedule() it, in either order. 00062 */ 00063 Timer(); 00064 00065 /** 00066 * Destructor. 00067 */ 00068 virtual ~Timer(); 00069 00070 /** 00071 * This method is overridden by a subclass and invoked when the timer 00072 * expires. This method will be invoked by the main event loop on whatever 00073 * thread is running the Event::Loop. 00074 */ 00075 virtual void handleTimerEvent() = 0; 00076 00077 /** 00078 * Start the timer. 00079 * \param nanoseconds 00080 * The timer will trigger once this number of nanoseconds have elapsed. 00081 * If the timer was already scheduled, the old time is forgotten. 00082 */ 00083 void schedule(uint64_t nanoseconds); 00084 00085 /** 00086 * Start the timer for an absolute point in time. If the timeout is in the 00087 * past, the timer will trigger immediately once the event loop runs. 00088 * \param timeout 00089 * The timer will trigger once this timeout has past. 00090 * If the timer was already scheduled, the old time is forgotten. 00091 */ 00092 void scheduleAbsolute(Core::Time::SteadyClock::time_point timeout); 00093 00094 /** 00095 * Stop the timer from calling handleTimerEvent(). 00096 * This will cancel the current timer, if any, so that handleTimerEvent() 00097 * is not called until the next time it is scheduled. 00098 * 00099 * This method behaves in a friendly way when called concurrently with the 00100 * timer firing: 00101 * - If this method is called from another thread and handleTimerEvent() is 00102 * running concurrently on the event loop thread, deschedule() will wait 00103 * for handleTimerEvent() to complete before returning. 00104 * - If this method is called from the event loop thread and 00105 * handleTimerEvent() is currently being fired, then deschedule() can't 00106 * wait and returns immediately. 00107 */ 00108 void deschedule(); 00109 00110 private: 00111 /** 00112 * Returns true if the timer has been scheduled and has not yet fired. 00113 * \warning 00114 * This is prone to races; it's primarily useful for unit tests. 00115 * It also improperly returns false after scheduleAbsolute() is called 00116 * with a time that has expired. It's marked as private so it can't be 00117 * accessed from normal (non-test) code. 00118 * TODO(ongaro): remove entirely or add additional state to this 00119 * class to make this work correctly? 00120 * \return 00121 * True if the timer has been scheduled and will eventually call 00122 * handleTimerEvent(). 00123 * False if the timer is currently running handleTimerEvent() or if it 00124 * is not scheduled to call handleTimerEvent() in the future. 00125 */ 00126 bool isScheduled() const; 00127 00128 /** 00129 * Generic event handler for files. Calls handleTimerEvent(). 00130 */ 00131 void handleFileEvent(uint32_t events); 00132 00133 // Timer is not copyable. 00134 Timer(const Timer&) = delete; 00135 Timer& operator=(const Timer&) = delete; 00136 }; 00137 00138 } // namespace LogCabin::Event 00139 } // namespace LogCabin 00140 00141 #endif /* LOGCABIN_EVENT_TIMER_H */