[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