[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.

svn path=/trunk/; revision=58534
This commit is contained in:
Hermès Bélusca-Maïto
2013-03-17 12:39:44 +00:00
parent c03ac4615e
commit db5a7755ce
4 changed files with 177 additions and 108 deletions
+94 -30
View 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)
PSERVICE* lpServiceRecord)
{
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)
LPWSTR* argv)
{
PSCM_CONTROL_PACKET ControlPacket;
SCM_REPLY_PACKET ReplyPacket;
@@ -1496,7 +1495,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
static DWORD
ScmStartUserModeService(PSERVICE Service,
DWORD argc,
LPWSTR *argv)
LPWSTR* argv)
{
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);
}
-18
View 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)
+82 -60
View 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;
}
+1
View 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;