services: Kill service thread after timeout so it can terminate cleanly.
This commit is contained in:
parent
8ebf0a72c9
commit
522bc15b45
|
@ -84,6 +84,53 @@ struct sc_lock
|
||||||
struct scmdatabase *db;
|
struct scmdatabase *db;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static HANDLE timeout_queue_event;
|
||||||
|
static CRITICAL_SECTION timeout_queue_cs;
|
||||||
|
static CRITICAL_SECTION_DEBUG timeout_queue_cs_debug =
|
||||||
|
{
|
||||||
|
0, 0, &timeout_queue_cs,
|
||||||
|
{ &timeout_queue_cs_debug.ProcessLocksList, &timeout_queue_cs_debug.ProcessLocksList },
|
||||||
|
0, 0, { (DWORD_PTR)(__FILE__ ": timeout_queue_cs") }
|
||||||
|
};
|
||||||
|
static CRITICAL_SECTION timeout_queue_cs = { &timeout_queue_cs_debug, -1, 0, 0, 0, 0 };
|
||||||
|
static struct list timeout_queue = LIST_INIT(timeout_queue);
|
||||||
|
struct timeout_queue_elem
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
|
||||||
|
FILETIME time;
|
||||||
|
void (*func)(struct service_entry*);
|
||||||
|
struct service_entry *service_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void run_after_timeout(void (*func)(struct service_entry*), struct service_entry *service, DWORD timeout)
|
||||||
|
{
|
||||||
|
struct timeout_queue_elem *elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct timeout_queue_elem));
|
||||||
|
ULARGE_INTEGER time;
|
||||||
|
|
||||||
|
if(!elem) {
|
||||||
|
func(service);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
service->ref_count++;
|
||||||
|
elem->func = func;
|
||||||
|
elem->service_entry = service;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime(&elem->time);
|
||||||
|
time.LowPart = elem->time.dwLowDateTime;
|
||||||
|
time.HighPart = elem->time.dwHighDateTime;
|
||||||
|
time.QuadPart += timeout*10000000;
|
||||||
|
elem->time.dwLowDateTime = time.LowPart;
|
||||||
|
elem->time.dwHighDateTime = time.HighPart;
|
||||||
|
|
||||||
|
EnterCriticalSection(&timeout_queue_cs);
|
||||||
|
list_add_head(&timeout_queue, &elem->entry);
|
||||||
|
LeaveCriticalSection(&timeout_queue_cs);
|
||||||
|
|
||||||
|
SetEvent(timeout_queue_event);
|
||||||
|
}
|
||||||
|
|
||||||
static void free_service_strings(struct service_entry *old, struct service_entry *new)
|
static void free_service_strings(struct service_entry *old, struct service_entry *new)
|
||||||
{
|
{
|
||||||
QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
|
QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
|
||||||
|
@ -700,7 +747,7 @@ DWORD __cdecl svcctl_SetServiceStatus(
|
||||||
service_unlock(service->service_entry);
|
service_unlock(service->service_entry);
|
||||||
|
|
||||||
if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
|
if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
|
||||||
service_terminate(service->service_entry);
|
run_after_timeout(service_terminate, service->service_entry, service_kill_timeout);
|
||||||
else if (service->service_entry->status_changed_event)
|
else if (service->service_entry->status_changed_event)
|
||||||
SetEvent(service->service_entry->status_changed_event);
|
SetEvent(service->service_entry->status_changed_event);
|
||||||
|
|
||||||
|
@ -1567,10 +1614,16 @@ DWORD RPC_Init(void)
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD RPC_MainLoop(void)
|
DWORD events_loop(void)
|
||||||
{
|
{
|
||||||
|
struct timeout_queue_elem *iter, *iter_safe;
|
||||||
DWORD err;
|
DWORD err;
|
||||||
HANDLE hExitEvent = __wine_make_process_system();
|
HANDLE wait_handles[2];
|
||||||
|
DWORD timeout = INFINITE;
|
||||||
|
|
||||||
|
wait_handles[0] = __wine_make_process_system();
|
||||||
|
wait_handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
|
timeout_queue_event = wait_handles[1];
|
||||||
|
|
||||||
SetEvent(g_hStartedEvent);
|
SetEvent(g_hStartedEvent);
|
||||||
|
|
||||||
|
@ -1578,12 +1631,67 @@ DWORD RPC_MainLoop(void)
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
err = WaitForSingleObjectEx(hExitEvent, INFINITE, TRUE);
|
err = WaitForMultipleObjects(2, wait_handles, FALSE, timeout);
|
||||||
WINE_TRACE("Wait returned %d\n", err);
|
WINE_TRACE("Wait returned %d\n", err);
|
||||||
|
|
||||||
|
if(err==WAIT_OBJECT_0+1 || err==WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
FILETIME cur_time;
|
||||||
|
ULARGE_INTEGER time;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime(&cur_time);
|
||||||
|
time.LowPart = cur_time.dwLowDateTime;
|
||||||
|
time.HighPart = cur_time.dwHighDateTime;
|
||||||
|
|
||||||
|
EnterCriticalSection(&timeout_queue_cs);
|
||||||
|
timeout = INFINITE;
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
|
||||||
|
{
|
||||||
|
if(CompareFileTime(&cur_time, &iter->time) >= 0)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&timeout_queue_cs);
|
||||||
|
iter->func(iter->service_entry);
|
||||||
|
EnterCriticalSection(&timeout_queue_cs);
|
||||||
|
|
||||||
|
release_service(iter->service_entry);
|
||||||
|
list_remove(&iter->entry);
|
||||||
|
HeapFree(GetProcessHeap(), 0, iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ULARGE_INTEGER time_diff;
|
||||||
|
|
||||||
|
time_diff.LowPart = iter->time.dwLowDateTime;
|
||||||
|
time_diff.HighPart = iter->time.dwHighDateTime;
|
||||||
|
time_diff.QuadPart = (time_diff.QuadPart-time.QuadPart)/10000;
|
||||||
|
|
||||||
|
if(time_diff.QuadPart < timeout)
|
||||||
|
timeout = time_diff.QuadPart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&timeout_queue_cs);
|
||||||
|
|
||||||
|
if(timeout != INFINITE)
|
||||||
|
timeout += 1000;
|
||||||
|
}
|
||||||
} while (err != WAIT_OBJECT_0);
|
} while (err != WAIT_OBJECT_0);
|
||||||
|
|
||||||
WINE_TRACE("Object signaled - wine shutdown\n");
|
WINE_TRACE("Object signaled - wine shutdown\n");
|
||||||
CloseHandle(hExitEvent);
|
EnterCriticalSection(&timeout_queue_cs);
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&timeout_queue_cs);
|
||||||
|
iter->func(iter->service_entry);
|
||||||
|
EnterCriticalSection(&timeout_queue_cs);
|
||||||
|
|
||||||
|
release_service(iter->service_entry);
|
||||||
|
list_remove(&iter->entry);
|
||||||
|
HeapFree(GetProcessHeap(), 0, iter);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&timeout_queue_cs);
|
||||||
|
|
||||||
|
CloseHandle(wait_handles[0]);
|
||||||
|
CloseHandle(wait_handles[1]);
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ HANDLE g_hStartedEvent;
|
||||||
struct scmdatabase *active_database;
|
struct scmdatabase *active_database;
|
||||||
|
|
||||||
DWORD service_pipe_timeout = 10000;
|
DWORD service_pipe_timeout = 10000;
|
||||||
DWORD service_kill_timeout = 20000;
|
DWORD service_kill_timeout = 60000;
|
||||||
static DWORD default_preshutdown_timeout = 180000;
|
static DWORD default_preshutdown_timeout = 180000;
|
||||||
static void *env = NULL;
|
static void *env = NULL;
|
||||||
|
|
||||||
|
@ -914,7 +914,7 @@ int main(int argc, char *argv[])
|
||||||
if ((err = RPC_Init()) == ERROR_SUCCESS)
|
if ((err = RPC_Init()) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
scmdatabase_autostart_services(active_database);
|
scmdatabase_autostart_services(active_database);
|
||||||
RPC_MainLoop();
|
events_loop();
|
||||||
scmdatabase_wait_terminate(active_database);
|
scmdatabase_wait_terminate(active_database);
|
||||||
}
|
}
|
||||||
scmdatabase_destroy(active_database);
|
scmdatabase_destroy(active_database);
|
||||||
|
|
|
@ -88,7 +88,7 @@ extern DWORD service_pipe_timeout;
|
||||||
extern DWORD service_kill_timeout;
|
extern DWORD service_kill_timeout;
|
||||||
|
|
||||||
DWORD RPC_Init(void);
|
DWORD RPC_Init(void);
|
||||||
DWORD RPC_MainLoop(void);
|
DWORD events_loop(void);
|
||||||
|
|
||||||
/* from utils.c */
|
/* from utils.c */
|
||||||
LPWSTR strdupW(LPCWSTR str);
|
LPWSTR strdupW(LPCWSTR str);
|
||||||
|
|
Loading…
Reference in New Issue