$search
00001 #include "rtc/rtcTime.h" 00002 #include <cmath> 00003 #include <time.h> 00004 #include <iomanip> 00005 #include <stdexcept> 00006 #include <time.h> 00007 00008 #include <boost/thread/mutex.hpp> 00009 00010 #ifndef WIN32 00011 #if POSIX_TIMERS <= 0 00012 #include <sys/time.h> 00013 #endif 00014 #else 00015 #include <sys/timeb.h> 00016 //rtc::Time rtc::Time::start_time; 00017 #endif 00018 00019 using namespace rtc; 00020 using namespace std; 00021 00022 00023 rtc::Time rtc::Time::sim_time_(0, 0); 00024 bool rtc::Time::use_system_time_(true); 00025 00026 const Duration rtc::DURATION_MAX(INT_MAX, 999999999); 00027 const Duration rtc::DURATION_MIN(INT_MIN, 0); 00028 00029 // This is declared here because it's set from the Time class but read from 00030 // the Duration class, and need not be exported to users of either. 00031 static bool g_stopped(false); 00032 00033 // I assume that this is declared here, instead of time.h, to keep users 00034 // of time.h from including boost/thread/mutex.hpp 00035 static boost::mutex g_sim_time_mutex; 00036 00037 void getWallTime(uint32_t& sec, uint32_t& nsec) 00038 { 00039 #ifndef WIN32 00040 #if POSIX_TIMERS > 0 00041 struct timespec start; 00042 clock_gettime(CLOCK_REALTIME, &start); 00043 sec = start.tv_sec; 00044 nsec = start.tv_nsec; 00045 #else 00046 struct timeval timeofday; 00047 gettimeofday(&timeofday,NULL); 00048 sec = timeofday.tv_sec; 00049 nsec = timeofday.tv_usec * 1000; 00050 #endif 00051 #else 00052 // unless I've missed something obvious, the only way to get high-precision 00053 // time on Windows is via the QueryPerformanceCounter() call. However, 00054 // this is somewhat problematic in Windows XP on some processors, especially 00055 // AMD, because the Windows implementation can freak out when the CPU clocks 00056 // down to save power. Time can jump or even go backwards. Micrtcoft has 00057 // fixed this bug for most systems now, but it can still show up if you have 00058 // not installed the latest CPU drivers (an oxymoron). They fixed all these 00059 // problems in Windows Vista, and this API is by far the most accurate that 00060 // I know of in Windows, so I'll use it here despite all these caveats 00061 static LARGE_INTEGER cpu_freq, init_cpu_time; 00062 static Time start_time; 00063 if (start_time.isZero()) 00064 { 00065 QueryPerformanceFrequency(&cpu_freq); 00066 if (cpu_freq.QuadPart == 0) 00067 { 00068 rtc_verbose("woah! this system (for whatever reason) does not support the " 00069 "high-performance timing API. ur done.\n"); 00070 abort(); 00071 } 00072 QueryPerformanceCounter(&init_cpu_time); 00073 // compute an offset from the Epoch using the lower-performance timer API 00074 FILETIME ft; 00075 GetSystemTimeAsFileTime(&ft); 00076 LARGE_INTEGER start_li; 00077 start_li.LowPart = ft.dwLowDateTime; 00078 start_li.HighPart = ft.dwHighDateTime; 00079 // why did they choose 1601 as the time zero, instead of 1970? 00080 // there were no outstanding hard rock bands in 1601. 00081 #ifdef _MSC_VER 00082 start_li.QuadPart -= 116444736000000000Ui64; 00083 #else 00084 start_li.QuadPart -= 116444736000000000ULL; 00085 #endif 00086 start_time.sec = (uint32_t)(start_li.QuadPart / 10000000); // 100-ns units. odd. 00087 start_time.nsec = (start_li.LowPart % 10000000) * 100; 00088 } 00089 LARGE_INTEGER cur_time; 00090 QueryPerformanceCounter(&cur_time); 00091 LARGE_INTEGER delta_cpu_time; 00092 delta_cpu_time.QuadPart = cur_time.QuadPart - init_cpu_time.QuadPart; 00093 // todo: how to handle cpu clock drift. not sure it's a big deal for us. 00094 // also, think about clock wraparound. seems extremely unlikey, but possible 00095 double d_delta_cpu_time = delta_cpu_time.QuadPart / (double)cpu_freq.QuadPart; 00096 Time t(start_time + Duration(d_delta_cpu_time)); 00097 00098 sec = t.sec; 00099 nsec = t.nsec; 00100 #endif 00101 } 00102 00103 Time Time::now() 00104 { 00105 if (!use_system_time_) 00106 { 00107 boost::mutex::scoped_lock lock(g_sim_time_mutex); 00108 Time t = sim_time_; 00109 return t; 00110 } 00111 00112 Time t; 00113 getWallTime(t.sec, t.nsec); 00114 00115 return t; 00116 } 00117 00118 void Time::setNow(const Time& new_now) 00119 { 00120 boost::mutex::scoped_lock lock(g_sim_time_mutex); 00121 00122 sim_time_ = new_now; 00123 use_system_time_ = false; 00124 } 00125 00126 void Time::init() 00127 { 00128 g_stopped = false; 00129 use_system_time_ = true; 00130 } 00131 00132 void Time::shutdown() 00133 { 00134 g_stopped = true; 00135 } 00136 00137 ostream &rtc::operator<<(ostream& os, const Time &rhs) 00138 { 00139 os << rhs.sec << "." << setw(9) << setfill('0') << rhs.nsec; 00140 return os; 00141 } 00142 00143 ostream &rtc::operator<<(ostream& os, const Duration& rhs) 00144 { 00145 os << rhs.sec << "." << setw(9) << setfill('0') << rhs.nsec; 00146 return os; 00147 } 00148 00149 bool Time::sleepUntil(const Time& end) 00150 { 00151 if (Time::useSystemTime()) 00152 { 00153 Duration d(end - Time::now()); 00154 if (d > Duration(0)) 00155 { 00156 return d.sleep(); 00157 } 00158 00159 return true; 00160 } 00161 else 00162 { 00163 Time start = Time::now(); 00164 struct timespec ts = {0, 1000000}; 00165 while (!g_stopped && (Time::now() < end)) 00166 { 00167 // Take a nap 00168 #ifdef _WIN32 00169 Sleep(1); 00170 #else 00171 if (nanosleep(&ts, NULL)) 00172 { 00173 return false; 00174 } 00175 #endif 00176 00177 if (Time::now() < start) 00178 { 00179 return false; 00180 } 00181 } 00182 00183 return true; 00184 } 00185 } 00186 00187 bool WallTime::sleepUntil(const WallTime& end) 00188 { 00189 WallDuration d(end - WallTime::now()); 00190 if (d > WallDuration(0)) 00191 { 00192 return d.sleep(); 00193 } 00194 00195 return true; 00196 } 00197 00198 bool wallSleep(uint32_t sec, uint32_t nsec) 00199 { 00200 #ifdef _WIN32 00201 Sleep(sec*1000+nsec); 00202 #else 00203 struct timespec ts = {sec, nsec}; 00204 struct timespec rem; 00205 while (nanosleep(&ts, &rem) && !g_stopped) 00206 { 00207 ts = rem; 00208 } 00209 #endif 00210 00211 return !g_stopped; 00212 } 00213 00214 bool Duration::sleep() const 00215 { 00216 if (Time::useSystemTime()) 00217 { 00218 return wallSleep(sec, nsec); 00219 } 00220 else 00221 { 00222 Time start = Time::now(); 00223 Time end = start + *this; 00224 while (!g_stopped && (Time::now() < end)) 00225 { 00226 wallSleep(0, 1000000); 00227 00228 if (Time::now() < start) 00229 { 00230 return false; 00231 } 00232 } 00233 00234 return true; 00235 } 00236 } 00237 00238 ostream &rtc::operator<<(ostream& os, const WallTime &rhs) 00239 { 00240 os << rhs.sec << "." << setw(9) << setfill('0') << rhs.nsec; 00241 return os; 00242 } 00243 00244 WallTime WallTime::now() 00245 { 00246 WallTime t; 00247 getWallTime(t.sec, t.nsec); 00248 00249 return t; 00250 } 00251 00252 ostream &rtc::operator<<(ostream& os, const WallDuration& rhs) 00253 { 00254 os << rhs.sec << "." << setw(9) << setfill('0') << rhs.nsec; 00255 return os; 00256 } 00257 00258 bool WallDuration::sleep() const 00259 { 00260 return wallSleep(sec, nsec); 00261 }