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