server: Implement TerminateJobObject.
This commit is contained in:
parent
b413a4e202
commit
1d359a5827
|
@ -2255,13 +2255,11 @@ static void test_TerminateJobObject(void)
|
||||||
ok(ret, "TerminateJobObject error %u\n", GetLastError());
|
ok(ret, "TerminateJobObject error %u\n", GetLastError());
|
||||||
|
|
||||||
dwret = WaitForSingleObject(pi.hProcess, 1000);
|
dwret = WaitForSingleObject(pi.hProcess, 1000);
|
||||||
todo_wine
|
|
||||||
ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
|
ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
|
||||||
if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
|
if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
|
||||||
|
|
||||||
ret = GetExitCodeProcess(pi.hProcess, &dwret);
|
ret = GetExitCodeProcess(pi.hProcess, &dwret);
|
||||||
ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
|
ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
|
||||||
todo_wine
|
|
||||||
ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
|
ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
|
||||||
"wrong exitcode %u\n", dwret);
|
"wrong exitcode %u\n", dwret);
|
||||||
|
|
||||||
|
|
|
@ -613,8 +613,19 @@ NTSTATUS WINAPI NtOpenJobObject( PHANDLE handle, ACCESS_MASK access, const OBJEC
|
||||||
*/
|
*/
|
||||||
NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
|
NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
|
||||||
{
|
{
|
||||||
FIXME( "stub: %p %x\n", handle, status );
|
NTSTATUS ret;
|
||||||
return STATUS_SUCCESS;
|
|
||||||
|
TRACE( "(%p, %d)\n", handle, status );
|
||||||
|
|
||||||
|
SERVER_START_REQ( terminate_job )
|
||||||
|
{
|
||||||
|
req->handle = wine_server_obj_handle( handle );
|
||||||
|
req->status = status;
|
||||||
|
ret = wine_server_call( req );
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|
|
@ -5156,6 +5156,20 @@ struct set_job_completion_port_reply
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct terminate_job_request
|
||||||
|
{
|
||||||
|
struct request_header __header;
|
||||||
|
obj_handle_t handle;
|
||||||
|
int status;
|
||||||
|
char __pad_20[4];
|
||||||
|
};
|
||||||
|
struct terminate_job_reply
|
||||||
|
{
|
||||||
|
struct reply_header __header;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
enum request
|
enum request
|
||||||
{
|
{
|
||||||
REQ_new_process,
|
REQ_new_process,
|
||||||
|
@ -5419,6 +5433,7 @@ enum request
|
||||||
REQ_process_in_job,
|
REQ_process_in_job,
|
||||||
REQ_set_job_limits,
|
REQ_set_job_limits,
|
||||||
REQ_set_job_completion_port,
|
REQ_set_job_completion_port,
|
||||||
|
REQ_terminate_job,
|
||||||
REQ_NB_REQUESTS
|
REQ_NB_REQUESTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5687,6 +5702,7 @@ union generic_request
|
||||||
struct process_in_job_request process_in_job_request;
|
struct process_in_job_request process_in_job_request;
|
||||||
struct set_job_limits_request set_job_limits_request;
|
struct set_job_limits_request set_job_limits_request;
|
||||||
struct set_job_completion_port_request set_job_completion_port_request;
|
struct set_job_completion_port_request set_job_completion_port_request;
|
||||||
|
struct terminate_job_request terminate_job_request;
|
||||||
};
|
};
|
||||||
union generic_reply
|
union generic_reply
|
||||||
{
|
{
|
||||||
|
@ -5953,8 +5969,9 @@ union generic_reply
|
||||||
struct process_in_job_reply process_in_job_reply;
|
struct process_in_job_reply process_in_job_reply;
|
||||||
struct set_job_limits_reply set_job_limits_reply;
|
struct set_job_limits_reply set_job_limits_reply;
|
||||||
struct set_job_completion_port_reply set_job_completion_port_reply;
|
struct set_job_completion_port_reply set_job_completion_port_reply;
|
||||||
|
struct terminate_job_reply terminate_job_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 466
|
#define SERVER_PROTOCOL_VERSION 467
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -64,6 +64,7 @@ static int process_signaled( struct object *obj, struct wait_queue_entry *entry
|
||||||
static unsigned int process_map_access( struct object *obj, unsigned int access );
|
static unsigned int process_map_access( struct object *obj, unsigned int access );
|
||||||
static void process_poll_event( struct fd *fd, int event );
|
static void process_poll_event( struct fd *fd, int event );
|
||||||
static void process_destroy( struct object *obj );
|
static void process_destroy( struct object *obj );
|
||||||
|
static void terminate_process( struct process *process, struct thread *skip, int exit_code );
|
||||||
|
|
||||||
static const struct object_ops process_ops =
|
static const struct object_ops process_ops =
|
||||||
{
|
{
|
||||||
|
@ -147,6 +148,7 @@ struct job
|
||||||
struct list process_list; /* list of all processes */
|
struct list process_list; /* list of all processes */
|
||||||
int num_processes; /* count of running processes */
|
int num_processes; /* count of running processes */
|
||||||
unsigned int limit_flags; /* limit flags */
|
unsigned int limit_flags; /* limit flags */
|
||||||
|
int terminating; /* job is terminating */
|
||||||
struct completion *completion_port; /* associated completion port */
|
struct completion *completion_port; /* associated completion port */
|
||||||
apc_param_t completion_key; /* key to send with completion messages */
|
apc_param_t completion_key; /* key to send with completion messages */
|
||||||
};
|
};
|
||||||
|
@ -188,6 +190,7 @@ static struct job *create_job_object( struct directory *root, const struct unico
|
||||||
list_init( &job->process_list );
|
list_init( &job->process_list );
|
||||||
job->num_processes = 0;
|
job->num_processes = 0;
|
||||||
job->limit_flags = 0;
|
job->limit_flags = 0;
|
||||||
|
job->terminating = 0;
|
||||||
job->completion_port = NULL;
|
job->completion_port = NULL;
|
||||||
job->completion_key = 0;
|
job->completion_key = 0;
|
||||||
}
|
}
|
||||||
|
@ -251,12 +254,35 @@ static void release_job_process( struct process *process )
|
||||||
assert( job->num_processes );
|
assert( job->num_processes );
|
||||||
job->num_processes--;
|
job->num_processes--;
|
||||||
|
|
||||||
add_job_completion( job, JOB_OBJECT_MSG_EXIT_PROCESS, get_process_id(process) );
|
if (!job->terminating)
|
||||||
|
add_job_completion( job, JOB_OBJECT_MSG_EXIT_PROCESS, get_process_id(process) );
|
||||||
|
|
||||||
if (!job->num_processes)
|
if (!job->num_processes)
|
||||||
add_job_completion( job, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, 0 );
|
add_job_completion( job, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void terminate_job( struct job *job, int exit_code )
|
||||||
|
{
|
||||||
|
/* don't report completion events for terminated processes */
|
||||||
|
job->terminating = 1;
|
||||||
|
|
||||||
|
for (;;) /* restart from the beginning of the list every time */
|
||||||
|
{
|
||||||
|
struct process *process;
|
||||||
|
|
||||||
|
/* find the first process associated with this job and still running */
|
||||||
|
LIST_FOR_EACH_ENTRY( process, &job->process_list, struct process, job_entry )
|
||||||
|
{
|
||||||
|
if (process->running_threads) break;
|
||||||
|
}
|
||||||
|
if (&process->job_entry == &job->process_list) break; /* no process found */
|
||||||
|
assert( process->job == job );
|
||||||
|
terminate_process( process, NULL, exit_code );
|
||||||
|
}
|
||||||
|
|
||||||
|
job->terminating = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void job_destroy( struct object *obj )
|
static void job_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
struct job *job = (struct job *)obj;
|
struct job *job = (struct job *)obj;
|
||||||
|
@ -1543,6 +1569,17 @@ DECL_HANDLER(process_in_job)
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* terminate all processes associated with the job */
|
||||||
|
DECL_HANDLER(terminate_job)
|
||||||
|
{
|
||||||
|
struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_TERMINATE );
|
||||||
|
|
||||||
|
if (!job) return;
|
||||||
|
|
||||||
|
terminate_job( job, req->status );
|
||||||
|
release_object( job );
|
||||||
|
}
|
||||||
|
|
||||||
/* update limits of the job object */
|
/* update limits of the job object */
|
||||||
DECL_HANDLER(set_job_limits)
|
DECL_HANDLER(set_job_limits)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
struct atom_table;
|
struct atom_table;
|
||||||
struct handle_table;
|
struct handle_table;
|
||||||
struct startup_info;
|
struct startup_info;
|
||||||
|
struct job;
|
||||||
|
|
||||||
/* process startup state */
|
/* process startup state */
|
||||||
enum startup_state { STARTUP_IN_PROGRESS, STARTUP_DONE, STARTUP_ABORTED };
|
enum startup_state { STARTUP_IN_PROGRESS, STARTUP_DONE, STARTUP_ABORTED };
|
||||||
|
|
|
@ -3544,3 +3544,10 @@ enum coords_relative
|
||||||
obj_handle_t port; /* handle to the completion port */
|
obj_handle_t port; /* handle to the completion port */
|
||||||
client_ptr_t key; /* key to send with completion messages */
|
client_ptr_t key; /* key to send with completion messages */
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
||||||
|
/* Terminate all processes associated with the job */
|
||||||
|
@REQ(terminate_job)
|
||||||
|
obj_handle_t handle; /* handle to the job */
|
||||||
|
int status; /* process exit code */
|
||||||
|
@END
|
||||||
|
|
|
@ -367,6 +367,7 @@ DECL_HANDLER(assign_job);
|
||||||
DECL_HANDLER(process_in_job);
|
DECL_HANDLER(process_in_job);
|
||||||
DECL_HANDLER(set_job_limits);
|
DECL_HANDLER(set_job_limits);
|
||||||
DECL_HANDLER(set_job_completion_port);
|
DECL_HANDLER(set_job_completion_port);
|
||||||
|
DECL_HANDLER(terminate_job);
|
||||||
|
|
||||||
#ifdef WANT_REQUEST_HANDLERS
|
#ifdef WANT_REQUEST_HANDLERS
|
||||||
|
|
||||||
|
@ -634,6 +635,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
||||||
(req_handler)req_process_in_job,
|
(req_handler)req_process_in_job,
|
||||||
(req_handler)req_set_job_limits,
|
(req_handler)req_set_job_limits,
|
||||||
(req_handler)req_set_job_completion_port,
|
(req_handler)req_set_job_completion_port,
|
||||||
|
(req_handler)req_terminate_job,
|
||||||
};
|
};
|
||||||
|
|
||||||
C_ASSERT( sizeof(affinity_t) == 8 );
|
C_ASSERT( sizeof(affinity_t) == 8 );
|
||||||
|
@ -2233,6 +2235,9 @@ C_ASSERT( FIELD_OFFSET(struct set_job_completion_port_request, job) == 12 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct set_job_completion_port_request, port) == 16 );
|
C_ASSERT( FIELD_OFFSET(struct set_job_completion_port_request, port) == 16 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct set_job_completion_port_request, key) == 24 );
|
C_ASSERT( FIELD_OFFSET(struct set_job_completion_port_request, key) == 24 );
|
||||||
C_ASSERT( sizeof(struct set_job_completion_port_request) == 32 );
|
C_ASSERT( sizeof(struct set_job_completion_port_request) == 32 );
|
||||||
|
C_ASSERT( FIELD_OFFSET(struct terminate_job_request, handle) == 12 );
|
||||||
|
C_ASSERT( FIELD_OFFSET(struct terminate_job_request, status) == 16 );
|
||||||
|
C_ASSERT( sizeof(struct terminate_job_request) == 24 );
|
||||||
|
|
||||||
#endif /* WANT_REQUEST_HANDLERS */
|
#endif /* WANT_REQUEST_HANDLERS */
|
||||||
|
|
||||||
|
|
|
@ -4133,6 +4133,12 @@ static void dump_set_job_completion_port_request( const struct set_job_completio
|
||||||
dump_uint64( ", key=", &req->key );
|
dump_uint64( ", key=", &req->key );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_terminate_job_request( const struct terminate_job_request *req )
|
||||||
|
{
|
||||||
|
fprintf( stderr, " handle=%04x", req->handle );
|
||||||
|
fprintf( stderr, ", status=%d", req->status );
|
||||||
|
}
|
||||||
|
|
||||||
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_new_process_request,
|
(dump_func)dump_new_process_request,
|
||||||
(dump_func)dump_get_new_process_info_request,
|
(dump_func)dump_get_new_process_info_request,
|
||||||
|
@ -4395,6 +4401,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_process_in_job_request,
|
(dump_func)dump_process_in_job_request,
|
||||||
(dump_func)dump_set_job_limits_request,
|
(dump_func)dump_set_job_limits_request,
|
||||||
(dump_func)dump_set_job_completion_port_request,
|
(dump_func)dump_set_job_completion_port_request,
|
||||||
|
(dump_func)dump_terminate_job_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
|
@ -4659,6 +4666,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const req_names[REQ_NB_REQUESTS] = {
|
static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
|
@ -4923,6 +4931,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
"process_in_job",
|
"process_in_job",
|
||||||
"set_job_limits",
|
"set_job_limits",
|
||||||
"set_job_completion_port",
|
"set_job_completion_port",
|
||||||
|
"terminate_job",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct
|
static const struct
|
||||||
|
|
Loading…
Reference in New Issue