From 156b205eb527b57d6e9e9e859df77a42c2104603 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Wed, 6 Jun 2007 20:33:13 +0200
Subject: [PATCH] server: Add support for system processes, that can be
 signaled to exit when all non-system processes are done.

---
 dlls/ntdll/ntdll.spec          |  1 +
 dlls/ntdll/process.c           | 18 +++++++++++++++
 include/wine/server_protocol.h | 17 ++++++++++++++-
 server/process.c               | 40 ++++++++++++++++++++++++++++++++--
 server/process.h               |  1 +
 server/protocol.def            |  7 ++++++
 server/request.h               |  2 ++
 server/trace.c                 | 12 ++++++++++
 8 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 535f375c4a5..b2b0cc075c0 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -1380,6 +1380,7 @@
 @ cdecl wine_server_handle_to_fd(long long ptr ptr)
 @ cdecl wine_server_release_fd(long long)
 @ cdecl wine_server_send_fd(long)
+@ cdecl __wine_make_process_system()
 
 # Codepages
 @ cdecl __wine_init_codepages(ptr ptr ptr)
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 724c08182b5..b059c94b9c5 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -71,6 +71,24 @@ PEB * WINAPI RtlGetCurrentPeb(void)
     return NtCurrentTeb()->Peb;
 }
 
+/***********************************************************************
+ *           __wine_make_process_system   (NTDLL.@)
+ *
+ * Mark the current process as a system process.
+ * Returns the event that is signaled when all non-system processes have exited.
+ */
+HANDLE __wine_make_process_system(void)
+{
+    HANDLE ret = 0;
+    SERVER_START_REQ( make_process_system )
+    {
+        if (!wine_server_call( req )) ret = reply->event;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
 #define UNIMPLEMENTED_INFO_CLASS(c) \
     case c: \
         FIXME("(process=%p) Unimplemented information class: " #c "\n", ProcessHandle); \
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 6b703a1238a..56574b0fa30 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -4054,6 +4054,18 @@ struct get_next_device_request_reply
 };
 
 
+
+struct make_process_system_request
+{
+    struct request_header __header;
+};
+struct make_process_system_reply
+{
+    struct reply_header __header;
+    obj_handle_t event;
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -4275,6 +4287,7 @@ enum request
     REQ_create_device,
     REQ_delete_device,
     REQ_get_next_device_request,
+    REQ_make_process_system,
     REQ_NB_REQUESTS
 };
 
@@ -4501,6 +4514,7 @@ union generic_request
     struct create_device_request create_device_request;
     struct delete_device_request delete_device_request;
     struct get_next_device_request_request get_next_device_request_request;
+    struct make_process_system_request make_process_system_request;
 };
 union generic_reply
 {
@@ -4725,8 +4739,9 @@ union generic_reply
     struct create_device_reply create_device_reply;
     struct delete_device_reply delete_device_reply;
     struct get_next_device_request_reply get_next_device_request_reply;
+    struct make_process_system_reply make_process_system_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 305
+#define SERVER_PROTOCOL_VERSION 306
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/process.c b/server/process.c
index d733031d728..623d2ae9914 100644
--- a/server/process.c
+++ b/server/process.c
@@ -52,7 +52,8 @@
 /* process structure */
 
 static struct list process_list = LIST_INIT(process_list);
-static int running_processes;
+static int running_processes, user_processes;
+static struct event *user_process_event;  /* signaled when all user processes have exited */
 
 /* process operations */
 
@@ -224,6 +225,11 @@ static void set_process_startup_state( struct process *process, enum startup_sta
 static void process_died( struct process *process )
 {
     if (debug_level) fprintf( stderr, "%04x: *process killed*\n", process->id );
+    if (!process->is_system)
+    {
+        if (!--user_processes && user_process_event)
+            set_event( user_process_event );
+    }
     release_object( process );
     if (!--running_processes) close_master_socket();
 }
@@ -272,6 +278,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
     process->priority        = PROCESS_PRIOCLASS_NORMAL;
     process->affinity        = 1;
     process->suspend         = 0;
+    process->is_system       = 0;
     process->create_flags    = 0;
     process->console         = NULL;
     process->startup_state   = STARTUP_IN_PROGRESS;
@@ -616,7 +623,15 @@ static void process_killed( struct process *process )
 void add_process_thread( struct process *process, struct thread *thread )
 {
     list_add_tail( &process->thread_list, &thread->proc_entry );
-    if (!process->running_threads++) running_processes++;
+    if (!process->running_threads++)
+    {
+        running_processes++;
+        if (!process->is_system)
+        {
+            if (!user_processes++ && user_process_event)
+                reset_event( user_process_event );
+        }
+    }
     grab_object( thread );
 }
 
@@ -1143,3 +1158,24 @@ DECL_HANDLER(get_process_idle_event)
         release_object( process );
     }
 }
+
+/* make the current process a system process */
+DECL_HANDLER(make_process_system)
+{
+    struct process *process = current->process;
+
+    if (!user_process_event)
+    {
+        if (!(user_process_event = create_event( NULL, NULL, 0, 1, 0 ))) return;
+        make_object_static( (struct object *)user_process_event );
+    }
+
+    if (!(reply->event = alloc_handle( current->process, user_process_event, EVENT_ALL_ACCESS, 0 )))
+        return;
+
+    if (!process->is_system)
+    {
+        process->is_system = 1;
+        if (!--user_processes) set_event( user_process_event );
+    }
+}
diff --git a/server/process.h b/server/process.h
index b2a6849666d..30549433472 100644
--- a/server/process.h
+++ b/server/process.h
@@ -66,6 +66,7 @@ struct process
     int                  priority;        /* priority class */
     int                  affinity;        /* process affinity mask */
     int                  suspend;         /* global process suspend count */
+    int                  is_system;       /* is it a system process? */
     unsigned int         create_flags;    /* process creation flags */
     struct list          locks;           /* list of file locks owned by the process */
     struct list          classes;         /* window classes owned by the process */
diff --git a/server/protocol.def b/server/protocol.def
index 8a7e5a86b03..df6b8d3e4ce 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2912,3 +2912,10 @@ enum message_type
     data_size_t  out_size;        /* needed output size */
     VARARG(next_data,bytes);      /* input data of the next ioctl */
 @END
+
+
+/* Make the current process a system process */
+@REQ(make_process_system)
+@REPLY
+    obj_handle_t event;           /* event signaled when all user processes have exited */
+@END
diff --git a/server/request.h b/server/request.h
index 90a0c6c361f..10b6cbe8f55 100644
--- a/server/request.h
+++ b/server/request.h
@@ -329,6 +329,7 @@ DECL_HANDLER(create_device_manager);
 DECL_HANDLER(create_device);
 DECL_HANDLER(delete_device);
 DECL_HANDLER(get_next_device_request);
+DECL_HANDLER(make_process_system);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -554,6 +555,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_create_device,
     (req_handler)req_delete_device,
     (req_handler)req_get_next_device_request,
+    (req_handler)req_make_process_system,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index a340bade55c..312b68de0c8 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3530,6 +3530,15 @@ static void dump_get_next_device_request_reply( const struct get_next_device_req
     dump_varargs_bytes( cur_size );
 }
 
+static void dump_make_process_system_request( const struct make_process_system_request *req )
+{
+}
+
+static void dump_make_process_system_reply( const struct make_process_system_reply *req )
+{
+    fprintf( stderr, " event=%p", req->event );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -3750,6 +3759,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_create_device_request,
     (dump_func)dump_delete_device_request,
     (dump_func)dump_get_next_device_request_request,
+    (dump_func)dump_make_process_system_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -3972,6 +3982,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_create_device_reply,
     (dump_func)0,
     (dump_func)dump_get_next_device_request_reply,
+    (dump_func)dump_make_process_system_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -4194,6 +4205,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "create_device",
     "delete_device",
     "get_next_device_request",
+    "make_process_system",
 };
 
 static const struct
-- 
GitLab