#pragma once #include #include #include #include #include #include #include /* Keeps current time accurate up to 1/10 second */ class TTimeKeeper { public: static TInstant GetNow(void) { return TInstant::MicroSeconds(GetTime()); } static time_t GetTime(void) { return Singleton()->CurrentTime.tv_sec; } static const struct timeval& GetTimeval(void) { return Singleton()->CurrentTime; } TTimeKeeper() : Thread(&TTimeKeeper::Worker, this) { ConstTime = !!GetEnv("TEST_TIME"); if (ConstTime) { try { CurrentTime.tv_sec = FromString(GetEnv("TEST_TIME")); } catch (TFromStringException exc) { ConstTime = false; } } if (!ConstTime) { gettimeofday(&CurrentTime, nullptr); Thread.Start(); } } ~TTimeKeeper() { if (!ConstTime) { Exit.Signal(); Thread.Join(); } } private: static const ui32 UpdateInterval = 100000; struct timeval CurrentTime; bool ConstTime; TSystemEvent Exit; TThread Thread; static void* Worker(void* arg) { TTimeKeeper* owner = static_cast(arg); do { /* Race condition may occur here but locking looks too expensive */ gettimeofday(&owner->CurrentTime, nullptr); } while (!owner->Exit.WaitT(TDuration::MicroSeconds(UpdateInterval))); return nullptr; } };