[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