From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/sync.c | 46 ++++++++++++++++++++++++++++++++++++++ server/thread.c | 3 ++- 2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 25ed4aec6a0..b19c9b1a967 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -2640,6 +2640,10 @@ static DWORD WINAPI alertable_wait_thread(void *param) return 0; }
+static void CALLBACK dummy_apc_func(ULONG_PTR userdata) +{ +} + static void CALLBACK alertable_wait_apc(ULONG_PTR userdata) { HANDLE *semaphores = (void *)userdata; @@ -2658,12 +2662,54 @@ static void CALLBACK alertable_wait_apc2(ULONG_PTR userdata) static void test_alertable_wait(void) { HANDLE thread, semaphores[2]; + LARGE_INTEGER timeout; + NTSTATUS status; DWORD result;
semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); ok(semaphores[0] != NULL, "CreateSemaphore failed with %lu\n", GetLastError()); semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); ok(semaphores[1] != NULL, "CreateSemaphore failed with %lu\n", GetLastError()); + + result = QueueUserAPC(dummy_apc_func, GetCurrentThread(), 0); + ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); + ReleaseSemaphore(semaphores[0], 1, NULL); + status = pNtWaitForMultipleObjects(1, &semaphores[0], FALSE, TRUE, NULL); + ok(status == STATUS_USER_APC, "expected STATUS_USER_APC, got %08lx\n", status); + status = pNtWaitForMultipleObjects(1, &semaphores[0], FALSE, TRUE, NULL); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", status); + + ReleaseSemaphore(semaphores[0], 1, NULL); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = QueueUserAPC(dummy_apc_func, GetCurrentThread(), 0); + ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); + status = pNtWaitForMultipleObjects(2, &semaphores[0], FALSE, TRUE, NULL); + ok(status == STATUS_USER_APC, "expected STATUS_USER_APC, got %08lx\n", status); + status = pNtWaitForMultipleObjects(2, &semaphores[0], FALSE, TRUE, NULL); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", status); + + timeout.QuadPart = 0; + ReleaseSemaphore(semaphores[0], 1, NULL); + result = QueueUserAPC(dummy_apc_func, GetCurrentThread(), 0); + ReleaseSemaphore(semaphores[1], 1, NULL); + ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); + status = pNtWaitForMultipleObjects(2, &semaphores[0], FALSE, TRUE, &timeout); + ok(status == STATUS_USER_APC, "expected STATUS_USER_APC, got %08lx\n", status); + status = pNtWaitForMultipleObjects(2, &semaphores[0], FALSE, TRUE, &timeout); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", status); + + timeout.QuadPart = -10000; + ReleaseSemaphore(semaphores[0], 1, NULL); + result = QueueUserAPC(dummy_apc_func, GetCurrentThread(), 0); + ReleaseSemaphore(semaphores[1], 1, NULL); + ok(result != 0, "QueueUserAPC failed with %lu\n", GetLastError()); + status = pNtWaitForMultipleObjects(2, &semaphores[0], TRUE, TRUE, &timeout); + ok(status == STATUS_USER_APC, "expected STATUS_USER_APC, got %08lx\n", status); + status = pNtWaitForMultipleObjects(2, &semaphores[0], TRUE, TRUE, &timeout); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", status); + status = pNtWaitForMultipleObjects(2, &semaphores[0], TRUE, TRUE, &timeout); + ok(status == WAIT_OBJECT_0 + 1, "expected STATUS_SUCCESS, got %08lx\n", status); + thread = CreateThread(NULL, 0, alertable_wait_thread, semaphores, 0, NULL); ok(thread != NULL, "CreateThread failed with %lu\n", GetLastError());
diff --git a/server/thread.c b/server/thread.c index 05ec6a4ec00..1452491887a 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1123,6 +1123,8 @@ static int check_wait( struct thread *thread ) /* Suspended threads may not acquire locks, but they can run system APCs */ if (thread->process->suspend + thread->suspend > 0) return -1;
+ if ((wait->flags & SELECT_ALERTABLE) && !list_empty(&thread->user_apc)) return STATUS_USER_APC; + if (wait->select == SELECT_WAIT_ALL) { int not_ok = 0; @@ -1138,7 +1140,6 @@ static int check_wait( struct thread *thread ) if (object_sync_signaled( entry->obj, entry )) return i; }
- if ((wait->flags & SELECT_ALERTABLE) && !list_empty(&thread->user_apc)) return STATUS_USER_APC; if (wait->when >= 0 && wait->when <= current_time) return STATUS_TIMEOUT; if (wait->when < 0 && -wait->when <= monotonic_time) return STATUS_TIMEOUT; return -1;