From: Piotr Caban Subject: [PATCH 4/6 v2] server: Use monotonic clock in waitable timers. Message-Id: Date: Mon, 6 Apr 2020 17:21:15 +0200 Signed-off-by: Piotr Caban --- dlls/ntdll/sync.c | 11 +++++++++-- server/protocol.def | 2 +- server/timer.c | 14 ++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 2b5b6ce44a..4a7b461627 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -1025,8 +1025,15 @@ NTSTATUS WINAPI NtQueryTimer( } SERVER_END_REQ; - /* convert from absolute into relative time */ - NtQuerySystemTime(&now); + /* convert into relative time */ + if (basic_info->RemainingTime.QuadPart > 0) + NtQuerySystemTime(&now); + else + { + RtlQueryPerformanceCounter(&now); + basic_info->RemainingTime.QuadPart = -basic_info->RemainingTime.QuadPart; + } + if (now.QuadPart > basic_info->RemainingTime.QuadPart) basic_info->RemainingTime.QuadPart = 0; else diff --git a/server/protocol.def b/server/protocol.def index e12e6fbdbf..cc23ee84db 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -487,7 +487,7 @@ typedef union enum apc_type type; /* APC_TIMER */ int __pad; client_ptr_t func; /* void (__stdcall *func)(void*, unsigned int, unsigned int); */ - timeout_t time; /* absolute time of expiration */ + abstime_t time; /* time of expiration */ client_ptr_t arg; /* user argument */ } timer; struct diff --git a/server/timer.c b/server/timer.c index 9cca85569f..c1269e0ff0 100644 --- a/server/timer.c +++ b/server/timer.c @@ -43,7 +43,7 @@ struct timer int manual; /* manual reset */ int signaled; /* current signaled state */ unsigned int period; /* timer period in ms */ - timeout_t when; /* next expiration */ + abstime_t when; /* next expiration */ struct timeout_user *timeout; /* timeout user */ struct thread *thread; /* thread that set the APC function */ client_ptr_t callback; /* callback APC function */ @@ -132,8 +132,9 @@ static void timer_callback( void *private ) if (timer->period) /* schedule the next expiration */ { - timer->when += (timeout_t)timer->period * 10000; - timer->timeout = add_timeout_user( timer->when, timer_callback, timer ); + if (timer->when > 0) timer->when = -monotonic_time; + timer->when -= (abstime_t)timer->period * 10000; + timer->timeout = add_timeout_user( abstime_to_timeout(timer->when), timer_callback, timer ); } else timer->timeout = NULL; @@ -171,21 +172,22 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period period = 0; /* period doesn't make any sense for a manual timer */ timer->signaled = 0; } - timer->when = (expire <= 0) ? current_time - expire : max( expire, current_time ); + timer->when = (expire <= 0) ? expire - monotonic_time : max( expire, current_time ); timer->period = period; timer->callback = callback; timer->arg = arg; if (callback) timer->thread = (struct thread *)grab_object( current ); - timer->timeout = add_timeout_user( timer->when, timer_callback, timer ); + timer->timeout = add_timeout_user( expire, timer_callback, timer ); return signaled; } static void timer_dump( struct object *obj, int verbose ) { struct timer *timer = (struct timer *)obj; + timeout_t timeout = abstime_to_timeout( timer->when ); assert( obj->ops == &timer_ops ); fprintf( stderr, "Timer manual=%d when=%s period=%u\n", - timer->manual, get_timeout_str(timer->when), timer->period ); + timer->manual, get_timeout_str(timeout), timer->period ); } static struct object_type *timer_get_type( struct object *obj )