Author: hbelusca Date: Sun Mar 17 12:39:44 2013 New Revision: 58534
URL: http://svn.reactos.org/svn/reactos?rev=58534&view=rev Log: [SERVICES] - 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.
Modified: trunk/reactos/base/system/services/database.c trunk/reactos/base/system/services/rpcserver.c trunk/reactos/base/system/services/services.c trunk/reactos/base/system/services/services.h
Modified: trunk/reactos/base/system/services/database.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/databa... ============================================================================== --- trunk/reactos/base/system/services/database.c [iso-8859-1] (original) +++ trunk/reactos/base/system/services/database.c [iso-8859-1] Sun Mar 17 12:39:44 2013 @@ -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 @@ 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 @@
DWORD ScmCreateNewServiceRecord(LPCWSTR lpServiceName, - PSERVICE *lpServiceRecord) + PSERVICE* lpServiceRecord) { PSERVICE lpService = NULL;
@@ -772,13 +773,11 @@
if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER) { - RtlInitUnicodeString(&DirName, - L"\Driver"); - } - else - { - RtlInitUnicodeString(&DirName, - L"\FileSystem"); + RtlInitUnicodeString(&DirName, L"\Driver"); + } + else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER) + { + RtlInitUnicodeString(&DirName, L"\FileSystem"); }
InitializeObjectAttributes(&ObjectAttributes, @@ -796,7 +795,7 @@ }
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 @@ static DWORD ScmSendStartCommand(PSERVICE Service, DWORD argc, - LPWSTR *argv) + LPWSTR* argv) { PSCM_CONTROL_PACKET ControlPacket; SCM_REPLY_PACKET ReplyPacket; @@ -1496,7 +1495,7 @@ static DWORD ScmStartUserModeService(PSERVICE Service, DWORD argc, - LPWSTR *argv) + LPWSTR* argv) { PROCESS_INFORMATION ProcessInformation; STARTUPINFOW StartupInfo; @@ -1512,6 +1511,7 @@ 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 @@ if (dwError == ERROR_SUCCESS) { /* Send start command */ - dwError = ScmSendStartCommand(Service, - argc, - argv); + dwError = ScmSendStartCommand(Service, argc, argv); } else { @@ -1569,24 +1567,22 @@ }
-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 @@ 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 @@ } }
- LeaveCriticalSection(&ControlServiceCriticalSection); - - DPRINT("ScmStartService() done (Error %lu)\n", dwError); + DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
if (dwError == ERROR_SUCCESS) { @@ -1677,17 +1671,80 @@ }
+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; @@ -1779,7 +1836,7 @@ (CurrentService->dwTag == CurrentGroup->TagArray[i])) { CurrentService->ServiceVisited = TRUE; - ScmStartService(CurrentService, 0, NULL); + ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; @@ -1797,7 +1854,7 @@ (CurrentService->ServiceVisited == FALSE)) { CurrentService->ServiceVisited = TRUE; - ScmStartService(CurrentService, 0, NULL); + ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; @@ -1817,7 +1874,7 @@ (CurrentService->ServiceVisited == FALSE)) { CurrentService->ServiceVisited = TRUE; - ScmStartService(CurrentService, 0, NULL); + ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; @@ -1834,7 +1891,7 @@ (CurrentService->ServiceVisited == FALSE)) { CurrentService->ServiceVisited = TRUE; - ScmStartService(CurrentService, 0, NULL); + ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; @@ -1848,6 +1905,13 @@ CurrentService->ServiceVisited = FALSE; ServiceEntry = ServiceEntry->Flink; } + + + /* Release the service start lock, if needed, and the critical section */ + if (Lock) ScmReleaseServiceStartLock(&Lock); + +done: + LeaveCriticalSection(&ControlServiceCriticalSection); }
Modified: trunk/reactos/base/system/services/rpcserver.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/rpcser... ============================================================================== --- trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] (original) +++ trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] Sun Mar 17 12:39:44 2013 @@ -2895,7 +2895,6 @@ DWORD dwError = ERROR_SUCCESS; PSERVICE_HANDLE hSvc; PSERVICE lpService = NULL; - SC_RPC_LOCK Lock = NULL;
#ifndef NDEBUG DWORD i; @@ -2941,16 +2940,8 @@ 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 dwError = ERROR_SUCCESS; PSERVICE_HANDLE hSvc; PSERVICE lpService = NULL; - SC_RPC_LOCK Lock = NULL; LPWSTR *lpVector = NULL; DWORD i; DWORD dwLength; @@ -4244,16 +4234,8 @@ } }
- /* 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 */
Modified: trunk/reactos/base/system/services/services.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/servic... ============================================================================== --- trunk/reactos/base/system/services/services.c [iso-8859-1] (original) +++ trunk/reactos/base/system/services/services.c [iso-8859-1] Sun Mar 17 12:39:44 2013 @@ -22,6 +22,12 @@ #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 @@
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; - } + hEvent = OpenEventW(dwDesiredAccess, FALSE, Name); } - else - { - return FALSE; - } - } - - *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 @@ ScmWaitForLsa(VOID) { HANDLE hEvent; - DWORD dwError; - - hEvent = CreateEventW(NULL, - TRUE, - FALSE, - L"LSA_RPC_SERVER_ACTIVE"); - if (hEvent == NULL) - { - 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; - } - } - } - - DPRINT("Wait for the LSA server!\n"); - WaitForSingleObject(hEvent, INFINITE); - DPRINT("LSA server running!\n"); - - CloseHandle(hEvent); + + if (!ScmCreateControlEvent(&hEvent, + LSA_RPC_SERVER_ACTIVE, + SYNCHRONIZE)) + { + 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"); + + CloseHandle(hEvent); + }
DPRINT("ScmWaitForLsa() done\n"); } @@ -351,23 +346,38 @@ 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)) - { - DPRINT1("SERVICES: Failed to create start event\n"); - goto done; - } - - DPRINT("SERVICES: created start event with handle %p.\n", 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 the start event\n"); + goto done; + } + 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 @@ /* 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,49 +403,58 @@ dwError = ScmCreateServiceDatabase(); if (dwError != ERROR_SUCCESS) { - DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError); - goto done; - } + 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");
@@ -451,6 +470,10 @@ 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 @@ DPRINT("SERVICES: Finished.\n");
ExitThread(0); - return 0; }
Modified: trunk/reactos/base/system/services/services.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/servic... ============================================================================== --- trunk/reactos/base/system/services/services.h [iso-8859-1] (original) +++ trunk/reactos/base/system/services/services.h [iso-8859-1] Sun Mar 17 12:39:44 2013 @@ -86,6 +86,7 @@ extern LIST_ENTRY ServiceListHead; extern LIST_ENTRY GroupListHead; extern LIST_ENTRY ImageListHead; +extern BOOL ScmInitialize; extern BOOL ScmShutdown;