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, ...@@ -763,8 +763,16 @@ NTSTATUS WINAPI NtOpenProcess(PHANDLE handle, ACCESS_MASK access,
*/ */
NTSTATUS WINAPI NtResumeProcess( HANDLE handle ) NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
{ {
FIXME("stub: %p\n", handle); NTSTATUS ret;
return STATUS_NOT_IMPLEMENTED;
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 ) ...@@ -773,8 +781,16 @@ NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
*/ */
NTSTATUS WINAPI NtSuspendProcess( HANDLE handle ) NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
{ {
FIXME("stub: %p\n", handle); NTSTATUS ret;
return STATUS_NOT_IMPLEMENTED;
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, ...@@ -53,6 +53,8 @@ static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS,
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
static NTSTATUS (WINAPI *pNtClose)(HANDLE); static NTSTATUS (WINAPI *pNtClose)(HANDLE);
static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process);
static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process);
#if defined(__x86_64__) #if defined(__x86_64__)
typedef struct typedef struct
...@@ -158,6 +160,9 @@ static VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, C ...@@ -158,6 +160,9 @@ static VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, C
static int (CDECL *p_setjmp)(_JUMP_BUFFER*); static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
#endif #endif
static int my_argc;
static char** my_argv;
#ifdef __i386__ #ifdef __i386__
#ifndef __WINE_WINTRNL_H #ifndef __WINE_WINTRNL_H
...@@ -167,8 +172,6 @@ static int (CDECL *p_setjmp)(_JUMP_BUFFER*); ...@@ -167,8 +172,6 @@ static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
#define MEM_EXECUTE_OPTION_PERMANENT 0x08 #define MEM_EXECUTE_OPTION_PERMANENT 0x08
#endif #endif
static int my_argc;
static char** my_argv;
static int test_stage; static int test_stage;
static BOOL is_wow64; static BOOL is_wow64;
...@@ -3190,6 +3193,138 @@ static void test_suspend_thread(void) ...@@ -3190,6 +3193,138 @@ static void test_suspend_thread(void)
CloseHandle(thread); 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) START_TEST(exception)
{ {
HMODULE hntdll = GetModuleHandleA("ntdll.dll"); HMODULE hntdll = GetModuleHandleA("ntdll.dll");
...@@ -3197,6 +3332,14 @@ START_TEST(exception) ...@@ -3197,6 +3332,14 @@ START_TEST(exception)
HMODULE hmsvcrt = LoadLibraryA("msvcrt.dll"); HMODULE hmsvcrt = LoadLibraryA("msvcrt.dll");
#endif #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); code_mem = VirtualAlloc(NULL, 65536, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(!code_mem) { if(!code_mem) {
trace("VirtualAlloc failed\n"); trace("VirtualAlloc failed\n");
...@@ -3224,6 +3367,8 @@ START_TEST(exception) ...@@ -3224,6 +3367,8 @@ START_TEST(exception)
pNtSetInformationProcess = (void*)GetProcAddress( hntdll, pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
"NtSetInformationProcess" ); "NtSetInformationProcess" );
pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
pNtSuspendProcess = (void *)GetProcAddress( hntdll, "NtSuspendProcess" );
pNtResumeProcess = (void *)GetProcAddress( hntdll, "NtResumeProcess" );
#ifdef __i386__ #ifdef __i386__
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
...@@ -3309,6 +3454,7 @@ START_TEST(exception) ...@@ -3309,6 +3454,7 @@ START_TEST(exception)
test_prot_fault(); test_prot_fault();
test_thread_context(); test_thread_context();
test_suspend_thread(); test_suspend_thread();
test_suspend_process();
#elif defined(__x86_64__) #elif defined(__x86_64__)
pRtlAddFunctionTable = (void *)GetProcAddress( hntdll, pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
...@@ -3351,6 +3497,7 @@ START_TEST(exception) ...@@ -3351,6 +3497,7 @@ START_TEST(exception)
test_dpe_exceptions(); test_dpe_exceptions();
test_wow64_context(); test_wow64_context();
test_suspend_thread(); test_suspend_thread();
test_suspend_process();
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry) if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
test_dynamic_unwind(); test_dynamic_unwind();
......
...@@ -5742,6 +5742,30 @@ struct terminate_job_reply ...@@ -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 enum request
{ {
REQ_new_process, REQ_new_process,
...@@ -6040,6 +6064,8 @@ enum request ...@@ -6040,6 +6064,8 @@ enum request
REQ_set_job_limits, REQ_set_job_limits,
REQ_set_job_completion_port, REQ_set_job_completion_port,
REQ_terminate_job, REQ_terminate_job,
REQ_suspend_process,
REQ_resume_process,
REQ_NB_REQUESTS REQ_NB_REQUESTS
}; };
...@@ -6343,6 +6369,8 @@ union generic_request ...@@ -6343,6 +6369,8 @@ union generic_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; struct terminate_job_request terminate_job_request;
struct suspend_process_request suspend_process_request;
struct resume_process_request resume_process_request;
}; };
union generic_reply union generic_reply
{ {
...@@ -6644,8 +6672,10 @@ union generic_reply ...@@ -6644,8 +6672,10 @@ union generic_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; 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 */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -1705,3 +1705,41 @@ DECL_HANDLER(set_job_completion_port) ...@@ -1705,3 +1705,41 @@ DECL_HANDLER(set_job_completion_port)
release_object( job ); 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 ...@@ -3909,3 +3909,15 @@ struct handle_info
obj_handle_t handle; /* handle to the job */ obj_handle_t handle; /* handle to the job */
int status; /* process exit code */ int status; /* process exit code */
@END @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); ...@@ -408,6 +408,8 @@ 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); DECL_HANDLER(terminate_job);
DECL_HANDLER(suspend_process);
DECL_HANDLER(resume_process);
#ifdef WANT_REQUEST_HANDLERS #ifdef WANT_REQUEST_HANDLERS
...@@ -710,6 +712,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -710,6 +712,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(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, (req_handler)req_terminate_job,
(req_handler)req_suspend_process,
(req_handler)req_resume_process,
}; };
C_ASSERT( sizeof(affinity_t) == 8 ); C_ASSERT( sizeof(affinity_t) == 8 );
...@@ -2436,6 +2440,10 @@ C_ASSERT( sizeof(struct set_job_completion_port_request) == 32 ); ...@@ -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, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct terminate_job_request, status) == 16 ); C_ASSERT( FIELD_OFFSET(struct terminate_job_request, status) == 16 );
C_ASSERT( sizeof(struct terminate_job_request) == 24 ); 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 */ #endif /* WANT_REQUEST_HANDLERS */
......
...@@ -570,7 +570,7 @@ void stop_thread_if_suspended( struct thread *thread ) ...@@ -570,7 +570,7 @@ void stop_thread_if_suspended( struct thread *thread )
} }
/* suspend a thread */ /* suspend a thread */
static int suspend_thread( struct thread *thread ) int suspend_thread( struct thread *thread )
{ {
int old_count = thread->suspend; int old_count = thread->suspend;
if (thread->suspend < MAXIMUM_SUSPEND_COUNT) if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
...@@ -582,7 +582,7 @@ static int suspend_thread( struct thread *thread ) ...@@ -582,7 +582,7 @@ static int suspend_thread( struct thread *thread )
} }
/* resume a thread */ /* resume a thread */
static int resume_thread( struct thread *thread ) int resume_thread( struct thread *thread )
{ {
int old_count = thread->suspend; int old_count = thread->suspend;
if (thread->suspend > 0) if (thread->suspend > 0)
......
...@@ -131,6 +131,8 @@ extern struct token *thread_get_impersonation_token( struct thread *thread ); ...@@ -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 set_thread_affinity( struct thread *thread, affinity_t affinity );
extern int is_cpu_supported( enum cpu_type cpu ); extern int is_cpu_supported( enum cpu_type cpu );
extern unsigned int get_supported_cpu_mask(void); extern unsigned int get_supported_cpu_mask(void);
extern int suspend_thread( struct thread *thread );
extern int resume_thread( struct thread *thread );
/* ptrace functions */ /* ptrace functions */
......
...@@ -4582,6 +4582,16 @@ static void dump_terminate_job_request( const struct terminate_job_request *req ...@@ -4582,6 +4582,16 @@ static void dump_terminate_job_request( const struct terminate_job_request *req
fprintf( stderr, ", status=%d", req->status ); 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] = { static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request, (dump_func)dump_new_process_request,
(dump_func)dump_exec_process_request, (dump_func)dump_exec_process_request,
...@@ -4879,6 +4889,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -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_limits_request,
(dump_func)dump_set_job_completion_port_request, (dump_func)dump_set_job_completion_port_request,
(dump_func)dump_terminate_job_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] = { static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
...@@ -5178,6 +5190,8 @@ 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, NULL,
NULL,
NULL,
}; };
static const char * const req_names[REQ_NB_REQUESTS] = { static const char * const req_names[REQ_NB_REQUESTS] = {
...@@ -5477,6 +5491,8 @@ 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_limits",
"set_job_completion_port", "set_job_completion_port",
"terminate_job", "terminate_job",
"suspend_process",
"resume_process",
}; };
static const struct 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