Added patch for job object completion support.

This commit is contained in:
Sebastian Lackner 2015-02-28 01:20:47 +01:00
parent cd62b5bedc
commit 8cc25d0fe4
6 changed files with 233 additions and 31 deletions

View File

@ -38,12 +38,13 @@ Wine. All those differences are also documented on the
Included bug fixes and improvements
===================================
**Bugfixes and features included in the next upcoming release [10]:**
**Bugfixes and features included in the next upcoming release [11]:**
* Add stub for gdiplus.GdipCreateEffect ([Wine Bug #32163](https://bugs.winehq.org/show_bug.cgi?id=32163))
* Add support for CopyFileEx progress callback ([Wine Bug #22692](https://bugs.winehq.org/show_bug.cgi?id=22692))
* Allow to cancel a file operation via progress callback ([Wine Bug #22690](https://bugs.winehq.org/show_bug.cgi?id=22690))
* Allow to override number of quality levels for D3DMULTISAMPLE_NONMASKABLE. ([Wine Bug #12652](https://bugs.winehq.org/show_bug.cgi?id=12652))
* EA Origin needs support for job objects ([Wine Bug #33723](https://bugs.winehq.org/show_bug.cgi?id=33723))
* Enforce that surfaces are flushed after ReleaseDC
* Fallback to global key state for threads without a queue ([Wine Bug #27238](https://bugs.winehq.org/show_bug.cgi?id=27238))
* Fix race-condition when threads are killed during shutdown

1
debian/changelog vendored
View File

@ -19,6 +19,7 @@ wine-staging (1.7.38) UNRELEASED; urgency=low
* Added patch to enforce that surfaces are flushed after ReleaseDC.
* Added patch to implement IProgressDialog::SetAnimation.
* Added patch in order to allow to override number of quality levels for D3DMULTISAMPLE_NONMASKABLE.
* Added patch for job object completion support.
* Removed patch to properly call DriverUnload when unloading device drivers (accepted upstream).
* Removed patch to allow Accept-Encoding for HTTP/1.0 in wininet (accepted upstream).
* Removed patch to declare pDirectInputCreateEx in a MSVC compatible way (accepted upstream).

View File

@ -3338,6 +3338,9 @@ fi
# Patchset server-JobObjects
# |
# | This patchset fixes the following Wine bugs:
# | * [#33723] EA Origin needs support for job objects
# |
# | Modified files:
# | * dlls/kernel32/tests/process.c, dlls/ntdll/sync.c, include/winnt.h, server/process.c, server/process.h,
# | server/protocol.def
@ -3353,6 +3356,7 @@ if test "$enable_server_JobObjects" -eq 1; then
patch_apply server-JobObjects/0008-kernel32-tests-Add-tests-for-JOB_OBJECT_LIMIT_BREAKA.patch
patch_apply server-JobObjects/0009-kernel32-tests-Add-tests-for-job-inheritance.patch
patch_apply server-JobObjects/0010-server-Basic-implementation-of-job-objects.patch
patch_apply server-JobObjects/0011-server-Implement-completion-messages-for-job-objects.patch
(
echo '+ { "Sebastian Lackner", "kernel32/tests: Allow multiple subprocess commands in process tests.", 1 },';
echo '+ { "Andrew Cook", "kernel32/tests: Add tests for IsProcessInJob.", 1 },';
@ -3364,6 +3368,7 @@ if test "$enable_server_JobObjects" -eq 1; then
echo '+ { "Andrew Cook", "kernel32/tests: Add tests for JOB_OBJECT_LIMIT_BREAKAWAY_OK.", 1 },';
echo '+ { "Andrew Cook", "kernel32/tests: Add tests for job inheritance.", 1 },';
echo '+ { "Andrew Cook", "server: Basic implementation of job objects.", 1 },';
echo '+ { "Andrew Cook", "server: Implement completion messages for job objects.", 1 },';
) >> "$patchlist"
fi

View File

@ -1,4 +1,4 @@
From 42af9f44c92dbe151b3ec5b4f57e941133349648 Mon Sep 17 00:00:00 2001
From bc3809dc809edebc43305826f2a687de1089ca26 Mon Sep 17 00:00:00 2001
From: Andrew Cook <ariscop@gmail.com>
Date: Thu, 26 Feb 2015 12:25:23 +1100
Subject: server: Basic implementation of job objects.
@ -15,10 +15,10 @@ Changes by Sebastian Lackner <sebastian@fds-team.de>:
dlls/kernel32/tests/process.c | 8 +-
dlls/ntdll/sync.c | 139 ++++++++++++++++++++---
include/winnt.h | 4 +
server/process.c | 256 ++++++++++++++++++++++++++++++++++++++++++
server/process.c | 254 ++++++++++++++++++++++++++++++++++++++++++
server/process.h | 3 +
server/protocol.def | 27 +++++
6 files changed, 417 insertions(+), 20 deletions(-)
6 files changed, 415 insertions(+), 20 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 9d7d8b8..3f78d74 100644
@ -288,7 +288,7 @@ index 4b06b2c..c2aa50e 100644
{
RelationProcessorCore = 0,
diff --git a/server/process.c b/server/process.c
index 0712a5b..850a9c8 100644
index 0712a5b..5770f0e 100644
--- a/server/process.c
+++ b/server/process.c
@@ -65,6 +65,7 @@ static unsigned int process_map_access( struct object *obj, unsigned int access
@ -509,7 +509,7 @@ index 0712a5b..850a9c8 100644
/* connect to the window station */
connect_process_winstation( process, current );
@@ -1361,3 +1530,90 @@ DECL_HANDLER(make_process_system)
@@ -1361,3 +1530,88 @@ DECL_HANDLER(make_process_system)
shutdown_timeout = add_timeout_user( master_socket_timeout, server_shutdown_timeout, NULL );
}
}
@ -545,59 +545,57 @@ index 0712a5b..850a9c8 100644
+DECL_HANDLER(job_assign)
+{
+ struct process *process;
+ struct job *job;
+ struct job *job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_ASSIGN_PROCESS );
+
+ if (!(job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_ASSIGN_PROCESS )))
+ return;
+
+ if ((process = get_process_from_handle( req->process_handle, PROCESS_SET_QUOTA | PROCESS_TERMINATE )))
+ if (job)
+ {
+ add_job_process( job, process );
+ release_object(process);
+ if ((process = get_process_from_handle( req->process_handle, PROCESS_SET_QUOTA | PROCESS_TERMINATE )))
+ {
+ add_job_process( job, process );
+ release_object(process);
+ }
+ release_object(job);
+ }
+
+ release_object(job);
+}
+
+/* check if a process is associated with a job */
+DECL_HANDLER(process_in_job)
+{
+ struct process *process;
+ struct job *job;
+ struct job *job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_ASSIGN_PROCESS );
+
+ if (!(job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_ASSIGN_PROCESS )))
+ return;
+
+ if ((process = get_process_from_handle( req->process_handle, PROCESS_QUERY_INFORMATION )))
+ if (job)
+ {
+ set_error((process->job == job) ? STATUS_PROCESS_IN_JOB : STATUS_PROCESS_NOT_IN_JOB);
+ release_object(process);
+ if ((process = get_process_from_handle( req->process_handle, PROCESS_QUERY_INFORMATION )))
+ {
+ set_error( (process->job == job) ? STATUS_PROCESS_IN_JOB : STATUS_PROCESS_NOT_IN_JOB );
+ release_object( process );
+ }
+ release_object(job);
+ }
+
+ release_object(job);
+}
+
+/* terminate all processes associated with the job */
+DECL_HANDLER(terminate_job)
+{
+ struct job *job;
+ struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_TERMINATE );
+
+ if ((job = get_job_obj( current->process, req->handle, JOB_OBJECT_TERMINATE )))
+ if (job)
+ {
+ terminate_job(job, req->status);
+ release_object(job);
+ terminate_job( job, req->status );
+ release_object( job );
+ }
+}
+
+/* update limits of the job object */
+DECL_HANDLER(job_set_limits)
+{
+ struct job *job;
+ struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_SET_ATTRIBUTES );
+
+ if ((job = get_job_obj( current->process, req->handle, JOB_OBJECT_SET_ATTRIBUTES )))
+ if (job)
+ {
+ job->limit_flags = req->limit_flags;
+ release_object(job);
+ release_object( job );
+ }
+}
diff --git a/server/process.h b/server/process.h

View File

@ -0,0 +1,196 @@
From 71738db8658662f68f156ce95d146de2eb68b9cf Mon Sep 17 00:00:00 2001
From: Andrew Cook <ariscop@gmail.com>
Date: Thu, 26 Feb 2015 13:02:36 +1100
Subject: server: Implement completion messages for job objects.
Fixes Wine bug #33723.
Various cleanups to fit with the rest of the wineserver
coding style by Sebastian Lackner <sebastian@fds-team.de>.
---
dlls/kernel32/tests/process.c | 4 ----
dlls/ntdll/sync.c | 15 +++++++++++++++
server/process.c | 44 +++++++++++++++++++++++++++++++++++++++++++
server/protocol.def | 6 ++++++
4 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 3f78d74..ec79418 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -2393,7 +2393,6 @@ static void test_CompletionPort(void)
port_info.CompletionKey = job;
port_info.CompletionPort = port;
ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
- todo_wine
ok(ret, "SetInformationJobObject error %u\n", GetLastError());
create_process("wait", &pi);
@@ -2401,16 +2400,13 @@ static void test_CompletionPort(void)
ret = pAssignProcessToJobObject(job, pi.hProcess);
ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
- todo_wine
test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, (LPOVERLAPPED)pi.dwProcessId, 0);
TerminateProcess(pi.hProcess, 0);
dwret = WaitForSingleObject(pi.hProcess, 500);
ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
- todo_wine
test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, (LPOVERLAPPED)pi.dwProcessId, 0);
- todo_wine
test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, NULL, 100);
CloseHandle(pi.hProcess);
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 56714ef..ef4a4cb 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -696,6 +696,21 @@ NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS cla
SERVER_END_REQ;
break;
+ case JobObjectAssociateCompletionPortInformation:
+ if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT))
+ return STATUS_INVALID_PARAMETER;
+
+ SERVER_START_REQ( job_set_completion )
+ {
+ JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
+ req->handle = wine_server_obj_handle( handle );
+ req->port = wine_server_obj_handle( port_info->CompletionPort );
+ req->key = wine_server_client_ptr( port_info->CompletionKey );
+ status = wine_server_call(req);
+ }
+ SERVER_END_REQ;
+ break;
+
default:
FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
return STATUS_NOT_IMPLEMENTED;
diff --git a/server/process.c b/server/process.c
index 5770f0e..73fe08a 100644
--- a/server/process.c
+++ b/server/process.c
@@ -149,6 +149,9 @@ struct job
struct list process_list; /* list of all processes */
int num_processes; /* count of running processes */
int limit_flags; /* limit flags */
+ int terminating; /* job is terminating */
+ struct completion *completion_port;
+ apc_param_t completion_key;
};
static const struct object_ops job_ops =
@@ -188,6 +191,9 @@ static struct job *create_job_object( struct directory *root, const struct unico
list_init( &job->process_list );
job->num_processes = 0;
job->limit_flags = 0;
+ job->terminating = 0;
+ job->completion_port = NULL;
+ job->completion_key = 0;
}
}
return job;
@@ -214,6 +220,12 @@ static unsigned int job_map_access( struct object *obj, unsigned int access )
return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
}
+static void add_job_completion( struct job *job, apc_param_t msg, apc_param_t pid )
+{
+ if (job->completion_port)
+ add_completion(job->completion_port, job->completion_key, pid, STATUS_SUCCESS, msg);
+}
+
static int add_job_process( struct job *job, struct process *process )
{
assert( job->obj.ops == &job_ops );
@@ -228,6 +240,7 @@ static int add_job_process( struct job *job, struct process *process )
list_add_tail( &job->process_list, &process->job_entry );
job->num_processes++;
+ add_job_completion( job, JOB_OBJECT_MSG_NEW_PROCESS, get_process_id(process) );
return 1;
}
@@ -242,10 +255,20 @@ static void release_job_process( struct process *process )
assert( job->obj.ops == &job_ops );
assert( job->num_processes );
job->num_processes--;
+
+ if (!job->terminating)
+ add_job_completion( job, JOB_OBJECT_MSG_EXIT_PROCESS, get_process_id(process) );
+
+ if (!job->num_processes)
+ add_job_completion( job, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, 0 );
}
static void terminate_job( struct job *job, int exit_code )
{
+ /* Windows doesn't report completion events for processes
+ * terminated by TerminateProcess, we do the same */
+ job->terminating = 1;
+
for (;;) /* restart from the beginning of the list every time */
{
struct process *process;
@@ -259,6 +282,8 @@ static void terminate_job( struct job *job, int exit_code )
assert( process->job == job );
terminate_process( process, NULL, exit_code );
}
+
+ job->terminating = 0;
}
static void job_destroy( struct object *obj )
@@ -268,6 +293,9 @@ static void job_destroy( struct object *obj )
assert( !job->num_processes );
assert( list_empty(&job->process_list) );
+
+ if (job->completion_port)
+ release_object(job->completion_port);
}
static void job_dump( struct object *obj, int verbose )
@@ -1615,3 +1643,19 @@ DECL_HANDLER(job_set_limits)
release_object( job );
}
}
+
+DECL_HANDLER(job_set_completion)
+{
+ struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_SET_ATTRIBUTES );
+
+ if (job)
+ {
+ if (!job->completion_port)
+ {
+ job->completion_port = get_completion_obj( current->process, req->port, IO_COMPLETION_MODIFY_STATE );
+ job->completion_key = req->key;
+ }
+ else set_error( STATUS_INVALID_PARAMETER );
+ release_object( job );
+ }
+}
diff --git a/server/protocol.def b/server/protocol.def
index cc39ef1..126c2a7 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -709,6 +709,12 @@ struct rawinput_device
unsigned int limit_flags;
@END
+@REQ(job_set_completion)
+ obj_handle_t handle;
+ obj_handle_t port;
+ client_ptr_t key;
+@END
+
/* Retrieve information about a newly started process */
@REQ(get_new_process_info)
obj_handle_t info; /* info handle returned from new_process_request */
--
2.3.0

View File

@ -1,3 +1,4 @@
Fixes: [33723] EA Origin needs support for job objects
Depends: kernel32-Console_Handles
Depends: server-OpenProcess
Depends: server-Misc_ACL