[SERVICES]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 17 Mar 2013 12:39:44 +0000 (12:39 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 17 Mar 2013 12:39:44 +0000 (12:39 +0000)
- It seems (after testing) that services report now correctly their state to the SCM. So we can start them in SERVICE_START_PENDING state (see revisions r45626 and r45640).
- Add some informative comments.
- Use a helper function to create start events at initialization time.
- When autostart services are up, signal an event. (see revisions r45633 and r45658).
- Wait for LSASS just after having created the services database, and before calling ScmGetBootAndSystemDriverState (conform to Windows Internals 4th, page 224).

---------

- When starting auto-start services, hold a lock during all the operation in such a way that, if an external program wants to start a service, it is obliged to wait till all the auto-start services have been started (usual service starting also uses that lock).

CORE-7001 #resolve #comment Should be fixed by r58534. Do not hesitate to reopen this bug-report if the problem reappears.

svn path=/trunk/; revision=58534

reactos/base/system/services/database.c
reactos/base/system/services/rpcserver.c
reactos/base/system/services/services.c
reactos/base/system/services/services.h

index 0c2a50d..0714a56 100644 (file)
@@ -19,9 +19,9 @@
 
 /*
  * Uncomment the line below to start services
- *  using the SERVICE_START_PENDING state
+ * using the SERVICE_START_PENDING state.
  */
-// #define USE_SERVICE_START_PENDING
+#define USE_SERVICE_START_PENDING
 
 /*
  * Uncomment the line below to use asynchronous IO operations
@@ -38,6 +38,7 @@ LIST_ENTRY ServiceListHead;
 static RTL_RESOURCE DatabaseLock;
 static DWORD ResumeCount = 1;
 
+/* The critical section synchronizes service controls commands */
 static CRITICAL_SECTION ControlServiceCriticalSection;
 static DWORD PipeTimeout = 30000; /* 30 Seconds */
 
@@ -359,7 +360,7 @@ ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
 
 DWORD
 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
-                          PSERVICE *lpServiceRecord)
+                          PSERVICElpServiceRecord)
 {
     PSERVICE lpService = NULL;
 
@@ -772,13 +773,11 @@ ScmCheckDriver(PSERVICE Service)
 
     if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
     {
-        RtlInitUnicodeString(&DirName,
-                             L"\\Driver");
+        RtlInitUnicodeString(&DirName, L"\\Driver");
     }
-    else
+    else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
     {
-        RtlInitUnicodeString(&DirName,
-                             L"\\FileSystem");
+        RtlInitUnicodeString(&DirName, L"\\FileSystem");
     }
 
     InitializeObjectAttributes(&ObjectAttributes,
@@ -796,7 +795,7 @@ ScmCheckDriver(PSERVICE Service)
     }
 
     BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
-                   2 * MAX_PATH * sizeof(WCHAR);
+                       2 * MAX_PATH * sizeof(WCHAR);
     DirInfo = HeapAlloc(GetProcessHeap(),
                         HEAP_ZERO_MEMORY,
                         BufferLength);
@@ -1096,7 +1095,7 @@ Done:
 static DWORD
 ScmSendStartCommand(PSERVICE Service,
                     DWORD argc,
-                    LPWSTR *argv)
+                    LPWSTRargv)
 {
     PSCM_CONTROL_PACKET ControlPacket;
     SCM_REPLY_PACKET ReplyPacket;
@@ -1496,7 +1495,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
 static DWORD
 ScmStartUserModeService(PSERVICE Service,
                         DWORD argc,
-                        LPWSTR *argv)
+                        LPWSTRargv)
 {
     PROCESS_INFORMATION ProcessInformation;
     STARTUPINFOW StartupInfo;
@@ -1512,6 +1511,7 @@ ScmStartUserModeService(PSERVICE Service,
         return ScmSendStartCommand(Service, argc, argv);
     }
 
+    /* Otherwise start its process */
     ZeroMemory(&StartupInfo, sizeof(StartupInfo));
     StartupInfo.cb = sizeof(StartupInfo);
     ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
@@ -1551,9 +1551,7 @@ ScmStartUserModeService(PSERVICE Service,
     if (dwError == ERROR_SUCCESS)
     {
         /* Send start command */
-        dwError = ScmSendStartCommand(Service,
-                                      argc,
-                                      argv);
+        dwError = ScmSendStartCommand(Service, argc, argv);
     }
     else
     {
@@ -1569,24 +1567,22 @@ ScmStartUserModeService(PSERVICE Service,
 }
 
 
-DWORD
-ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
+static DWORD
+ScmLoadService(PSERVICE Service,
+               DWORD argc,
+               LPWSTR* argv)
 {
     PSERVICE_GROUP Group = Service->lpGroup;
     DWORD dwError = ERROR_SUCCESS;
     LPCWSTR ErrorLogStrings[2];
     WCHAR szErrorBuffer[32];
 
-    DPRINT("ScmStartService() called\n");
-
+    DPRINT("ScmLoadService() called\n");
     DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
 
-    EnterCriticalSection(&ControlServiceCriticalSection);
-
     if (Service->Status.dwCurrentState != SERVICE_STOPPED)
     {
         DPRINT("Service %S is already running!\n", Service->lpServiceName);
-        LeaveCriticalSection(&ControlServiceCriticalSection);
         return ERROR_SERVICE_ALREADY_RUNNING;
     }
 
@@ -1602,7 +1598,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
             Service->Status.dwCurrentState = SERVICE_RUNNING;
         }
     }
-    else
+    else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
     {
         /* Start user-mode service */
         dwError = ScmCreateOrReferenceServiceImage(Service);
@@ -1625,9 +1621,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
         }
     }
 
-    LeaveCriticalSection(&ControlServiceCriticalSection);
-
-    DPRINT("ScmStartService() done (Error %lu)\n", dwError);
+    DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
 
     if (dwError == ERROR_SUCCESS)
     {
@@ -1677,18 +1671,81 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
 }
 
 
+DWORD
+ScmStartService(PSERVICE Service,
+                DWORD argc,
+                LPWSTR* argv)
+{
+    DWORD dwError = ERROR_SUCCESS;
+    SC_RPC_LOCK Lock = NULL;
+
+    DPRINT("ScmStartService() called\n");
+    DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
+
+    /* Acquire the service control critical section, to synchronize starts */
+    EnterCriticalSection(&ControlServiceCriticalSection);
+
+    /*
+     * Acquire the user service start lock while the service is starting, if
+     * needed (i.e. if we are not starting it during the initialization phase).
+     * If we don't success, bail out.
+     */
+    if (!ScmInitialize)
+    {
+        dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
+        if (dwError != ERROR_SUCCESS) goto done;
+    }
+
+    /* Really start the service */
+    dwError = ScmLoadService(Service, argc, argv);
+
+    /* Release the service start lock, if needed, and the critical section */
+    if (Lock) ScmReleaseServiceStartLock(&Lock);
+
+done:
+    LeaveCriticalSection(&ControlServiceCriticalSection);
+
+    DPRINT("ScmStartService() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
 VOID
 ScmAutoStartServices(VOID)
 {
+    DWORD dwError = ERROR_SUCCESS;
+    SC_RPC_LOCK Lock = NULL;
+
     PLIST_ENTRY GroupEntry;
     PLIST_ENTRY ServiceEntry;
     PSERVICE_GROUP CurrentGroup;
     PSERVICE CurrentService;
     WCHAR szSafeBootServicePath[MAX_PATH];
-    DWORD dwError;
     HKEY hKey;
     ULONG i;
 
+    /* Acquire the service control critical section, to synchronize starts */
+    EnterCriticalSection(&ControlServiceCriticalSection);
+
+    /*
+     * Acquire the user service start lock while the service is starting, if
+     * needed (i.e. if we are not starting it during the initialization phase).
+     * If we don't success, bail out.
+     */
+    if (!ScmInitialize)
+    {
+        /*
+         * Actually this code is never executed since we are called
+         * at initialization time, so that ScmInitialize == TRUE.
+         * But keep the code here if someday we are called later on
+         * for whatever reason...
+         */
+        dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
+        if (dwError != ERROR_SUCCESS) goto done;
+    }
+
+
     /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
     ServiceEntry = ServiceListHead.Flink;
     while (ServiceEntry != &ServiceListHead)
@@ -1779,7 +1836,7 @@ ScmAutoStartServices(VOID)
                     (CurrentService->dwTag == CurrentGroup->TagArray[i]))
                 {
                     CurrentService->ServiceVisited = TRUE;
-                    ScmStartService(CurrentService, 0, NULL);
+                    ScmLoadService(CurrentService, 0, NULL);
                 }
 
                 ServiceEntry = ServiceEntry->Flink;
@@ -1797,7 +1854,7 @@ ScmAutoStartServices(VOID)
                 (CurrentService->ServiceVisited == FALSE))
             {
                 CurrentService->ServiceVisited = TRUE;
-                ScmStartService(CurrentService, 0, NULL);
+                ScmLoadService(CurrentService, 0, NULL);
             }
 
             ServiceEntry = ServiceEntry->Flink;
@@ -1817,7 +1874,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, 0, NULL);
+            ScmLoadService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -1834,7 +1891,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, 0, NULL);
+            ScmLoadService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -1848,6 +1905,13 @@ ScmAutoStartServices(VOID)
         CurrentService->ServiceVisited = FALSE;
         ServiceEntry = ServiceEntry->Flink;
     }
+
+
+    /* Release the service start lock, if needed, and the critical section */
+    if (Lock) ScmReleaseServiceStartLock(&Lock);
+
+done:
+    LeaveCriticalSection(&ControlServiceCriticalSection);
 }
 
 
index 4c877d2..110e55d 100644 (file)
@@ -2895,7 +2895,6 @@ DWORD RStartServiceW(
     DWORD dwError = ERROR_SUCCESS;
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService = NULL;
-    SC_RPC_LOCK Lock = NULL;
 
 #ifndef NDEBUG
     DWORD i;
@@ -2941,17 +2940,9 @@ DWORD RStartServiceW(
     if (lpService->bDeleted)
         return ERROR_SERVICE_MARKED_FOR_DELETE;
 
-    /* Acquire the service start lock until the service has been started */
-    dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
-    if (dwError != ERROR_SUCCESS)
-        return dwError;
-
     /* Start the service */
     dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
 
-    /* Release the service start lock */
-    ScmReleaseServiceStartLock(&Lock);
-
     return dwError;
 }
 
@@ -4171,7 +4162,6 @@ DWORD RStartServiceA(
     DWORD dwError = ERROR_SUCCESS;
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService = NULL;
-    SC_RPC_LOCK Lock = NULL;
     LPWSTR *lpVector = NULL;
     DWORD i;
     DWORD dwLength;
@@ -4244,17 +4234,9 @@ DWORD RStartServiceA(
         }
     }
 
-    /* Acquire the service start lock until the service has been started */
-    dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
-    if (dwError != ERROR_SUCCESS)
-        goto done;
-
     /* Start the service */
     dwError = ScmStartService(lpService, argc, lpVector);
 
-     /* Release the service start lock */
-     ScmReleaseServiceStartLock(&Lock);
-
 done:
     /* Free the Unicode argument vector */
     if (lpVector != NULL)
index 2edb6e7..5385a6b 100644 (file)
@@ -22,6 +22,12 @@ int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
 #define PIPE_BUFSIZE 1024
 #define PIPE_TIMEOUT 1000
 
+/* Defined in include/reactos/services/services.h */
+// #define SCM_START_EVENT             L"SvcctrlStartEvent_A3752DX"
+#define SCM_AUTOSTARTCOMPLETE_EVENT L"SC_AutoStartComplete"
+#define LSA_RPC_SERVER_ACTIVE       L"LSA_RPC_SERVER_ACTIVE"
+
+BOOL ScmInitialize = FALSE;
 BOOL ScmShutdown = FALSE;
 static HANDLE hScmShutdownEvent = NULL;
 
@@ -77,35 +83,38 @@ ScmLogError(DWORD dwEventId,
 
 
 BOOL
-ScmCreateStartEvent(PHANDLE StartEvent)
+ScmCreateControlEvent(PHANDLE Event,
+                      LPCWSTR Name,
+                      DWORD dwDesiredAccess)
 {
+    /*
+     * This function creates a generic non-inheritable event
+     * and return a handle to the caller. The caller must
+     * close this handle afterwards.
+     */
+
     HANDLE hEvent;
 
-    hEvent = CreateEventW(NULL,
-                          TRUE,
-                          FALSE,
-                          L"SvcctrlStartEvent_A3752DX");
+    hEvent = CreateEventW(NULL, TRUE, FALSE, Name);
     if (hEvent == NULL)
     {
         if (GetLastError() == ERROR_ALREADY_EXISTS)
         {
-            hEvent = OpenEventW(EVENT_ALL_ACCESS,
-                                FALSE,
-                                L"SvcctrlStartEvent_A3752DX");
-            if (hEvent == NULL)
-            {
-                return FALSE;
-            }
-        }
-        else
-        {
-            return FALSE;
+            hEvent = OpenEventW(dwDesiredAccess, FALSE, Name);
         }
     }
 
-    *StartEvent = hEvent;
-
-    return TRUE;
+    if (hEvent)
+    {
+        DPRINT("SERVICES: Created event %S with handle %x\n", Name, hEvent);
+        *Event = hEvent;
+        return TRUE;
+    }
+    else
+    {
+        DPRINT1("SERVICES: Failed to create event %S (Error %lu)\n", Name, GetLastError());
+        return FALSE;
+    }
 }
 
 
@@ -113,35 +122,21 @@ VOID
 ScmWaitForLsa(VOID)
 {
     HANDLE hEvent;
-    DWORD dwError;
 
-    hEvent = CreateEventW(NULL,
-                          TRUE,
-                          FALSE,
-                          L"LSA_RPC_SERVER_ACTIVE");
-    if (hEvent == NULL)
+    if (!ScmCreateControlEvent(&hEvent,
+                               LSA_RPC_SERVER_ACTIVE,
+                               SYNCHRONIZE))
     {
-        dwError = GetLastError();
-        DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
-
-        if (dwError == ERROR_ALREADY_EXISTS)
-        {
-            hEvent = OpenEventW(SYNCHRONIZE,
-                                FALSE,
-                                L"LSA_RPC_SERVER_ACTIVE");
-            if (hEvent == NULL)
-            {
-               DPRINT1("Could not open the notification event (Error %lu)\n", GetLastError());
-               return;
-            }
-        }
+        DPRINT1("Failed to create the notification event (Error %lu)\n", GetLastError());
     }
+    else
+    {
+        DPRINT("Wait for the LSA server!\n");
+        WaitForSingleObject(hEvent, INFINITE);
+        DPRINT("LSA server running!\n");
 
-    DPRINT("Wait for the LSA server!\n");
-    WaitForSingleObject(hEvent, INFINITE);
-    DPRINT("LSA server running!\n");
-
-    CloseHandle(hEvent);
+        CloseHandle(hEvent);
+    }
 
     DPRINT("ScmWaitForLsa() done\n");
 }
@@ -351,23 +346,38 @@ wWinMain(HINSTANCE hInstance,
          int nShowCmd)
 {
     HANDLE hScmStartEvent = NULL;
+    HANDLE hScmAutoStartCompleteEvent = NULL;
     SC_RPC_LOCK Lock = NULL;
     BOOL bCanDeleteNamedPipeCriticalSection = FALSE;
     DWORD dwError;
 
     DPRINT("SERVICES: Service Control Manager\n");
 
-    /* Create start event */
-    if (!ScmCreateStartEvent(&hScmStartEvent))
+    /* We are initializing ourselves */
+    ScmInitialize = TRUE;
+
+    /* Create the start event */
+    if (!ScmCreateControlEvent(&hScmStartEvent,
+                               SCM_START_EVENT,
+                               EVENT_ALL_ACCESS))
     {
-        DPRINT1("SERVICES: Failed to create start event\n");
+        DPRINT1("SERVICES: Failed to create the start event\n");
         goto done;
     }
+    DPRINT("SERVICES: Created start event with handle %p.\n", hScmStartEvent);
 
-    DPRINT("SERVICES: created start event with handle %p.\n", hScmStartEvent);
+    /* Create the auto-start complete event */
+    if (!ScmCreateControlEvent(&hScmAutoStartCompleteEvent,
+                               SCM_AUTOSTARTCOMPLETE_EVENT,
+                               EVENT_ALL_ACCESS))
+    {
+        DPRINT1("SERVICES: Failed to create the auto-start complete event\n");
+        goto done;
+    }
+    DPRINT("SERVICES: created auto-start complete event with handle %p.\n", hScmAutoStartCompleteEvent);
 
     /* Create the shutdown event */
-    hScmShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    hScmShutdownEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
     if (hScmShutdownEvent == NULL)
     {
         DPRINT1("SERVICES: Failed to create shutdown event\n");
@@ -385,7 +395,7 @@ wWinMain(HINSTANCE hInstance,
     /* Read the control set values */
     if (!ScmGetControlSetValues())
     {
-        DPRINT1("SERVICES: failed to read the control set values\n");
+        DPRINT1("SERVICES: Failed to read the control set values\n");
         goto done;
     }
 
@@ -393,50 +403,59 @@ wWinMain(HINSTANCE hInstance,
     dwError = ScmCreateServiceDatabase();
     if (dwError != ERROR_SUCCESS)
     {
-        DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError);
+        DPRINT1("SERVICES: Failed to create SCM database (Error %lu)\n", dwError);
         goto done;
     }
 
+    /* Wait for the LSA server */
+    ScmWaitForLsa();
+
     /* Update the services database */
     ScmGetBootAndSystemDriverState();
 
-    /* Register the Service Control Manager process with CSRSS */
+    /* Register the Service Control Manager process with the ReactOS Subsystem */
     if (!RegisterServicesProcess(GetCurrentProcessId()))
     {
         DPRINT1("SERVICES: Could not register SCM process\n");
         goto done;
     }
 
-    /* Acquire the service start lock until autostart services have been started */
+    /*
+     * Acquire the user service start lock until
+     * auto-start services have been started.
+     */
     dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
     if (dwError != ERROR_SUCCESS)
     {
-        DPRINT1("SERVICES: failed to acquire the service start lock (Error %lu)\n", dwError);
+        DPRINT1("SERVICES: Failed to acquire the service start lock (Error %lu)\n", dwError);
         goto done;
     }
 
     /* Start the RPC server */
     ScmStartRpcServer();
 
-    DPRINT("SERVICES: Initialized.\n");
-
     /* Signal start event */
     SetEvent(hScmStartEvent);
 
+    DPRINT("SERVICES: Initialized.\n");
+
     /* Register event handler (used for system shutdown) */
     SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
 
-    /* Wait for the LSA server */
-    ScmWaitForLsa();
-
     /* Start auto-start services */
     ScmAutoStartServices();
 
+    /* Signal auto-start complete event */
+    SetEvent(hScmAutoStartCompleteEvent);
+
     /* FIXME: more to do ? */
 
     /* Release the service start lock */
     ScmReleaseServiceStartLock(&Lock);
 
+    /* Initialization finished */
+    ScmInitialize = FALSE;
+
     DPRINT("SERVICES: Running.\n");
 
     /* Wait until the shutdown event gets signaled */
@@ -451,6 +470,10 @@ done:
     if (hScmShutdownEvent != NULL)
         CloseHandle(hScmShutdownEvent);
 
+    /* Close the auto-start complete event */
+    if (hScmAutoStartCompleteEvent != NULL)
+        CloseHandle(hScmAutoStartCompleteEvent);
+
     /* Close the start event */
     if (hScmStartEvent != NULL)
         CloseHandle(hScmStartEvent);
@@ -458,7 +481,6 @@ done:
     DPRINT("SERVICES: Finished.\n");
 
     ExitThread(0);
-
     return 0;
 }
 
index 8e13a3e..20afb30 100644 (file)
@@ -86,6 +86,7 @@ typedef struct _START_LOCK
 extern LIST_ENTRY ServiceListHead;
 extern LIST_ENTRY GroupListHead;
 extern LIST_ENTRY ImageListHead;
+extern BOOL ScmInitialize;
 extern BOOL ScmShutdown;