Jacek Caban : services: Support delayed autostart services.

Alexandre Julliard julliard at winehq.org
Thu Jun 20 16:04:19 CDT 2019


Module: wine
Branch: master
Commit: d8dec0b3f9da2daad55efd1a9f8fa99711b15635
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=d8dec0b3f9da2daad55efd1a9f8fa99711b15635

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Thu Jun 20 17:58:45 2019 +0200

services: Support delayed autostart services.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 programs/services/services.c | 116 ++++++++++++++++++++++++++++++++++++++++++-
 programs/services/services.h |   1 +
 2 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/programs/services/services.c b/programs/services/services.c
index 7ca249c..ff5c4cb 100644
--- a/programs/services/services.c
+++ b/programs/services/services.c
@@ -29,6 +29,7 @@
 #include <userenv.h>
 
 #include "wine/debug.h"
+#include "wine/heap.h"
 #include "svcctl.h"
 
 #include "services.h"
@@ -42,6 +43,7 @@ struct scmdatabase *active_database;
 DWORD service_pipe_timeout = 10000;
 DWORD service_kill_timeout = 60000;
 static DWORD default_preshutdown_timeout = 180000;
+static DWORD autostart_delay = 120000;
 static void *environment = NULL;
 static HKEY service_current_key = NULL;
 
@@ -68,6 +70,7 @@ static const WCHAR SZ_TAG[]               = {'T','a','g',0};
 static const WCHAR SZ_DESCRIPTION[]       = {'D','e','s','c','r','i','p','t','i','o','n',0};
 static const WCHAR SZ_PRESHUTDOWN[]       = {'P','r','e','s','h','u','t','d','o','w','n','T','i','m','e','o','u','t',0};
 static const WCHAR SZ_WOW64[]             = {'W','O','W','6','4',0};
+static const WCHAR SZ_DELAYED_AUTOSTART[] = {'D','e','l','a','y','e','d','A','u','t','o','S','t','a','r','t',0};
 
 static DWORD process_create(const WCHAR *name, struct process_entry **entry)
 {
@@ -186,6 +189,8 @@ static DWORD load_service_config(HKEY hKey, struct service_entry *entry)
 
     if (load_reg_dword(hKey, SZ_WOW64, &value) == 0 && value == 1)
         entry->is_wow64 = TRUE;
+    if (load_reg_dword(hKey, SZ_DELAYED_AUTOSTART, &value) == 0 && value == 1)
+        entry->delayed_autostart = TRUE;
 
     WINE_TRACE("Image path           = %s\n", wine_dbgstr_w(entry->config.lpBinaryPathName) );
     WINE_TRACE("Group                = %s\n", wine_dbgstr_w(entry->config.lpLoadOrderGroup) );
@@ -329,11 +334,101 @@ static int __cdecl compare_tags(const void *a, const void *b)
     return service_a->config.dwTagId - service_b->config.dwTagId;
 }
 
+static PTP_CLEANUP_GROUP delayed_autostart_cleanup;
+
+struct delayed_autostart_params
+{
+    unsigned int count;
+    struct service_entry **services;
+};
+
+static void CALLBACK delayed_autostart_cancel_callback(void *object, void *userdata)
+{
+    struct delayed_autostart_params *params = object;
+    while(params->count--)
+        release_service(params->services[params->count]);
+    heap_free(params->services);
+    heap_free(params);
+}
+
+static void CALLBACK delayed_autostart_callback(TP_CALLBACK_INSTANCE *instance, void *context,
+                                                 TP_WAIT *wait, TP_WAIT_RESULT result)
+{
+    struct delayed_autostart_params *params = context;
+    struct service_entry *service;
+    unsigned int i;
+    DWORD err;
+
+    if (result == WAIT_TIMEOUT)
+    {
+        scmdatabase_lock_startup(active_database, INFINITE);
+
+        for (i = 0; i < params->count; i++)
+        {
+            service = params->services[i];
+            if (service->status.dwCurrentState == SERVICE_STOPPED)
+            {
+                TRACE("Starting deleyed auto-start service %s\n", debugstr_w(service->name));
+                err = service_start(service, 0, NULL);
+                if (err != ERROR_SUCCESS)
+                    FIXME("Delayed auto-start service %s failed to start: %d\n",
+                          wine_dbgstr_w(service->name), err);
+            }
+            release_service(service);
+        }
+
+        scmdatabase_unlock_startup(active_database);
+    }
+
+    heap_free(params->services);
+    heap_free(params);
+    CloseThreadpoolWait(wait);
+}
+
+static BOOL schedule_delayed_autostart(struct service_entry **services, unsigned int count)
+{
+    struct delayed_autostart_params *params;
+    TP_CALLBACK_ENVIRON environment;
+    LARGE_INTEGER timestamp;
+    TP_WAIT *wait;
+    FILETIME ft;
+
+    if (!(delayed_autostart_cleanup = CreateThreadpoolCleanupGroup()))
+    {
+        ERR("CreateThreadpoolCleanupGroup failed with error %u\n", GetLastError());
+        return FALSE;
+    }
+
+    if (!(params = heap_alloc(sizeof(*params)))) return FALSE;
+    params->count = count;
+    params->services = services;
+
+    memset(&environment, 0, sizeof(environment));
+    environment.Version = 1;
+    environment.CleanupGroup = delayed_autostart_cleanup;
+    environment.CleanupGroupCancelCallback = delayed_autostart_cancel_callback;
+
+    timestamp.QuadPart = (ULONGLONG)autostart_delay * -10000;
+    ft.dwLowDateTime   = timestamp.u.LowPart;
+    ft.dwHighDateTime  = timestamp.u.HighPart;
+
+    if (!(wait = CreateThreadpoolWait(delayed_autostart_callback, params, &environment)))
+    {
+        ERR("CreateThreadpoolWait failed: %u\n", GetLastError());
+        heap_free(params);
+        return FALSE;
+    }
+
+    SetThreadpoolWait(wait, params, &ft);
+    return TRUE;
+}
+
 static void scmdatabase_autostart_services(struct scmdatabase *db)
 {
     struct service_entry **services_list;
     unsigned int i = 0;
     unsigned int size = 32;
+    unsigned int delayed_cnt = 0;
     struct service_entry *service;
 
     services_list = HeapAlloc(GetProcessHeap(), 0, size * sizeof(services_list[0]));
@@ -370,6 +465,12 @@ static void scmdatabase_autostart_services(struct scmdatabase *db)
     {
         DWORD err;
         service = services_list[i];
+        if (service->delayed_autostart)
+        {
+            TRACE("delayed starting %s\n", wine_dbgstr_w(service->name));
+            services_list[delayed_cnt++] = service;
+            continue;
+        }
         err = service_start(service, 0, NULL);
         if (err != ERROR_SUCCESS)
             WINE_FIXME("Auto-start service %s failed to start: %d\n",
@@ -378,7 +479,9 @@ static void scmdatabase_autostart_services(struct scmdatabase *db)
     }
 
     scmdatabase_unlock_startup(db);
-    HeapFree(GetProcessHeap(), 0, services_list);
+
+    if (!delayed_cnt || !schedule_delayed_autostart(services_list, delayed_cnt))
+        heap_free(services_list);
 }
 
 static void scmdatabase_wait_terminate(struct scmdatabase *db)
@@ -1115,6 +1218,8 @@ static void load_registry_parameters(void)
         {'S','e','r','v','i','c','e','s','P','i','p','e','T','i','m','e','o','u','t',0};
     static const WCHAR killtimeoutW[] =
         {'W','a','i','t','T','o','K','i','l','l','S','e','r','v','i','c','e','T','i','m','e','o','u','t',0};
+    static const WCHAR autostartdelayW[] =
+        {'A','u','t','o','S','t','a','r','t','D','e','l','a','y',0};
     HKEY key;
     WCHAR buffer[64];
     DWORD type, count, val;
@@ -1131,6 +1236,10 @@ static void load_registry_parameters(void)
         type == REG_SZ && (val = wcstol( buffer, NULL, 10 )))
         service_kill_timeout = val;
 
+    count = sizeof(val);
+    if (!RegQueryValueExW( key, autostartdelayW, NULL, &type, (BYTE *)&val, &count ) && type == REG_DWORD)
+        autostart_delay = val;
+
     RegCloseKey( key );
 }
 
@@ -1164,6 +1273,11 @@ int main(int argc, char *argv[])
         SetEvent(started_event);
         WaitForSingleObject(exit_event, INFINITE);
         scmdatabase_wait_terminate(active_database);
+        if (delayed_autostart_cleanup)
+        {
+            CloseThreadpoolCleanupGroupMembers(delayed_autostart_cleanup, TRUE, NULL);
+            CloseThreadpoolCleanupGroup(delayed_autostart_cleanup);
+        }
         RPC_Stop();
     }
     scmdatabase_destroy(active_database);
diff --git a/programs/services/services.h b/programs/services/services.h
index e1481d9..0d400e5 100644
--- a/programs/services/services.h
+++ b/programs/services/services.h
@@ -63,6 +63,7 @@ struct service_entry
     BOOL force_shutdown;
     BOOL marked_for_delete;
     BOOL is_wow64;
+    BOOL delayed_autostart;
     struct list handles;
 };
 




More information about the wine-cvs mailing list