[PATCH 1/5] ntdll: Implmement NtQueryTimerResolution and NtSetTimerResolution

Arkadiusz Hiler ahiler at codeweavers.com
Mon Aug 17 12:46:50 CDT 2020


This change implements querying, setting and resetting timer resolution. The
set resolution has no effect on any of the wait calls yet - they are still
using select() or server_select() with the raw values.

Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
---
 dlls/ntdll/tests/time.c | 32 +++++++++++++++++++++++
 dlls/ntdll/unix/sync.c  | 57 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/dlls/ntdll/tests/time.c b/dlls/ntdll/tests/time.c
index a00d507e4e..6c800c8c4e 100644
--- a/dlls/ntdll/tests/time.c
+++ b/dlls/ntdll/tests/time.c
@@ -35,6 +35,9 @@ static NTSTATUS (WINAPI *pRtlQueryTimeZoneInformation)( RTL_TIME_ZONE_INFORMATIO
 static NTSTATUS (WINAPI *pRtlQueryDynamicTimeZoneInformation)( RTL_DYNAMIC_TIME_ZONE_INFORMATION *);
 static BOOL     (WINAPI *pRtlQueryUnbiasedInterruptTime)( ULONGLONG *time );
 
+static NTSTATUS (WINAPI *pNtQueryTimerResolution)( ULONG *min_res, ULONG *max_res, ULONG *current_res );
+static NTSTATUS (WINAPI *pNtSetTimerResolution)( ULONG res, BOOLEAN set, ULONG *current_res );
+
 static const int MonthLengths[2][12] =
 {
 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
@@ -264,6 +267,32 @@ static void test_user_shared_data_time(void)
     todo_wine ok(changed >= 90, "tick count isn't updated after sleeping one millisecond (%d%% correct)\n", changed);
 }
 
+static void test_timer_resolution(void)
+{
+    ULONG min, max, cur, def, cur2;
+
+    ok(pNtQueryTimerResolution(NULL, NULL, NULL) == STATUS_ACCESS_VIOLATION, "getting resolution is fine with writign to a NULL pointer\n");
+    ok(pNtQueryTimerResolution(&min, &max, &def) == STATUS_SUCCESS, "failed to get resolution\n");
+    ok(def == min, "the default timer resolution is not set to the minimum\n");
+
+    ok(pNtSetTimerResolution(0, TRUE, NULL) == STATUS_ACCESS_VIOLATION, "setting resolution is fine with writing to a NULL pointer\n");
+    ok(pNtSetTimerResolution(0, FALSE, &cur) == STATUS_TIMER_RESOLUTION_NOT_SET, "we have managed to unset resolution without setting one\n");
+
+    ok(pNtSetTimerResolution(20000, TRUE, &cur) == STATUS_SUCCESS, "filed to set timer resolution\n");
+    ok(cur <= 20000 && cur >= 20000/2, "resoltuion was set to %u which is not close to the requested one\n", cur);
+
+    ok(pNtQueryTimerResolution(&min, &max, &cur2) == STATUS_SUCCESS, "failed to get resolution\n");
+    ok(cur2 == cur, "setting and quering resoltions report mismatched values %u != %u\n", cur2, cur);
+
+    ok(pNtSetTimerResolution(100000, TRUE, &cur) == STATUS_SUCCESS, "failed to decrease resolution\n");
+    ok(cur <= 100000 && cur >= 100000/2, "resolution was set to %u which is not close to the requested one\n", cur);
+
+    ok(pNtSetTimerResolution(123456, FALSE, &cur) == STATUS_SUCCESS, "failed to unset resolution\n");
+    ok(cur == def, "after unsetting we've got %u instead of the default %u\n", cur, def);
+
+    ok(pNtSetTimerResolution(123456, FALSE, &cur) == STATUS_TIMER_RESOLUTION_NOT_SET, "we have unset resolution more times than one\n");
+}
+
 START_TEST(time)
 {
     HMODULE mod = GetModuleHandleA("ntdll.dll");
@@ -276,6 +305,8 @@ START_TEST(time)
     pRtlQueryDynamicTimeZoneInformation =
         (void *)GetProcAddress(mod, "RtlQueryDynamicTimeZoneInformation");
     pRtlQueryUnbiasedInterruptTime = (void *)GetProcAddress(mod, "RtlQueryUnbiasedInterruptTime");
+    pNtQueryTimerResolution = (void *)GetProcAddress(mod, "NtQueryTimerResolution");
+    pNtSetTimerResolution = (void *)GetProcAddress(mod, "NtSetTimerResolution");
 
     if (pRtlTimeToTimeFields && pRtlTimeFieldsToTime)
         test_pRtlTimeToTimeFields();
@@ -284,4 +315,5 @@ START_TEST(time)
     test_NtQueryPerformanceCounter();
     test_RtlQueryTimeZoneInformation();
     test_user_shared_data_time();
+    test_timer_resolution();
 }
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 23dca9c61b..eb93ac0d4b 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -81,6 +81,15 @@ static const LARGE_INTEGER zero_timeout;
 
 static pthread_mutex_t addr_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+static ULONG timer_resolution_current = 0;
+static const ULONG timer_resolution_min = 156250; /* also the default */
+static const ULONG timer_resolution_max = 5000;
+
+static ULONG get_timer_resolution(void)
+{
+    return timer_resolution_current ? timer_resolution_current : timer_resolution_min;
+}
+
 /* return a monotonic time counter, in Win32 ticks */
 static inline ULONGLONG monotonic_counter(void)
 {
@@ -1438,8 +1447,19 @@ NTSTATUS WINAPI NtSetSystemTime( const LARGE_INTEGER *new, LARGE_INTEGER *old )
  */
 NTSTATUS WINAPI NtQueryTimerResolution( ULONG *min_res, ULONG *max_res, ULONG *current_res )
 {
-    FIXME( "(%p,%p,%p), stub!\n", min_res, max_res, current_res );
-    return STATUS_NOT_IMPLEMENTED;
+    __TRY
+    {
+        *min_res = timer_resolution_min;
+        *max_res = timer_resolution_max;
+        *current_res = get_timer_resolution();
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        return STATUS_ACCESS_VIOLATION;
+    }
+    __ENDTRY
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -1448,8 +1468,37 @@ NTSTATUS WINAPI NtQueryTimerResolution( ULONG *min_res, ULONG *max_res, ULONG *c
  */
 NTSTATUS WINAPI NtSetTimerResolution( ULONG res, BOOLEAN set, ULONG *current_res )
 {
-    FIXME( "(%u,%u,%p), stub!\n", res, set, current_res );
-    return STATUS_NOT_IMPLEMENTED;
+    __TRY
+    {
+        *current_res =  timer_resolution_current;
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        return STATUS_ACCESS_VIOLATION;
+    }
+    __ENDTRY
+
+    if (set)
+    {
+        if (res < timer_resolution_max)
+            res = timer_resolution_max;
+
+        if (res > timer_resolution_min)
+            res = timer_resolution_min;
+
+        InterlockedExchange( (LONG*) &timer_resolution_current, res );
+    }
+    else
+    {
+        ULONG original = InterlockedExchange( (LONG*) &timer_resolution_current, 0 );
+
+        if (original == 0)
+            return STATUS_TIMER_RESOLUTION_NOT_SET;
+    }
+
+    *current_res = get_timer_resolution();
+
+    return STATUS_SUCCESS;
 }
 
 
-- 
2.28.0




More information about the wine-devel mailing list