rtcTime.cpp
Go to the documentation of this file.
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 }


rtc
Author(s): Benjamin Pitzer
autogenerated on Mon Oct 6 2014 10:07:35