https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f6d81f225747e4b1b3716e9ca8629f77dcc52b1a

commit f6d81f225747e4b1b3716e9ca8629f77dcc52b1a
Author:     Eric Kohl <[email protected]>
AuthorDate: Fri Oct 5 08:41:23 2018 +0200
Commit:     Eric Kohl <[email protected]>
CommitDate: Fri Oct 5 08:41:23 2018 +0200

    [SERVICES] Fix timeout when a service is stopped
    
    RSetServiceStatus: Send the stop command for the dispatcher thread from a 
separate thread.
    
    Fixes CORE-15064
---
 base/system/services/rpcserver.c | 59 ++++++++++++++++++++++++++++++++++------
 1 file changed, 50 insertions(+), 9 deletions(-)

diff --git a/base/system/services/rpcserver.c b/base/system/services/rpcserver.c
index 7f251c8760..8e383a5bdc 100644
--- a/base/system/services/rpcserver.c
+++ b/base/system/services/rpcserver.c
@@ -1671,6 +1671,43 @@ ScmIsValidServiceState(DWORD dwCurrentState)
 }
 
 
+static
+DWORD
+WINAPI
+ScmStopThread(
+    _In_ PVOID pParam)
+{
+    PSERVICE pService;
+
+    DPRINT("ScmStopThread(%p)\n", pParam);
+
+    pService = (PSERVICE)pParam;
+
+    if (pService->lpImage->dwImageRunCount != 0)
+        return 0;
+
+    Sleep(2000);
+
+    /* Lock the service database exclusively */
+    ScmLockDatabaseExclusive();
+
+    /* Stop the dispatcher thread */
+    ScmControlService(pService->lpImage->hControlPipe,
+                      L"",
+                      (SERVICE_STATUS_HANDLE)pService,
+                      SERVICE_CONTROL_STOP);
+
+    /* Remove the service image */
+    ScmRemoveServiceImage(pService->lpImage);
+
+    /* Unlock the service database */
+    ScmUnlockDatabase();
+
+    DPRINT("ScmStopThread done!\n");
+    return 0;
+}
+
+
 /* Function 7 */
 DWORD
 WINAPI
@@ -1683,6 +1720,8 @@ RSetServiceStatus(
     DWORD dwPreviousType;
     LPCWSTR lpLogStrings[2];
     WCHAR szLogBuffer[80];
+    HANDLE hStopThread = NULL;
+    DWORD dwStopThreadId;
     UINT uID;
 
     DPRINT("RSetServiceStatus() called\n");
@@ -1762,15 +1801,17 @@ RSetServiceStatus(
         /* If we just stopped the last running service... */
         if (lpService->lpImage->dwImageRunCount == 0)
         {
-            /* Stop the dispatcher thread */
-            ScmControlService(lpService->lpImage->hControlPipe,
-                              L"",
-                              (SERVICE_STATUS_HANDLE)lpService,
-                              SERVICE_CONTROL_STOP);
-
-            /* Remove the service image */
-            ScmRemoveServiceImage(lpService->lpImage);
-            lpService->lpImage = NULL;
+           /* Run the stop thread to stop the service dispatcher */
+           hStopThread = CreateThread(NULL,
+                                      0,
+                                      (LPTHREAD_START_ROUTINE)ScmStopThread,
+                                      (LPVOID)lpService,
+                                      0,
+                                      &dwStopThreadId);
+           if (hStopThread != NULL)
+           {
+               CloseHandle(hStopThread);
+           }
         }
     }
 

Reply via email to