Paul Gofman : server: Send completions for existing job processes when adding completion port.

Alexandre Julliard julliard at winehq.org
Wed May 19 14:55:13 CDT 2021


Module: wine
Branch: master
Commit: de0dc0e8ac664549c64124fa02011b8f096217b3
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=de0dc0e8ac664549c64124fa02011b8f096217b3

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Tue May 18 14:36:34 2021 +0300

server: Send completions for existing job processes when adding completion port.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/kernel32/tests/process.c | 64 +++++++++++++++++++++++++++++++++++++++++--
 server/process.c              | 21 ++++++++++++++
 2 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index f170043b5b9..52c3036fe59 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -2786,13 +2786,17 @@ static void test_QueryInformationJobObject(void)
 static void test_CompletionPort(void)
 {
     JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
-    PROCESS_INFORMATION pi;
+    PROCESS_INFORMATION pi, pi2;
     HANDLE job, port;
     BOOL ret;
 
     job = pCreateJobObjectW(NULL, NULL);
     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
 
+    create_process("wait", &pi2);
+    ret = pAssignProcessToJobObject(job, pi2.hProcess);
+    ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
+
     port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
     ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
 
@@ -2806,12 +2810,19 @@ static void test_CompletionPort(void)
     ret = pAssignProcessToJobObject(job, pi.hProcess);
     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
 
+    test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0);
     test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
 
     TerminateProcess(pi.hProcess, 0);
     wait_child_process(pi.hProcess);
 
     test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
+    TerminateProcess(pi2.hProcess, 0);
+    wait_child_process(pi2.hProcess);
+    CloseHandle(pi2.hProcess);
+    CloseHandle(pi2.hThread);
+
+    test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0);
     test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
 
     CloseHandle(pi.hProcess);
@@ -4350,10 +4361,15 @@ static void test_dead_process(void)
 
 static void test_nested_jobs_child(unsigned int index)
 {
-    HANDLE job, job_parent, job_other;
+    JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
+    HANDLE job, job_parent, job_other, port;
     PROCESS_INFORMATION pi;
+    OVERLAPPED *overlapped;
     char job_name[32];
+    ULONG_PTR value;
+    DWORD dead_pid;
     BOOL ret, out;
+    DWORD key;
 
     sprintf(job_name, "test_nested_jobs_%u", index);
     job = pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_QUERY
@@ -4412,6 +4428,20 @@ static void test_nested_jobs_child(unsigned int index)
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
 
+    dead_pid = pi.dwProcessId;
+
+    port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
+    ok(!!port, "CreateIoCompletionPort error %u\n", GetLastError());
+
+    port_info.CompletionPort = port;
+    port_info.CompletionKey = job;
+    ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
+    ok(ret, "SetInformationJobObject error %u\n", GetLastError());
+    port_info.CompletionKey = job_parent;
+    ret = pSetInformationJobObject(job_parent, JobObjectAssociateCompletionPortInformation,
+            &port_info, sizeof(port_info));
+    ok(ret, "SetInformationJobObject error %u\n", GetLastError());
+
     create_process("wait", &pi);
     out = FALSE;
     ret = pIsProcessInJob(pi.hProcess, job, &out);
@@ -4423,12 +4453,42 @@ static void test_nested_jobs_child(unsigned int index)
     ok(ret, "IsProcessInJob error %u\n", GetLastError());
     ok(out, "IsProcessInJob returned out=%u\n", out);
 
+    /* The first already dead child process still shows up randomly. */
+    do
+    {
+        ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
+    } while (ret && (ULONG_PTR)overlapped == dead_pid);
+
+    ok(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
+    ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %x\n", key);
+    ok((HANDLE)value == job, "unexpected value %p\n", (void *)value);
+    ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#x\n", (DWORD)(DWORD_PTR)overlapped);
+
+    do
+    {
+        ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
+    } while (ret && (ULONG_PTR)overlapped == dead_pid);
+
+    ok(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
+    ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %x\n", key);
+    ok((HANDLE)value == job_parent, "unexpected value %p\n", (void *)value);
+    ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#x\n", (DWORD)(DWORD_PTR)overlapped);
+
+    test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
+    test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job_parent, pi.dwProcessId, 0);
+
+    ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
+    ok(!ret, "GetQueuedCompletionStatus succeeded.\n");
+
     if (index)
     {
         ret = pAssignProcessToJobObject(job_other, GetCurrentProcess());
         ok(!ret, "AssignProcessToJobObject succeded\n");
         ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %u.\n", GetLastError());
     }
+
+    CloseHandle(port);
+
 done:
     TerminateProcess(pi.hProcess, 0);
     wait_child_process(pi.hProcess);
diff --git a/server/process.c b/server/process.c
index 8baccdbad94..32c6fdd269b 100644
--- a/server/process.c
+++ b/server/process.c
@@ -255,6 +255,25 @@ static void add_job_completion( struct job *job, apc_param_t msg, apc_param_t pi
         add_completion( job->completion_port, job->completion_key, pid, STATUS_SUCCESS, msg );
 }
 
+static void add_job_completion_existing_processes( struct job *job, struct job *completion_job )
+{
+    struct process *process;
+    struct job *j;
+
+    assert( completion_job->obj.ops == &job_ops );
+
+    LIST_FOR_EACH_ENTRY( j, &job->child_job_list, struct job, parent_job_entry )
+    {
+        add_job_completion_existing_processes( j, completion_job );
+    }
+
+    LIST_FOR_EACH_ENTRY( process, &job->process_list, struct process, job_entry )
+    {
+        if (process->running_threads)
+            add_job_completion( completion_job, JOB_OBJECT_MSG_NEW_PROCESS, get_process_id( process ));
+    }
+}
+
 static int process_in_job( struct job *job, struct process *process )
 {
     struct job *j;
@@ -1715,6 +1734,8 @@ DECL_HANDLER(set_job_completion_port)
     {
         job->completion_port = get_completion_obj( current->process, req->port, IO_COMPLETION_MODIFY_STATE );
         job->completion_key = req->key;
+
+        add_job_completion_existing_processes( job, job );
     }
     else
         set_error( STATUS_INVALID_PARAMETER );




More information about the wine-cvs mailing list