Module: wine Branch: master Commit: 381c034be3698231e71d20062985a5005c3b32a8 URL: http://source.winehq.org/git/wine.git/?a=commit;h=381c034be3698231e71d200629...
Author: Sebastian Lackner sebastian@fds-team.de Date: Fri Oct 9 06:37:57 2015 +0200
ntdll: Wait_thread_proc should not terminate on user APC.
Signed-off-by: Sebastian Lackner sebastian@fds-team.de Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/tests/threadpool.c | 68 +++++++++++++++++++++++++++++++++++++++++-- dlls/ntdll/threadpool.c | 2 +- 2 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c index d4e13bd..304fe91 100644 --- a/dlls/ntdll/tests/threadpool.c +++ b/dlls/ntdll/tests/threadpool.c @@ -148,6 +148,7 @@ struct rtl_wait_info HANDLE semaphore1; HANDLE semaphore2; DWORD wait_result; + DWORD threadid; LONG userdata; };
@@ -162,6 +163,7 @@ static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout) InterlockedIncrement(&info->userdata); else InterlockedExchangeAdd(&info->userdata, 0x10000); + info->threadid = GetCurrentThreadId(); ReleaseSemaphore(info->semaphore1, 1, NULL);
if (info->semaphore2) @@ -172,14 +174,22 @@ static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout) } }
+static HANDLE rtl_wait_apc_semaphore; + +static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata) +{ + trace("Running rtl_wait_apc callback\n"); + if (rtl_wait_apc_semaphore) + ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL); +} + static void test_RtlRegisterWait(void) { + HANDLE wait1, event, thread; struct rtl_wait_info info; HANDLE semaphores[2]; NTSTATUS status; DWORD result; - HANDLE wait1; - HANDLE event;
semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL); ok(semaphores[0] != NULL, "failed to create semaphore\n"); @@ -270,6 +280,60 @@ static void test_RtlRegisterWait(void) status = RtlDeregisterWait(wait1); ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+ /* test for IO threads */ + info.userdata = 0; + info.threadid = 0; + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEINIOTHREAD); + ok(!status, "RtlRegisterWait failed with status %x\n", status); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 100); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid); + thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); + ok(thread != NULL, "OpenThread failed with %u\n", GetLastError()); + rtl_wait_apc_semaphore = semaphores[0]; + result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); + ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError()); + result = WaitForSingleObject(semaphores[0], 200); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + rtl_wait_apc_semaphore = 0; + CloseHandle(thread); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 100); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); + Sleep(50); + status = RtlDeregisterWait(wait1); + ok(!status, "RtlDeregisterWait failed with status %x\n", status); + + info.userdata = 0; + info.threadid = 0; + status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); + ok(!status, "RtlRegisterWait failed with status %x\n", status); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 100); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata); + ok(info.threadid != 0, "expected info.threadid != 0, got %u\n", info.threadid); + thread = OpenThread(THREAD_SET_CONTEXT, FALSE, info.threadid); + ok(thread != NULL, "OpenThread failed with %u\n", GetLastError()); + rtl_wait_apc_semaphore = semaphores[0]; + result = QueueUserAPC(rtl_wait_apc_cb, thread, 0); + ok(result != 0, "QueueUserAPC failed with %u\n", GetLastError()); + result = WaitForSingleObject(semaphores[0], 200); + ok(result == WAIT_TIMEOUT || broken(result == WAIT_OBJECT_0) /* >= Win Vista */, + "WaitForSingleObject returned %u\n", result); + rtl_wait_apc_semaphore = 0; + CloseHandle(thread); + ReleaseSemaphore(semaphores[1], 1, NULL); + result = WaitForSingleObject(semaphores[0], 100); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata); + Sleep(50); + status = RtlDeregisterWait(wait1); + ok(!status, "RtlDeregisterWait failed with status %x\n", status); + /* test RtlDeregisterWaitEx before wait expired */ info.userdata = 0; status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT); diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c index 0ed0851..9c98040 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -537,7 +537,7 @@ static DWORD CALLBACK wait_thread_proc(LPVOID Arg) if (wait_work_item->Flags & WT_EXECUTEONLYONCE) break; } - else + else if (status != STATUS_USER_APC) break; }