[PATCH 1/2] server: Store async list in process object and use that to find async in cansel_async request.

Jacek Caban jacek at codeweavers.com
Thu Dec 1 08:03:33 CST 2016


On 01.12.2016 12:52, Alexandre Julliard wrote:
> Jacek Caban <jacek at codeweavers.com> writes:
>
>>> We'd probably need to clear them explicitly at process exit.
>> I agree that we should. I will send a new series implementing that. I
>> tested that with the attached patch (I can't send it to wine-patches yet
>> because it uses pipes in message mode).
> Thread exit would be interesting to test too.

I tested that and it seems that Windows aborts asyncs on thread exit.
It's easy to implement aborting itself in Wine, but I must admit that I
have very mixed feelings about it.

I would expect to be able to initialize an async I/O in one thread and
handle its completion in another. That's how threadpool - based
applications are likely to work and, maybe not literally, but [1] gives
an impression that it's supported. I tried to test threadpool with the
attached test, but it throws an exception in TerminateThread call, not
allowing me to terminate that thread. That makes me think that it
supports splitting async I/O between threads by heavily ensuring that
affected threads are not terminated. We don't have something like that
in Wine and I find it very risky to implement async cancellation on
thread exit at this point.

Thanks,
Jacek

[1]
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686760(v=vs.85).aspx
-------------- next part --------------
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index c17d2a0..5b47240 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -2801,16 +2801,28 @@ static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL
     test_flush_done(flush_thread);
 }
 
-static void child_process_write_pipe(HANDLE pipe)
+static DWORD WINAPI write_pipe_proc(HANDLE pipe)
 {
-    OVERLAPPED overlapped;
-    char buf[10000];
+    static OVERLAPPED overlapped;
+    static char buf[10000];
 
     memset(buf, 'x', sizeof(buf));
     overlapped_write_async(pipe, buf, sizeof(buf), &overlapped);
 
-    /* sleep until parent process tesrminates this process. */
+    /* sleep until thread is terminated */
     Sleep(INFINITE);
+    return 1;
+}
+
+static HANDLE tp_thread;
+
+static void WINAPI tp_write_pipe(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work)
+{
+    BOOL res = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
+                               &tp_thread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+    ok(res, "DuplicateHandle failed: %u\n", GetLastError());
+    trace("thread handle %p\n", tp_thread);
+    write_pipe_proc(context);
 }
 
 static HANDLE create_writepipe_process(HANDLE pipe)
@@ -2864,8 +2876,9 @@ static void test_overlapped_transport(DWORD read_mode)
     OVERLAPPED overlapped, overlapped2;
     HANDLE server, client, flush;
     DWORD read_bytes;
-    HANDLE process;
+    HANDLE process, thread;
     char buf[60000];
+    TP_WORK *tp_work;
     BOOL res;
 
     create_overlapped_pipe(read_mode, &client, &server);
@@ -2928,6 +2941,55 @@ static void test_overlapped_transport(DWORD read_mode)
     CloseHandle(process);
     CloseHandle(server);
     CloseHandle(client);
+
+    /* terminate thread with pending write */
+    create_overlapped_pipe(read_mode, &client, &server);
+    thread = CreateThread(NULL, 0, write_pipe_proc, client, 0, NULL);
+    ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
+    /* succesfully read part of write that is pending in different thread */
+    res = ReadFile(server, buf, 10, &read_bytes, NULL);
+    if(read_mode == PIPE_READMODE_BYTE)
+        ok(res, "ReadFile failed: %u\n", GetLastError());
+    else
+        ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x %u\n", res, GetLastError());
+    ok(read_bytes == 10, "read_bytes = %u\n", read_bytes);
+    TerminateThread(thread, 0);
+    WaitForSingleObject(thread, INFINITE);
+    /* after terminating thread, there is no pending write and pipe buffer is empty */
+    overlapped_read_async(server, buf, 10, &overlapped);
+    overlapped_write_sync(client, buf, 1);
+    test_overlapped_result(server, &overlapped, 1, FALSE);
+    CloseHandle(thread);
+    CloseHandle(server);
+    CloseHandle(client);
+
+    /* The code below is an ugly attempt to test thread pools.
+     * It throws an exception on Windows in TerminateThread, but not on Wine. */
+    return;
+
+    /* terminate thread in thread pool with pending write */
+    create_overlapped_pipe(read_mode, &client, &server);
+    tp_work = CreateThreadpoolWork(tp_write_pipe, client, NULL);
+    ok(tp_work != NULL, "CreateThreadpoolWork failed: %u\n", GetLastError());
+    SubmitThreadpoolWork(tp_work);
+    /* succesfully read part of write that is pending in different thread */
+    res = ReadFile(server, buf, 10, &read_bytes, NULL);
+    if(read_mode == PIPE_READMODE_BYTE)
+        ok(res, "ReadFile failed: %u\n", GetLastError());
+    else
+        ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x %u\n", res, GetLastError());
+    ok(read_bytes == 10, "read_bytes = %u\n", read_bytes);
+    trace("terminating thread %p\n", tp_thread);
+    TerminateThread(tp_thread, 0);
+    trace("terminated\n");
+    WaitForSingleObject(tp_thread, INFINITE);
+    /* after terminating thread, there is no pending write and pipe buffer is empty */
+    overlapped_read_async(server, buf, 10, &overlapped);
+    overlapped_write_sync(client, buf, 1);
+    test_overlapped_result(server, &overlapped, 1, FALSE);
+    CloseHandle(tp_thread);
+    CloseHandle(server);
+    CloseHandle(client);
 }
 
 START_TEST(pipe)
@@ -2948,7 +3010,7 @@ START_TEST(pipe)
     {
         UINT_PTR handle;
         sscanf(argv[3], "%lx", &handle);
-        child_process_write_pipe((HANDLE)handle);
+        write_pipe_proc((HANDLE)handle);
         return;
     }
 


More information about the wine-devel mailing list