[v2 PATCH 2/2] ntdll: Add NtSuspendProcess()/NtResumeProcess() implementation.

Nikolay Sivov nsivov at codeweavers.com
Fri Apr 12 02:00:31 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ntdll/process.c           |  24 +++++--
 dlls/ntdll/tests/exception.c   | 116 ++++++++++++++++++++++++++++++++-
 include/wine/server_protocol.h |  32 ++++++++-
 server/process.c               |  25 +++++++
 server/protocol.def            |  12 ++++
 server/request.h               |   8 +++
 server/trace.c                 |  16 +++++
 7 files changed, 225 insertions(+), 8 deletions(-)

diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 6c6c427372..573a7a771d 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -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;
 }
 
 
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index c79fb8eb8d..95dff4fed5 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -55,6 +55,8 @@ static BOOL      (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
 static NTSTATUS  (WINAPI *pNtClose)(HANDLE);
 static NTSTATUS  (WINAPI *pNtSuspendThread)(HANDLE thread, ULONG *count);
 static NTSTATUS  (WINAPI *pNtResumeThread)(HANDLE thread, ULONG *count);
+static NTSTATUS  (WINAPI *pNtSuspendProcess)(HANDLE process);
+static NTSTATUS  (WINAPI *pNtResumeProcess)(HANDLE process);
 
 #if defined(__x86_64__)
 typedef struct
@@ -160,6 +162,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
@@ -169,8 +174,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;
@@ -3192,6 +3195,102 @@ 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 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);
+
+    ok(event != NULL, "Failed to open event handle.\n");
+    ok(event2 != NULL, "Failed to open event handle.\n");
+
+    for (;;)
+    {
+        SetEvent(event2);
+        if (WaitForSingleObject(event, 100) == WAIT_OBJECT_0)
+            break;
+    }
+
+    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);
+
+    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);
+
+    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");
@@ -3199,6 +3298,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");
@@ -3228,6 +3335,8 @@ START_TEST(exception)
     pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
     pNtSuspendThread = (void *)GetProcAddress( hntdll, "NtSuspendThread" );
     pNtResumeThread = (void *)GetProcAddress( hntdll, "NtResumeThread" );
+    pNtSuspendProcess = (void *)GetProcAddress( hntdll, "NtSuspendProcess" );
+    pNtResumeProcess = (void *)GetProcAddress( hntdll, "NtResumeProcess" );
 
 #ifdef __i386__
     if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
@@ -3237,7 +3346,6 @@ START_TEST(exception)
     else
         skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n");
 
-    my_argc = winetest_get_mainargs( &my_argv );
     if (my_argc >= 4)
     {
         void *addr;
@@ -3313,6 +3421,7 @@ START_TEST(exception)
     test_prot_fault();
     test_thread_context();
     test_suspend_thread();
+    test_suspend_process();
 
 #elif defined(__x86_64__)
     pRtlAddFunctionTable               = (void *)GetProcAddress( hntdll,
@@ -3355,6 +3464,7 @@ START_TEST(exception)
     test_dpe_exceptions();
     test_wow64_context();
     test_suspend_thread();
+    test_suspend_process();
 
     if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
       test_dynamic_unwind();
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 88b933cc14..c3d1bb6a59 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -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 */
diff --git a/server/process.c b/server/process.c
index 473d3b1a27..9e3953dc59 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1705,3 +1705,28 @@ 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 )))
+    {
+        suspend_process( process );
+        release_object( process );
+    }
+}
+
+/* resume a process */
+DECL_HANDLER(resume_process)
+{
+    struct process *process;
+
+    if ((process = get_process_from_handle( req->handle, PROCESS_SUSPEND_RESUME )))
+    {
+        if (process->suspend > 0)
+            resume_process( process );
+        release_object( process );
+    }
+}
diff --git a/server/protocol.def b/server/protocol.def
index b6ad514463..8a3ca0a28f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3909,3 +3909,15 @@ struct handle_info
     obj_handle_t handle;          /* handle to the job */
     int          status;          /* process exit code */
 @END
+
+
+/* Suspend a process */
+ at REQ(suspend_process)
+    obj_handle_t handle;          /* process handle */
+ at END
+
+
+/* Resume a process */
+ at REQ(resume_process)
+    obj_handle_t handle;          /* process handle */
+ at END
diff --git a/server/request.h b/server/request.h
index a3e95137e1..a21252c7a6 100644
--- a/server/request.h
+++ b/server/request.h
@@ -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 */
 
diff --git a/server/trace.c b/server/trace.c
index d4d0c3eb8d..5c6325a257 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -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
-- 
2.20.1




More information about the wine-devel mailing list