00001 /* 00002 * Phusion Passenger - http://www.modrails.com/ 00003 * Copyright (c) 2010 Phusion 00004 * 00005 * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a copy 00008 * of this software and associated documentation files (the "Software"), to deal 00009 * in the Software without restriction, including without limitation the rights 00010 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00011 * copies of the Software, and to permit persons to whom the Software is 00012 * furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included in 00015 * all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00020 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00022 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00023 * THE SOFTWARE. 00024 */ 00025 #ifndef _PASSENGER_TIMER_H_ 00026 #define _PASSENGER_TIMER_H_ 00027 00028 #include <boost/thread.hpp> 00029 #include <oxt/system_calls.hpp> 00030 #include <sys/time.h> 00031 #include <cerrno> 00032 00033 namespace Passenger { 00034 00035 using namespace boost; 00036 using namespace oxt; 00037 00038 /** 00039 * A Timer which one can use to check how much time has elapsed since the 00040 * timer started. This timer support miliseconds-resolution, but the exact 00041 * resolution depends on the OS and the hardware. 00042 * 00043 * This class is thread-safe. 00044 * 00045 * @code 00046 * Timer timer; 00047 * sleep(10); 00048 * timer.elapsed(); // => about 10000 (msec) 00049 * @endcode 00050 */ 00051 class Timer { 00052 private: 00053 struct timeval startTime; 00054 mutable boost::mutex lock; 00055 public: 00056 /** 00057 * Creates a new Timer object. 00058 * 00059 * @param startNow Whether the timer should be started immediately. 00060 */ 00061 Timer(bool startNow = true) { 00062 if (startNow) { 00063 start(); 00064 } else { 00065 stop(); 00066 } 00067 } 00068 00069 /** 00070 * Start the timer. If the timer was already started, then this will 00071 * restart the timer. 00072 */ 00073 void start() { 00074 // TODO: We really use should clock_gettime() and the monotonic 00075 // clock whenever possible, instead of gettimeofday()... 00076 lock_guard<boost::mutex> l(lock); 00077 int ret; 00078 do { 00079 ret = gettimeofday(&startTime, NULL); 00080 } while (ret == -1 && errno == EINTR); 00081 } 00082 00083 /** 00084 * Stop the timer. If there's currently another thread waiting on the wait() 00085 * call, then that wait() call will block indefinitely until you call start() 00086 * and sufficient amount of time has elapsed. 00087 */ 00088 void stop() { 00089 lock_guard<boost::mutex> l(lock); 00090 startTime.tv_sec = 0; 00091 startTime.tv_usec = 0; 00092 } 00093 00094 /** 00095 * Returns the amount of time that has elapsed since the timer was last started, 00096 * in miliseconds. If the timer is currently stopped, then 0 is returned. 00097 */ 00098 unsigned long long elapsed() const { 00099 lock_guard<boost::mutex> l(lock); 00100 if (startTime.tv_sec == 0 && startTime.tv_usec == 0) { 00101 return 0; 00102 } else { 00103 struct timeval t; 00104 unsigned long long now, beginning; 00105 int ret; 00106 00107 do { 00108 ret = gettimeofday(&t, NULL); 00109 } while (ret == -1 && errno == EINTR); 00110 now = (unsigned long long) t.tv_sec * 1000 + t.tv_usec / 1000; 00111 beginning = (unsigned long long) startTime.tv_sec * 1000 + startTime.tv_usec / 1000; 00112 return now - beginning; 00113 } 00114 } 00115 00116 /** 00117 * Wait until <em>time</em> miliseconds have elapsed since the timer 00118 * was last started. 00119 */ 00120 void wait(unsigned long long time) const { 00121 while (elapsed() < time) { 00122 syscalls::usleep(25000); 00123 } 00124 } 00125 }; 00126 00127 } // namespace Passenger 00128 00129 #endif /* _PASSENGER_TIMER_H_ */