Andrew Eikum : advapi32: Also wait on services without a control thread during shutdown.

Alexandre Julliard julliard at winehq.org
Tue Feb 6 15:55:51 CST 2018


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

Author: Andrew Eikum <aeikum at codeweavers.com>
Date:   Tue Feb  6 10:43:57 2018 -0600

advapi32: Also wait on services without a control thread during shutdown.

Tested service messages during OS shutdown manually on Windows 7.

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/advapi32/service.c | 94 +++++++++++++++++++++++++++++++------------------
 1 file changed, 59 insertions(+), 35 deletions(-)

diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index 7d66326..70907e1 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -529,6 +529,63 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
     return 1;
 }
 
+/* wait for services which accept this type of message to become STOPPED */
+static void handle_shutdown_msg(DWORD msg, DWORD accept)
+{
+    SERVICE_STATUS st;
+    SERVICE_PRESHUTDOWN_INFO spi;
+    DWORD i, n = 0, sz, timeout = 2000;
+    ULONGLONG stop_time;
+    BOOL res, done = TRUE;
+    SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services );
+
+    EnterCriticalSection( &service_cs );
+    for (i = 0; i < nb_services; i++)
+    {
+        res = QueryServiceStatus( services[i]->full_access_handle, &st );
+        if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept))
+            continue;
+
+        done = FALSE;
+
+        if (accept == SERVICE_ACCEPT_PRESHUTDOWN)
+        {
+            res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
+                    (LPBYTE)&spi, sizeof(spi), &sz );
+            if (res)
+            {
+                FIXME( "service should be able to delay shutdown\n" );
+                timeout = max( spi.dwPreshutdownTimeout, timeout );
+            }
+        }
+
+        service_handle_control( services[i], msg, NULL, 0 );
+        wait_handles[n++] = services[i]->full_access_handle;
+    }
+    LeaveCriticalSection( &service_cs );
+
+    /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
+    timeout = min( timeout, 3000 );
+    stop_time = GetTickCount64() + timeout;
+
+    while (!done && GetTickCount64() < stop_time)
+    {
+        done = TRUE;
+        for (i = 0; i < n; i++)
+        {
+            res = QueryServiceStatus( wait_handles[i], &st );
+            if (!res || st.dwCurrentState == SERVICE_STOPPED)
+                continue;
+
+            done = FALSE;
+            Sleep( 100 );
+            break;
+        }
+    }
+
+    HeapFree( GetProcessHeap(), 0, wait_handles );
+}
+
 /******************************************************************************
  * service_run_main_thread
  */
@@ -583,41 +640,8 @@ static BOOL service_run_main_thread(void)
         ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
         if (!ret)  /* system process event */
         {
-            SERVICE_STATUS st;
-            SERVICE_PRESHUTDOWN_INFO spi;
-            DWORD timeout = 5000;
-            BOOL res;
-
-            EnterCriticalSection( &service_cs );
-            n = 0;
-            for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
-            {
-                if (!services[i]->thread) continue;
-
-                res = QueryServiceStatus(services[i]->full_access_handle, &st);
-                ret = ERROR_SUCCESS;
-                if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
-                {
-                    res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
-                            (LPBYTE)&spi, sizeof(spi), &i );
-                    if (res)
-                    {
-                        FIXME("service should be able to delay shutdown\n");
-                        timeout += spi.dwPreshutdownTimeout;
-                        ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL, 0 );
-                        wait_handles[n++] = services[i]->thread;
-                    }
-                }
-                else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
-                {
-                    ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL, 0 );
-                    wait_handles[n++] = services[i]->thread;
-                }
-            }
-            LeaveCriticalSection( &service_cs );
-
-            TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
-            WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
+            handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN);
+            handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN);
             ExitProcess(0);
         }
         else if (ret == 1)




More information about the wine-cvs mailing list