Commit 19bf03ed authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

ntdll: Add NtSuspendProcess()/NtResumeProcess() implementation.

parent c8b9aa00
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment