#include "osdrvutil.hpp" #if defined(__linux__) #include #elif defined(_WIN32) #include #include #else #error "Only support __linux__ or _WIN32" #endif #include #include #include #include // strerror has to be the most overcomplicated function imaginable. The simple // version, 'strerror', is not thread-safe, and the improved versions are all // incompatible from OS to OS. Even different versions of linux aren't // compatible. A lot of conditional compilation is needed. #if defined(__linux__) inline static void strerror_helper(int status, int errnum, char errbuf[256]) { if (status != 0) { snprintf(errbuf, 256, "unknown errno %d", errnum); } } inline static void strerror_helper(const char *result, int errnum, char errbuf[256]) { if (result != errbuf) { snprintf(errbuf, 256, "%s", result); } } static void strerror_safe(int errnum, char errbuf[256]) { auto rval = strerror_r(errnum, errbuf, 256); strerror_helper(rval, errnum, errbuf); } #elif defined(_WIN32) static void strerror_safe(int errnum, char errbuf[256]) { int status = strerror_s(errbuf, 256, errnum); if (status != 0) { snprintf(errbuf, 256, "unknown errno %d", errnum); } } #endif // The monotonic clock is required to start at zero at initialization time, // advance steadily, and never go backwards. It is okay, however, if it is a // little inaccurate, or if it drifts a little over time. #if defined(__linux__) class MonoClock { private: struct timespec base_; public: MonoClock() { int status = clock_gettime(CLOCK_MONOTONIC, &base_); assert(status == 0); } double get() { struct timespec t; int status = clock_gettime(CLOCK_MONOTONIC, &t); assert(status == 0); double tv_sec = t.tv_sec - base_.tv_sec; double tv_nsec = t.tv_nsec - base_.tv_nsec; return tv_sec + (tv_nsec * 1.0E-9); } }; #elif defined(_WIN32) class MonoClock { public: double freq_; LONGLONG base_; inline LONGLONG qpc() { LARGE_INTEGER x; BOOL status = QueryPerformanceCounter(&x); assert(status != 0); return x.QuadPart; } MonoClock() { LARGE_INTEGER x; BOOL status = QueryPerformanceFrequency(&x); assert(status != 0); freq_ = 1.0 / double(x.QuadPart); base_ = qpc(); } double get() { return (qpc() - base_) * freq_; } }; #endif namespace drvutil { static MonoClock monoclock; double get_monotonic_clock() { return monoclock.get(); } std::string strerror_str(int errnum) { char buf[256]; strerror_safe(errnum, buf); return buf; } } // namespace drvutil