From 20a1ca2bbfe1c79f2971e55ba18fa4dcab06426b Mon Sep 17 00:00:00 2001 From: Dan Hipschman Date: Mon, 21 Jul 2008 17:46:30 -0700 Subject: [PATCH] ntdll: Implement [Rtl]Create/DeleteTimerQueue[Ex]. --- dlls/kernel32/sync.c | 25 +++++++++---- dlls/kernel32/tests/sync.c | 12 ++----- dlls/ntdll/ntdll.spec | 4 +-- dlls/ntdll/threadpool.c | 72 ++++++++++++++++++++++++++++++++++++++ include/winternl.h | 2 ++ 5 files changed, 97 insertions(+), 18 deletions(-) diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index a484392c9e1..7bce44566f8 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -1047,9 +1047,16 @@ BOOL WINAPI CancelWaitableTimer( HANDLE handle ) */ HANDLE WINAPI CreateTimerQueue(void) { - FIXME("stub\n"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + HANDLE q; + NTSTATUS status = RtlCreateTimerQueue(&q); + + if (status != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError(status) ); + return NULL; + } + + return q; } @@ -1058,9 +1065,15 @@ HANDLE WINAPI CreateTimerQueue(void) */ BOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent) { - FIXME("(%p, %p): stub\n", TimerQueue, CompletionEvent); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + NTSTATUS status = RtlDeleteTimerQueueEx(TimerQueue, CompletionEvent); + + if (status != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; + } + + return TRUE; } /*********************************************************************** diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index cb118cfd780..697f90553c1 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -605,18 +605,15 @@ static void test_timer_queue(void) /* Test asynchronous deletion of the queue. */ q = pCreateTimerQueue(); - todo_wine ok(q != NULL, "CreateTimerQueue\n"); SetLastError(0xdeadbeef); ret = pDeleteTimerQueueEx(q, NULL); ok(!ret, "DeleteTimerQueueEx\n"); - todo_wine ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx\n"); /* Test synchronous deletion of the queue and running timers. */ q = pCreateTimerQueue(); - todo_wine ok(q != NULL, "CreateTimerQueue\n"); /* Called once. */ @@ -668,9 +665,9 @@ static void test_timer_queue(void) Sleep(500); ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueEx\n"); todo_wine { - ok(ret, "DeleteTimerQueueEx\n"); ok(n1 == 1, "Timer callback 1\n"); ok(n2 < n3, "Timer callback 2 should be much slower than 3\n"); } @@ -687,23 +684,18 @@ static void test_timer_queue(void) } q = pCreateTimerQueue(); - todo_wine ok(q != NULL, "CreateTimerQueue\n"); SetLastError(0xdeadbeef); ret = pDeleteTimerQueueEx(q, e); ok(!ret, "DeleteTimerQueueEx\n"); - todo_wine - { ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx\n"); ok(WaitForSingleObject(e, 250) == WAIT_OBJECT_0, "Timer destruction event not triggered\n"); - } CloseHandle(e); /* Test deleting/changing a timer in execution. */ q = pCreateTimerQueue(); - todo_wine ok(q != NULL, "CreateTimerQueue\n"); d2.t = t2 = NULL; @@ -731,9 +723,9 @@ static void test_timer_queue(void) Sleep(200); ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueEx\n"); todo_wine { - ok(ret, "DeleteTimerQueueEx\n"); ok(d2.num_calls == d2.max_calls, "DeleteTimerQueueTimer\n"); ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n"); } diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 575f99da373..0be408ef4d8 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -489,7 +489,7 @@ # @ stub RtlCreateSystemVolumeInformationFolder @ stub RtlCreateTagHeap # @ stub RtlCreateTimer -# @ stub RtlCreateTimerQueue +@ stdcall RtlCreateTimerQueue(ptr) @ stdcall RtlCreateUnicodeString(ptr wstr) @ stdcall RtlCreateUnicodeStringFromAsciiz(ptr str) @ stub RtlCreateUserProcess @@ -520,7 +520,7 @@ @ stdcall RtlDeleteSecurityObject(ptr) # @ stub RtlDeleteTimer # @ stub RtlDeleteTimerQueue -# @ stub RtlDeleteTimerQueueEx +@ stdcall RtlDeleteTimerQueueEx(ptr ptr) @ stdcall RtlDeregisterWait(ptr) @ stdcall RtlDeregisterWaitEx(ptr ptr) @ stdcall RtlDestroyAtomTable(ptr) diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c index e0541368b12..aa03959008e 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -528,3 +528,75 @@ NTSTATUS WINAPI RtlDeregisterWait(HANDLE WaitHandle) { return RtlDeregisterWaitEx(WaitHandle, NULL); } + + +/************************** Timer Queue Impl **************************/ + +struct queue_timer +{ + struct list entry; +}; + +struct timer_queue +{ + RTL_CRITICAL_SECTION cs; + struct list timers; +}; + +/*********************************************************************** + * RtlCreateTimerQueue (NTDLL.@) + * + * Creates a timer queue object and returns a handle to it. + * + * PARAMS + * NewTimerQueue [O] The newly created queue. + * + * RETURNS + * Success: STATUS_SUCCESS. + * Failure: Any NTSTATUS code. + */ +NTSTATUS WINAPI RtlCreateTimerQueue(PHANDLE NewTimerQueue) +{ + struct timer_queue *q = RtlAllocateHeap(GetProcessHeap(), 0, sizeof *q); + if (!q) + return STATUS_NO_MEMORY; + + RtlInitializeCriticalSection(&q->cs); + list_init(&q->timers); + + *NewTimerQueue = q; + return STATUS_SUCCESS; +} + +/*********************************************************************** + * RtlDeleteTimerQueueEx (NTDLL.@) + * + * Deletes a timer queue object. + * + * PARAMS + * TimerQueue [I] The timer queue to destroy. + * CompletionEvent [I] If NULL, return immediately. If INVALID_HANDLE_VALUE, + * wait until all timers are finished firing before + * returning. Otherwise, return immediately and set the + * event when all timers are done. + * + * RETURNS + * Success: STATUS_SUCCESS if synchronous, STATUS_PENDING if not. + * Failure: Any NTSTATUS code. + */ +NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent) +{ + struct timer_queue *q = TimerQueue; + + RtlDeleteCriticalSection(&q->cs); + RtlFreeHeap(GetProcessHeap(), 0, q); + + if (CompletionEvent == INVALID_HANDLE_VALUE) + return STATUS_SUCCESS; + else + { + if (CompletionEvent) + NtSetEvent(CompletionEvent, NULL); + return STATUS_PENDING; + } +} diff --git a/include/winternl.h b/include/winternl.h index fe2f83d3feb..7b8e0551b17 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2117,6 +2117,7 @@ NTSYSAPI NTSTATUS WINAPI RtlCreateEnvironment(BOOLEAN, PWSTR*); NTSYSAPI HANDLE WINAPI RtlCreateHeap(ULONG,PVOID,SIZE_T,SIZE_T,PVOID,PRTL_HEAP_DEFINITION); NTSYSAPI NTSTATUS WINAPI RtlCreateProcessParameters(RTL_USER_PROCESS_PARAMETERS**,const UNICODE_STRING*,const UNICODE_STRING*,const UNICODE_STRING*,const UNICODE_STRING*,PWSTR,const UNICODE_STRING*,const UNICODE_STRING*,const UNICODE_STRING*,const UNICODE_STRING*); NTSYSAPI NTSTATUS WINAPI RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR,DWORD); +NTSYSAPI NTSTATUS WINAPI RtlCreateTimerQueue(PHANDLE); NTSYSAPI BOOLEAN WINAPI RtlCreateUnicodeString(PUNICODE_STRING,LPCWSTR); NTSYSAPI BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz(PUNICODE_STRING,LPCSTR); NTSYSAPI NTSTATUS WINAPI RtlCreateUserThread(HANDLE,const SECURITY_DESCRIPTOR*,BOOLEAN,PVOID,SIZE_T,SIZE_T,PRTL_THREAD_START_ROUTINE,void*,HANDLE*,CLIENT_ID*); @@ -2127,6 +2128,7 @@ NTSYSAPI NTSTATUS WINAPI RtlDeleteCriticalSection(RTL_CRITICAL_SECTION *); NTSYSAPI NTSTATUS WINAPI RtlDeleteRegistryValue(ULONG, PCWSTR, PCWSTR); NTSYSAPI void WINAPI RtlDeleteResource(LPRTL_RWLOCK); NTSYSAPI NTSTATUS WINAPI RtlDeleteSecurityObject(PSECURITY_DESCRIPTOR*); +NTSYSAPI NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE, HANDLE); NTSYSAPI PRTL_USER_PROCESS_PARAMETERS WINAPI RtlDeNormalizeProcessParams(RTL_USER_PROCESS_PARAMETERS*); NTSYSAPI NTSTATUS WINAPI RtlDeregisterWait(HANDLE); NTSYSAPI NTSTATUS WINAPI RtlDeregisterWaitEx(HANDLE,HANDLE);