Piotr Caban : services: Kill service thread after timeout so it can terminate cleanly.

Alexandre Julliard julliard at winehq.org
Mon Oct 22 13:42:45 CDT 2012


Module: wine
Branch: master
Commit: 522bc15b455ffbd09bb2f594aaaa3e9b13903efe
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=522bc15b455ffbd09bb2f594aaaa3e9b13903efe

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Mon Oct 22 14:26:10 2012 +0200

services: Kill service thread after timeout so it can terminate cleanly.

---

 programs/services/rpc.c      |  118 ++++++++++++++++++++++++++++++++++++++++--
 programs/services/services.c |    4 +-
 programs/services/services.h |    2 +-
 3 files changed, 116 insertions(+), 8 deletions(-)

diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index bf8ce80..9fe81d1 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -84,6 +84,53 @@ struct sc_lock
     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)
 {
     QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
@@ -700,7 +747,7 @@ DWORD __cdecl svcctl_SetServiceStatus(
     service_unlock(service->service_entry);
 
     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)
         SetEvent(service->service_entry->status_changed_event);
 
@@ -1567,10 +1614,16 @@ DWORD RPC_Init(void)
     return ERROR_SUCCESS;
 }
 
-DWORD RPC_MainLoop(void)
+DWORD events_loop(void)
 {
+    struct timeout_queue_elem *iter, *iter_safe;
     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);
 
@@ -1578,12 +1631,67 @@ DWORD RPC_MainLoop(void)
 
     do
     {
-        err = WaitForSingleObjectEx(hExitEvent, INFINITE, TRUE);
+        err = WaitForMultipleObjects(2, wait_handles, FALSE, timeout);
         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);
 
     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;
 }
 
diff --git a/programs/services/services.c b/programs/services/services.c
index d28e47e..75abf06 100644
--- a/programs/services/services.c
+++ b/programs/services/services.c
@@ -40,7 +40,7 @@ HANDLE g_hStartedEvent;
 struct scmdatabase *active_database;
 
 DWORD service_pipe_timeout = 10000;
-DWORD service_kill_timeout = 20000;
+DWORD service_kill_timeout = 60000;
 static DWORD default_preshutdown_timeout = 180000;
 static void *env = NULL;
 
@@ -914,7 +914,7 @@ int main(int argc, char *argv[])
     if ((err = RPC_Init()) == ERROR_SUCCESS)
     {
         scmdatabase_autostart_services(active_database);
-        RPC_MainLoop();
+        events_loop();
         scmdatabase_wait_terminate(active_database);
     }
     scmdatabase_destroy(active_database);
diff --git a/programs/services/services.h b/programs/services/services.h
index b4b895e..3e36141 100644
--- a/programs/services/services.h
+++ b/programs/services/services.h
@@ -88,7 +88,7 @@ extern DWORD service_pipe_timeout;
 extern DWORD service_kill_timeout;
 
 DWORD RPC_Init(void);
-DWORD RPC_MainLoop(void);
+DWORD events_loop(void);
 
 /* from utils.c */
 LPWSTR strdupW(LPCWSTR str);




More information about the wine-cvs mailing list