[5/5] ntdll, kernel32: Implement [Rtl]Create/DeleteTimerQueue[Ex].
Dan Hipschman
dsh at linux.ucla.edu
Mon Jul 21 19:46:30 CDT 2008
This is a start for implementing the timer queue in ntdll. I cleaned it
up a bit in the process, but nothing major has changed.
---
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 a484392..7bce445 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 cb118cf..697f905 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 575f99d..0be408e 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 e054136..aa03959 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 fe2f83d..7b8e055 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);
More information about the wine-patches
mailing list