services: Support delayed autostart services.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4c750a35c3
commit
d8dec0b3f9
|
@ -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);
|
||||
|
|
|
@ -63,6 +63,7 @@ struct service_entry
|
|||
BOOL force_shutdown;
|
||||
BOOL marked_for_delete;
|
||||
BOOL is_wow64;
|
||||
BOOL delayed_autostart;
|
||||
struct list handles;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue