[1/2] ntdll: Add support for a default timer queue.

Dan Hipschman dsh at linux.ucla.edu
Tue Jul 29 16:36:41 CDT 2008


This adds support for a default timer queue and should fix bug 14683.
I've just added some minimal tests for documented behavior here.  I
also discovered some undocumented (and a bit strange) behavior which
I've added in the following patch, which can be applied if the tests
are deemed reasonable (if an app would depend on them, i would think
the app was broken, but then doesn't matter).

---
 dlls/kernel32/tests/sync.c |   14 ++++++++++++++
 dlls/ntdll/threadpool.c    |   44 +++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c
index dcf2b62..2a686ca 100644
--- a/dlls/kernel32/tests/sync.c
+++ b/dlls/kernel32/tests/sync.c
@@ -880,6 +880,20 @@ static void test_timer_queue(void)
     ok(!ret, "DeleteTimerQueueEx\n");
     ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueEx\n");
     ok(d1.num_calls == 1, "DeleteTimerQueueTimer\n");
+
+    /* Test functions on the default timer queue.  */
+    t1 = NULL;
+    n1 = 0;
+    ret = pCreateTimerQueueTimer(&t1, NULL, timer_queue_cb1, &n1, 1000,
+                                 1000, 0);
+    ok(ret, "CreateTimerQueueTimer, default queue\n");
+    ok(t1 != NULL, "CreateTimerQueueTimer, default queue\n");
+
+    ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000);
+    ok(ret, "ChangeTimerQueueTimer, default queue\n");
+
+    ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE);
+    ok(ret, "DeleteTimerQueueTimer, default queue\n");
 }
 
 START_TEST(sync)
diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c
index e468cbe..18baeee 100644
--- a/dlls/ntdll/threadpool.c
+++ b/dlls/ntdll/threadpool.c
@@ -816,9 +816,14 @@ NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
 {
     struct timer_queue *q = TimerQueue;
     struct queue_timer *t, *temp;
-    HANDLE thread = q->thread;
+    HANDLE thread;
     NTSTATUS status;
 
+    if (!q)
+        return STATUS_INVALID_HANDLE;
+
+    thread = q->thread;
+
     RtlEnterCriticalSection(&q->cs);
     q->quit = TRUE;
     if (list_head(&q->timers))
@@ -851,6 +856,31 @@ NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
     return status;
 }
 
+static struct timer_queue *default_timer_queue;
+
+static struct timer_queue *get_timer_queue(HANDLE TimerQueue)
+{
+    if (TimerQueue)
+        return TimerQueue;
+    else
+    {
+        if (!default_timer_queue)
+        {
+            HANDLE q;
+            NTSTATUS status = RtlCreateTimerQueue(&q);
+            if (status == STATUS_SUCCESS)
+            {
+                PVOID p = interlocked_cmpxchg_ptr(
+                    (void **) &default_timer_queue, q, NULL);
+                if (p)
+                    /* Got beat to the punch.  */
+                    RtlDeleteTimerQueueEx(p, NULL);
+            }
+        }
+        return default_timer_queue;
+    }
+}
+
 /***********************************************************************
  *              RtlCreateTimer   (NTDLL.@)
  *
@@ -882,8 +912,12 @@ NTSTATUS WINAPI RtlCreateTimer(PHANDLE NewTimer, HANDLE TimerQueue,
                                ULONG Flags)
 {
     NTSTATUS status;
-    struct timer_queue *q = TimerQueue;
-    struct queue_timer *t = RtlAllocateHeap(GetProcessHeap(), 0, sizeof *t);
+    struct queue_timer *t;
+    struct timer_queue *q = get_timer_queue(TimerQueue);
+    if (!q)
+        return STATUS_NO_MEMORY;
+
+    t = RtlAllocateHeap(GetProcessHeap(), 0, sizeof *t);
     if (!t)
         return STATUS_NO_MEMORY;
 
@@ -933,8 +967,8 @@ NTSTATUS WINAPI RtlCreateTimer(PHANDLE NewTimer, HANDLE TimerQueue,
 NTSTATUS WINAPI RtlUpdateTimer(HANDLE TimerQueue, HANDLE Timer,
                                DWORD DueTime, DWORD Period)
 {
-    struct timer_queue *q = TimerQueue;
     struct queue_timer *t = Timer;
+    struct timer_queue *q = t->q;
 
     RtlEnterCriticalSection(&q->cs);
     /* Can't change a timer if it was once-only or destroyed.  */
@@ -969,8 +1003,8 @@ NTSTATUS WINAPI RtlUpdateTimer(HANDLE TimerQueue, HANDLE Timer,
 NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer,
                                HANDLE CompletionEvent)
 {
-    struct timer_queue *q = TimerQueue;
     struct queue_timer *t = Timer;
+    struct timer_queue *q = t->q;
     NTSTATUS status = STATUS_PENDING;
     HANDLE event = NULL;
 



More information about the wine-patches mailing list