33#include < mutex>
44#include < node.h>
55
6+ // Platform-specific includes for time functions
7+ #ifdef _WIN32
8+ #include < realtimeapiset.h>
9+ #include < windows.h>
10+ #elif defined(__APPLE__)
11+ #include < time.h>
12+ #elif defined(__linux__)
13+ #include < time.h>
14+ #endif
15+
616using namespace v8 ;
717using namespace node ;
818using namespace std ::chrono;
@@ -243,6 +253,31 @@ void RegisterThread(const FunctionCallbackInfo<Value> &args) {
243253 }
244254}
245255
256+ // Cross-platform monotonic time function. Provides a monotonic clock that only
257+ // increases and does not tick when the system is suspended.
258+ steady_clock::time_point GetUnbiasedMonotonicTime () {
259+ #ifdef _WIN32
260+ // Windows: QueryUnbiasedInterruptTimePrecise returns time in 100-nanosecond
261+ // units
262+ ULONGLONG interrupt_time;
263+ QueryUnbiasedInterruptTimePrecise (&interrupt_time);
264+ // Convert from 100-nanosecond units to nanoseconds
265+ uint64_t time_ns = interrupt_time * 100 ;
266+ return steady_clock::time_point (nanoseconds (time_ns));
267+ #elif defined(__APPLE__)
268+ uint64_t time_ns = clock_gettime_nsec_np (CLOCK_UPTIME_RAW);
269+ return steady_clock::time_point (nanoseconds (time_ns));
270+ #elif defined(__linux__)
271+ struct timespec ts;
272+ clock_gettime (CLOCK_MONOTONIC, &ts);
273+ return steady_clock::time_point (seconds (ts.tv_sec ) + nanoseconds (ts.tv_nsec ));
274+ #else
275+ // Fallback for other platforms using steady_clock. Note: this will be
276+ // monotonic but is not gaurenteed to ignore time spent while suspended.
277+ return steady_clock::now ();
278+ #endif
279+ }
280+
246281// Function to track a thread and set its state
247282void ThreadPoll (const FunctionCallbackInfo<Value> &args) {
248283 auto isolate = args.GetIsolate ();
@@ -275,8 +310,8 @@ void ThreadPoll(const FunctionCallbackInfo<Value> &args) {
275310 if (disable_last_seen) {
276311 thread_info.last_seen = milliseconds::zero ();
277312 } else {
278- thread_info.last_seen =
279- duration_cast<milliseconds>( system_clock::now ().time_since_epoch ());
313+ thread_info.last_seen = duration_cast<milliseconds>(
314+ GetUnbiasedMonotonicTime ().time_since_epoch ());
280315 }
281316 }
282317 }
@@ -286,8 +321,8 @@ void ThreadPoll(const FunctionCallbackInfo<Value> &args) {
286321void GetThreadsLastSeen (const FunctionCallbackInfo<Value> &args) {
287322 Isolate *isolate = args.GetIsolate ();
288323 Local<Object> result = Object::New (isolate);
289- milliseconds now =
290- duration_cast<milliseconds>( system_clock::now ().time_since_epoch ());
324+ milliseconds now = duration_cast<milliseconds>(
325+ GetUnbiasedMonotonicTime ().time_since_epoch ());
291326 {
292327 std::lock_guard<std::mutex> lock (threads_mutex);
293328 for (const auto &[thread_isolate, info] : threads) {
0 commit comments