6666#include " LevelManager.hh"
6767#include " SdfGenerator.hh"
6868
69+ #ifdef _WIN32
70+ #ifndef NOMINMAX
71+ #define NOMINMAX
72+ #endif
73+ #ifndef WIN32_LEAN_AND_MEAN
74+ #define WIN32_LEAN_AND_MEAN
75+ #endif
76+ #include < windows.h>
77+ #endif
78+
6979using namespace gz ;
7080using namespace sim ;
7181
@@ -103,6 +113,34 @@ struct MaybeGilScopedRelease
103113
104114}
105115
116+ #ifdef _WIN32
117+ namespace gz
118+ {
119+ namespace sim
120+ {
121+ inline namespace GZ_SIM_VERSION_NAMESPACE {
122+ // Utility class to store the windows HANDLE variable and close
123+ // the handle using RAII. This class also hides the HANDLE
124+ // type from the global header files.
125+ class SimulationRunnerWinHandleStorage
126+ {
127+ private: HANDLE handleStorage{NULL };
128+
129+ public: HANDLE handle () { return handleStorage; }
130+
131+ public: SimulationRunnerWinHandleStorage(HANDLE h) : handleStorage(h) {}
132+
133+ public: ~SimulationRunnerWinHandleStorage () {
134+ if (handleStorage != NULL )
135+ {
136+ CloseHandle (handleStorage);
137+ }
138+ }
139+ };
140+ }
141+ }
142+ }
143+ #endif
106144
107145// ////////////////////////////////////////////////
108146SimulationRunner::SimulationRunner (const sdf::World &_world,
@@ -182,6 +220,16 @@ SimulationRunner::SimulationRunner(const sdf::World &_world,
182220 );
183221 this ->currentInfo .simTime = this ->simTimeEpoch ;
184222
223+ #ifdef _WIN32
224+ HANDLE winPrecisionTimerHandle = CreateWaitableTimerExA (NULL , NULL ,
225+ CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
226+ if (winPrecisionTimerHandle != NULL )
227+ {
228+ winPrecisionTimer = std::make_unique<SimulationRunnerWinHandleStorage>(
229+ winPrecisionTimerHandle);
230+ }
231+ #endif
232+
185233 // World control
186234 transport::NodeOptions opts;
187235 std::string ns{" /world/" + this ->worldName };
@@ -913,14 +961,45 @@ bool SimulationRunner::Run(const uint64_t _iterations)
913961 // larger than the typical OS + CPU C-state latency.
914962 constexpr auto kSpinThreshold = 200us;
915963
964+ auto now = std::chrono::steady_clock::now ();
965+
916966 // If the scheduled update time is in the future...
917- if (nextUpdateTime > std::chrono::steady_clock:: now() )
967+ if (nextUpdateTime > now)
918968 {
919969 // ...sleep until we are close to the target time.
920970 auto sleepTarget = nextUpdateTime - kSpinThreshold ;
921- if (sleepTarget > std::chrono::steady_clock:: now() )
971+ if (sleepTarget > now)
922972 {
973+ #ifndef _WIN32
923974 std::this_thread::sleep_until (sleepTarget);
975+ #else
976+ if (winPrecisionTimer)
977+ {
978+ auto sleepTargetDuration =
979+ std::chrono::duration_cast<std::chrono::microseconds>(
980+ sleepTarget - now);
981+ LARGE_INTEGER due_time;
982+ memset (&due_time, 0 , sizeof (due_time));
983+ // Positive durations are absolute, while negative durations
984+ // are relative in 10 us intervals.
985+ // The absolute time uses the non-precision system clock so we
986+ // need to use relative time.
987+ due_time.QuadPart = -sleepTargetDuration.count () * 10 ;
988+ if (SetWaitableTimer (winPrecisionTimer->handle (), &due_time, 0 ,
989+ NULL , NULL , FALSE ) != TRUE )
990+ {
991+ gzerr << " Could not SetWaitableTimer" << std::endl;
992+ }
993+ else
994+ {
995+ WaitForSingleObject (winPrecisionTimer->handle (), INFINITE);
996+ }
997+ }
998+ else
999+ {
1000+ std::this_thread::sleep_until (sleepTarget);
1001+ }
1002+ #endif
9241003 }
9251004
9261005 // ...then busy-wait for the final moments for precision.
@@ -931,7 +1010,7 @@ bool SimulationRunner::Run(const uint64_t _iterations)
9311010 }
9321011
9331012 // Schedule the next update time.
934- auto now = std::chrono::steady_clock::now ();
1013+ now = std::chrono::steady_clock::now ();
9351014 nextUpdateTime += this ->updatePeriod ;
9361015 if (nextUpdateTime < now)
9371016 {
0 commit comments