[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