ntdll: Add NtSuspendProcess()/NtResumeProcess() implementation.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c8b9aa00c6
commit
19bf03ed4b
|
@ -763,8 +763,16 @@ NTSTATUS WINAPI NtOpenProcess(PHANDLE handle, ACCESS_MASK access,
|
|||
*/
|
||||
NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
|
||||
{
|
||||
FIXME("stub: %p\n", handle);
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
NTSTATUS ret;
|
||||
|
||||
SERVER_START_REQ( resume_process )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
ret = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -773,8 +781,16 @@ NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
|
|||
*/
|
||||
NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
|
||||
{
|
||||
FIXME("stub: %p\n", handle);
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
NTSTATUS ret;
|
||||
|
||||
SERVER_START_REQ( suspend_process )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
ret = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS,
|
|||
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
|
||||
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
||||
static NTSTATUS (WINAPI *pNtClose)(HANDLE);
|
||||
static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process);
|
||||
static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
typedef struct
|
||||
|
@ -158,6 +160,9 @@ static VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, C
|
|||
static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
|
||||
#endif
|
||||
|
||||
static int my_argc;
|
||||
static char** my_argv;
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#ifndef __WINE_WINTRNL_H
|
||||
|
@ -167,8 +172,6 @@ static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
|
|||
#define MEM_EXECUTE_OPTION_PERMANENT 0x08
|
||||
#endif
|
||||
|
||||
static int my_argc;
|
||||
static char** my_argv;
|
||||
static int test_stage;
|
||||
|
||||
static BOOL is_wow64;
|
||||
|
@ -3190,6 +3193,138 @@ static void test_suspend_thread(void)
|
|||
CloseHandle(thread);
|
||||
}
|
||||
|
||||
static const char *suspend_process_event_name = "suspend_process_event";
|
||||
static const char *suspend_process_event2_name = "suspend_process_event2";
|
||||
|
||||
static DWORD WINAPI dummy_thread_proc( void *arg )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void suspend_process_proc(void)
|
||||
{
|
||||
HANDLE event = OpenEventA(SYNCHRONIZE, FALSE, suspend_process_event_name);
|
||||
HANDLE event2 = OpenEventA(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, suspend_process_event2_name);
|
||||
unsigned int count;
|
||||
NTSTATUS status;
|
||||
HANDLE thread;
|
||||
|
||||
ok(event != NULL, "Failed to open event handle.\n");
|
||||
ok(event2 != NULL, "Failed to open event handle.\n");
|
||||
|
||||
thread = CreateThread(NULL, 0, dummy_thread_proc, 0, CREATE_SUSPENDED, NULL);
|
||||
ok(thread != NULL, "Failed to create auxiliary thread.\n");
|
||||
|
||||
/* Suspend up to limit. */
|
||||
while (!(status = NtSuspendThread(thread, NULL)))
|
||||
;
|
||||
ok(status == STATUS_SUSPEND_COUNT_EXCEEDED, "Unexpected status %#x.\n", status);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
SetEvent(event2);
|
||||
if (WaitForSingleObject(event, 100) == WAIT_OBJECT_0)
|
||||
break;
|
||||
}
|
||||
|
||||
status = NtSuspendThread(thread, &count);
|
||||
ok(!status, "Failed to suspend a thread, status %#x.\n", status);
|
||||
ok(count == 125, "Unexpected suspend count %u.\n", count);
|
||||
|
||||
status = NtResumeThread(thread, NULL);
|
||||
ok(!status, "Failed to resume a thread, status %#x.\n", status);
|
||||
|
||||
CloseHandle(event);
|
||||
CloseHandle(event2);
|
||||
}
|
||||
|
||||
static void test_suspend_process(void)
|
||||
{
|
||||
PROCESS_INFORMATION info;
|
||||
char path_name[MAX_PATH];
|
||||
STARTUPINFOA startup;
|
||||
HANDLE event, event2;
|
||||
NTSTATUS status;
|
||||
char **argv;
|
||||
DWORD ret;
|
||||
|
||||
event = CreateEventA(NULL, FALSE, FALSE, suspend_process_event_name);
|
||||
ok(event != NULL, "Failed to create event.\n");
|
||||
|
||||
event2 = CreateEventA(NULL, FALSE, FALSE, suspend_process_event2_name);
|
||||
ok(event2 != NULL, "Failed to create event.\n");
|
||||
|
||||
winetest_get_mainargs(&argv);
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
sprintf(path_name, "%s exception suspend_process", argv[0]);
|
||||
|
||||
ret = CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info),
|
||||
ok(ret, "Failed to create target process.\n");
|
||||
|
||||
/* New process signals this event. */
|
||||
ResetEvent(event2);
|
||||
ret = WaitForSingleObject(event2, INFINITE);
|
||||
ok(ret == WAIT_OBJECT_0, "Wait failed, %#x.\n", ret);
|
||||
|
||||
/* Suspend main thread */
|
||||
status = NtSuspendThread(info.hThread, &ret);
|
||||
ok(!status && !ret, "Failed to suspend main thread, status %#x.\n", status);
|
||||
|
||||
/* Process wasn't suspended yet. */
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(!status, "Failed to resume a process, status %#x.\n", status);
|
||||
|
||||
status = pNtSuspendProcess(0);
|
||||
ok(status == STATUS_INVALID_HANDLE, "Unexpected status %#x.\n", status);
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(!status, "Failed to resume a process, status %#x.\n", status);
|
||||
|
||||
ResetEvent(event2);
|
||||
ret = WaitForSingleObject(event2, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Wait failed.\n");
|
||||
|
||||
status = pNtSuspendProcess(info.hProcess);
|
||||
ok(!status, "Failed to suspend a process, status %#x.\n", status);
|
||||
|
||||
status = NtSuspendThread(info.hThread, &ret);
|
||||
ok(!status && ret == 1, "Failed to suspend main thread, status %#x.\n", status);
|
||||
status = NtResumeThread(info.hThread, &ret);
|
||||
ok(!status && ret == 2, "Failed to resume main thread, status %#x.\n", status);
|
||||
|
||||
ResetEvent(event2);
|
||||
ret = WaitForSingleObject(event2, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Wait failed.\n");
|
||||
|
||||
status = pNtSuspendProcess(info.hProcess);
|
||||
ok(!status, "Failed to suspend a process, status %#x.\n", status);
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(!status, "Failed to resume a process, status %#x.\n", status);
|
||||
|
||||
ResetEvent(event2);
|
||||
ret = WaitForSingleObject(event2, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Wait failed.\n");
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(!status, "Failed to resume a process, status %#x.\n", status);
|
||||
|
||||
ResetEvent(event2);
|
||||
ret = WaitForSingleObject(event2, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Wait failed.\n");
|
||||
|
||||
SetEvent(event);
|
||||
|
||||
winetest_wait_child_process(info.hProcess);
|
||||
|
||||
CloseHandle(info.hProcess);
|
||||
CloseHandle(info.hThread);
|
||||
|
||||
CloseHandle(event);
|
||||
CloseHandle(event2);
|
||||
}
|
||||
|
||||
START_TEST(exception)
|
||||
{
|
||||
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
|
||||
|
@ -3197,6 +3332,14 @@ START_TEST(exception)
|
|||
HMODULE hmsvcrt = LoadLibraryA("msvcrt.dll");
|
||||
#endif
|
||||
|
||||
my_argc = winetest_get_mainargs( &my_argv );
|
||||
|
||||
if (my_argc >= 3 && !strcmp(my_argv[2], "suspend_process"))
|
||||
{
|
||||
suspend_process_proc();
|
||||
return;
|
||||
}
|
||||
|
||||
code_mem = VirtualAlloc(NULL, 65536, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if(!code_mem) {
|
||||
trace("VirtualAlloc failed\n");
|
||||
|
@ -3224,6 +3367,8 @@ START_TEST(exception)
|
|||
pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
|
||||
"NtSetInformationProcess" );
|
||||
pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
|
||||
pNtSuspendProcess = (void *)GetProcAddress( hntdll, "NtSuspendProcess" );
|
||||
pNtResumeProcess = (void *)GetProcAddress( hntdll, "NtResumeProcess" );
|
||||
|
||||
#ifdef __i386__
|
||||
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
|
||||
|
@ -3309,6 +3454,7 @@ START_TEST(exception)
|
|||
test_prot_fault();
|
||||
test_thread_context();
|
||||
test_suspend_thread();
|
||||
test_suspend_process();
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
|
||||
|
@ -3351,6 +3497,7 @@ START_TEST(exception)
|
|||
test_dpe_exceptions();
|
||||
test_wow64_context();
|
||||
test_suspend_thread();
|
||||
test_suspend_process();
|
||||
|
||||
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
|
||||
test_dynamic_unwind();
|
||||
|
|
|
@ -5742,6 +5742,30 @@ struct terminate_job_reply
|
|||
};
|
||||
|
||||
|
||||
|
||||
struct suspend_process_request
|
||||
{
|
||||
struct request_header __header;
|
||||
obj_handle_t handle;
|
||||
};
|
||||
struct suspend_process_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct resume_process_request
|
||||
{
|
||||
struct request_header __header;
|
||||
obj_handle_t handle;
|
||||
};
|
||||
struct resume_process_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
};
|
||||
|
||||
|
||||
enum request
|
||||
{
|
||||
REQ_new_process,
|
||||
|
@ -6040,6 +6064,8 @@ enum request
|
|||
REQ_set_job_limits,
|
||||
REQ_set_job_completion_port,
|
||||
REQ_terminate_job,
|
||||
REQ_suspend_process,
|
||||
REQ_resume_process,
|
||||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
|
@ -6343,6 +6369,8 @@ union generic_request
|
|||
struct set_job_limits_request set_job_limits_request;
|
||||
struct set_job_completion_port_request set_job_completion_port_request;
|
||||
struct terminate_job_request terminate_job_request;
|
||||
struct suspend_process_request suspend_process_request;
|
||||
struct resume_process_request resume_process_request;
|
||||
};
|
||||
union generic_reply
|
||||
{
|
||||
|
@ -6644,8 +6672,10 @@ union generic_reply
|
|||
struct set_job_limits_reply set_job_limits_reply;
|
||||
struct set_job_completion_port_reply set_job_completion_port_reply;
|
||||
struct terminate_job_reply terminate_job_reply;
|
||||
struct suspend_process_reply suspend_process_reply;
|
||||
struct resume_process_reply resume_process_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 578
|
||||
#define SERVER_PROTOCOL_VERSION 579
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -1705,3 +1705,41 @@ DECL_HANDLER(set_job_completion_port)
|
|||
|
||||
release_object( job );
|
||||
}
|
||||
|
||||
/* Suspend a process */
|
||||
DECL_HANDLER(suspend_process)
|
||||
{
|
||||
struct process *process;
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_SUSPEND_RESUME )))
|
||||
{
|
||||
struct list *ptr, *next;
|
||||
|
||||
LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list )
|
||||
{
|
||||
struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry );
|
||||
suspend_thread( thread );
|
||||
}
|
||||
|
||||
release_object( process );
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume a process */
|
||||
DECL_HANDLER(resume_process)
|
||||
{
|
||||
struct process *process;
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_SUSPEND_RESUME )))
|
||||
{
|
||||
struct list *ptr, *next;
|
||||
|
||||
LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list )
|
||||
{
|
||||
struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry );
|
||||
resume_thread( thread );
|
||||
}
|
||||
|
||||
release_object( process );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3909,3 +3909,15 @@ struct handle_info
|
|||
obj_handle_t handle; /* handle to the job */
|
||||
int status; /* process exit code */
|
||||
@END
|
||||
|
||||
|
||||
/* Suspend a process */
|
||||
@REQ(suspend_process)
|
||||
obj_handle_t handle; /* process handle */
|
||||
@END
|
||||
|
||||
|
||||
/* Resume a process */
|
||||
@REQ(resume_process)
|
||||
obj_handle_t handle; /* process handle */
|
||||
@END
|
||||
|
|
|
@ -408,6 +408,8 @@ DECL_HANDLER(process_in_job);
|
|||
DECL_HANDLER(set_job_limits);
|
||||
DECL_HANDLER(set_job_completion_port);
|
||||
DECL_HANDLER(terminate_job);
|
||||
DECL_HANDLER(suspend_process);
|
||||
DECL_HANDLER(resume_process);
|
||||
|
||||
#ifdef WANT_REQUEST_HANDLERS
|
||||
|
||||
|
@ -710,6 +712,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_set_job_limits,
|
||||
(req_handler)req_set_job_completion_port,
|
||||
(req_handler)req_terminate_job,
|
||||
(req_handler)req_suspend_process,
|
||||
(req_handler)req_resume_process,
|
||||
};
|
||||
|
||||
C_ASSERT( sizeof(affinity_t) == 8 );
|
||||
|
@ -2436,6 +2440,10 @@ 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 );
|
||||
C_ASSERT( FIELD_OFFSET(struct suspend_process_request, handle) == 12 );
|
||||
C_ASSERT( sizeof(struct suspend_process_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct resume_process_request, handle) == 12 );
|
||||
C_ASSERT( sizeof(struct resume_process_request) == 16 );
|
||||
|
||||
#endif /* WANT_REQUEST_HANDLERS */
|
||||
|
||||
|
|
|
@ -570,7 +570,7 @@ void stop_thread_if_suspended( struct thread *thread )
|
|||
}
|
||||
|
||||
/* suspend a thread */
|
||||
static int suspend_thread( struct thread *thread )
|
||||
int suspend_thread( struct thread *thread )
|
||||
{
|
||||
int old_count = thread->suspend;
|
||||
if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
|
||||
|
@ -582,7 +582,7 @@ static int suspend_thread( struct thread *thread )
|
|||
}
|
||||
|
||||
/* resume a thread */
|
||||
static int resume_thread( struct thread *thread )
|
||||
int resume_thread( struct thread *thread )
|
||||
{
|
||||
int old_count = thread->suspend;
|
||||
if (thread->suspend > 0)
|
||||
|
|
|
@ -131,6 +131,8 @@ extern struct token *thread_get_impersonation_token( struct thread *thread );
|
|||
extern int set_thread_affinity( struct thread *thread, affinity_t affinity );
|
||||
extern int is_cpu_supported( enum cpu_type cpu );
|
||||
extern unsigned int get_supported_cpu_mask(void);
|
||||
extern int suspend_thread( struct thread *thread );
|
||||
extern int resume_thread( struct thread *thread );
|
||||
|
||||
/* ptrace functions */
|
||||
|
||||
|
|
|
@ -4582,6 +4582,16 @@ static void dump_terminate_job_request( const struct terminate_job_request *req
|
|||
fprintf( stderr, ", status=%d", req->status );
|
||||
}
|
||||
|
||||
static void dump_suspend_process_request( const struct suspend_process_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%04x", req->handle );
|
||||
}
|
||||
|
||||
static void dump_resume_process_request( const struct resume_process_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%04x", req->handle );
|
||||
}
|
||||
|
||||
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||
(dump_func)dump_new_process_request,
|
||||
(dump_func)dump_exec_process_request,
|
||||
|
@ -4879,6 +4889,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_set_job_limits_request,
|
||||
(dump_func)dump_set_job_completion_port_request,
|
||||
(dump_func)dump_terminate_job_request,
|
||||
(dump_func)dump_suspend_process_request,
|
||||
(dump_func)dump_resume_process_request,
|
||||
};
|
||||
|
||||
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||
|
@ -5178,6 +5190,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||
|
@ -5477,6 +5491,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"set_job_limits",
|
||||
"set_job_completion_port",
|
||||
"terminate_job",
|
||||
"suspend_process",
|
||||
"resume_process",
|
||||
};
|
||||
|
||||
static const struct
|
||||
|
|
Loading…
Reference in New Issue