mirror of
https://github.com/reactos/reactos.git
synced 2024-07-04 11:44:33 +00:00
[SERVICES][ADVAPI32] Fix the broken service stop sequence
services\database.c: - Refactor ScmControlService() so that it can be used to send the dispatcher loop stop command. - Separate the code to decrement the image run counter from the service image cleanup code. services\rpcserver.c: - RSetServiceStatus(): Stop the dispatcher loop when the image run counter is zero and remove the service image after that. advapi32\service\sctrl.c: - Do not terminate the service dispatcher loop when the last service is being stopped. Wait for an explicit dispatcher stop command (empty service name). CORE-12413
This commit is contained in:
parent
b6c060ce04
commit
1dfbed9c3d
|
@ -432,16 +432,10 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static VOID
|
VOID
|
||||||
ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
|
ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage)
|
||||||
{
|
{
|
||||||
DPRINT1("ScmDereferenceServiceImage() called\n");
|
DPRINT1("ScmRemoveServiceImage() called\n");
|
||||||
|
|
||||||
pServiceImage->dwImageRunCount--;
|
|
||||||
|
|
||||||
if (pServiceImage->dwImageRunCount == 0)
|
|
||||||
{
|
|
||||||
DPRINT1("dwImageRunCount == 0\n");
|
|
||||||
|
|
||||||
/* FIXME: Terminate the process */
|
/* FIXME: Terminate the process */
|
||||||
|
|
||||||
|
@ -467,7 +461,6 @@ ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
|
||||||
/* Release the service image */
|
/* Release the service image */
|
||||||
HeapFree(GetProcessHeap(), 0, pServiceImage);
|
HeapFree(GetProcessHeap(), 0, pServiceImage);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PSERVICE
|
PSERVICE
|
||||||
|
@ -618,7 +611,15 @@ ScmDeleteServiceRecord(PSERVICE lpService)
|
||||||
|
|
||||||
/* Dereference the service image */
|
/* Dereference the service image */
|
||||||
if (lpService->lpImage)
|
if (lpService->lpImage)
|
||||||
ScmDereferenceServiceImage(lpService->lpImage);
|
{
|
||||||
|
lpService->lpImage->dwImageRunCount--;
|
||||||
|
|
||||||
|
if (lpService->lpImage->dwImageRunCount == 0)
|
||||||
|
{
|
||||||
|
ScmRemoveServiceImage(lpService->lpImage);
|
||||||
|
lpService->lpImage = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Decrement the group reference counter */
|
/* Decrement the group reference counter */
|
||||||
ScmSetServiceGroup(lpService, NULL);
|
ScmSetServiceGroup(lpService, NULL);
|
||||||
|
@ -1095,7 +1096,9 @@ ScmGetBootAndSystemDriverState(VOID)
|
||||||
|
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
ScmControlService(PSERVICE Service,
|
ScmControlService(HANDLE hControlPipe,
|
||||||
|
PWSTR pServiceName,
|
||||||
|
SERVICE_STATUS_HANDLE hServiceStatus,
|
||||||
DWORD dwControl)
|
DWORD dwControl)
|
||||||
{
|
{
|
||||||
PSCM_CONTROL_PACKET ControlPacket;
|
PSCM_CONTROL_PACKET ControlPacket;
|
||||||
|
@ -1116,7 +1119,7 @@ ScmControlService(PSERVICE Service,
|
||||||
|
|
||||||
/* Calculate the total length of the start command line */
|
/* Calculate the total length of the start command line */
|
||||||
PacketSize = sizeof(SCM_CONTROL_PACKET);
|
PacketSize = sizeof(SCM_CONTROL_PACKET);
|
||||||
PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
|
PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR));
|
||||||
|
|
||||||
ControlPacket = HeapAlloc(GetProcessHeap(),
|
ControlPacket = HeapAlloc(GetProcessHeap(),
|
||||||
HEAP_ZERO_MEMORY,
|
HEAP_ZERO_MEMORY,
|
||||||
|
@ -1129,17 +1132,17 @@ ScmControlService(PSERVICE Service,
|
||||||
|
|
||||||
ControlPacket->dwSize = PacketSize;
|
ControlPacket->dwSize = PacketSize;
|
||||||
ControlPacket->dwControl = dwControl;
|
ControlPacket->dwControl = dwControl;
|
||||||
ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
|
ControlPacket->hServiceStatus = hServiceStatus;
|
||||||
|
|
||||||
ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
|
ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
|
||||||
|
|
||||||
Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
||||||
wcscpy(Ptr, Service->lpServiceName);
|
wcscpy(Ptr, pServiceName);
|
||||||
|
|
||||||
ControlPacket->dwArgumentsCount = 0;
|
ControlPacket->dwArgumentsCount = 0;
|
||||||
ControlPacket->dwArgumentsOffset = 0;
|
ControlPacket->dwArgumentsOffset = 0;
|
||||||
|
|
||||||
bResult = WriteFile(Service->lpImage->hControlPipe,
|
bResult = WriteFile(hControlPipe,
|
||||||
ControlPacket,
|
ControlPacket,
|
||||||
PacketSize,
|
PacketSize,
|
||||||
&dwWriteCount,
|
&dwWriteCount,
|
||||||
|
@ -1153,13 +1156,13 @@ ScmControlService(PSERVICE Service,
|
||||||
{
|
{
|
||||||
DPRINT("dwError: ERROR_IO_PENDING\n");
|
DPRINT("dwError: ERROR_IO_PENDING\n");
|
||||||
|
|
||||||
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
|
dwError = WaitForSingleObject(hControlPipe,
|
||||||
PipeTimeout);
|
PipeTimeout);
|
||||||
DPRINT("WaitForSingleObject() returned %lu\n", dwError);
|
DPRINT("WaitForSingleObject() returned %lu\n", dwError);
|
||||||
|
|
||||||
if (dwError == WAIT_TIMEOUT)
|
if (dwError == WAIT_TIMEOUT)
|
||||||
{
|
{
|
||||||
bResult = CancelIo(Service->lpImage->hControlPipe);
|
bResult = CancelIo(hControlPipe);
|
||||||
if (bResult == FALSE)
|
if (bResult == FALSE)
|
||||||
{
|
{
|
||||||
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
|
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
|
||||||
|
@ -1170,7 +1173,7 @@ ScmControlService(PSERVICE Service,
|
||||||
}
|
}
|
||||||
else if (dwError == WAIT_OBJECT_0)
|
else if (dwError == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
|
bResult = GetOverlappedResult(hControlPipe,
|
||||||
&Overlapped,
|
&Overlapped,
|
||||||
&dwWriteCount,
|
&dwWriteCount,
|
||||||
TRUE);
|
TRUE);
|
||||||
|
@ -1193,7 +1196,7 @@ ScmControlService(PSERVICE Service,
|
||||||
/* Read the reply */
|
/* Read the reply */
|
||||||
Overlapped.hEvent = (HANDLE) NULL;
|
Overlapped.hEvent = (HANDLE) NULL;
|
||||||
|
|
||||||
bResult = ReadFile(Service->lpImage->hControlPipe,
|
bResult = ReadFile(hControlPipe,
|
||||||
&ReplyPacket,
|
&ReplyPacket,
|
||||||
sizeof(SCM_REPLY_PACKET),
|
sizeof(SCM_REPLY_PACKET),
|
||||||
&dwReadCount,
|
&dwReadCount,
|
||||||
|
@ -1207,13 +1210,13 @@ ScmControlService(PSERVICE Service,
|
||||||
{
|
{
|
||||||
DPRINT("dwError: ERROR_IO_PENDING\n");
|
DPRINT("dwError: ERROR_IO_PENDING\n");
|
||||||
|
|
||||||
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
|
dwError = WaitForSingleObject(hControlPipe,
|
||||||
PipeTimeout);
|
PipeTimeout);
|
||||||
DPRINT("WaitForSingleObject() returned %lu\n", dwError);
|
DPRINT("WaitForSingleObject() returned %lu\n", dwError);
|
||||||
|
|
||||||
if (dwError == WAIT_TIMEOUT)
|
if (dwError == WAIT_TIMEOUT)
|
||||||
{
|
{
|
||||||
bResult = CancelIo(Service->lpImage->hControlPipe);
|
bResult = CancelIo(hControlPipe);
|
||||||
if (bResult == FALSE)
|
if (bResult == FALSE)
|
||||||
{
|
{
|
||||||
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
|
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
|
||||||
|
@ -1224,7 +1227,7 @@ ScmControlService(PSERVICE Service,
|
||||||
}
|
}
|
||||||
else if (dwError == WAIT_OBJECT_0)
|
else if (dwError == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
|
bResult = GetOverlappedResult(hControlPipe,
|
||||||
&Overlapped,
|
&Overlapped,
|
||||||
&dwReadCount,
|
&dwReadCount,
|
||||||
TRUE);
|
TRUE);
|
||||||
|
@ -1255,13 +1258,6 @@ Done:
|
||||||
dwError = ReplyPacket.dwError;
|
dwError = ReplyPacket.dwError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwError == ERROR_SUCCESS &&
|
|
||||||
dwControl == SERVICE_CONTROL_STOP)
|
|
||||||
{
|
|
||||||
ScmDereferenceServiceImage(Service->lpImage);
|
|
||||||
Service->lpImage = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LeaveCriticalSection(&ControlServiceCriticalSection);
|
LeaveCriticalSection(&ControlServiceCriticalSection);
|
||||||
|
|
||||||
DPRINT("ScmControlService() done\n");
|
DPRINT("ScmControlService() done\n");
|
||||||
|
@ -1831,11 +1827,15 @@ ScmLoadService(PSERVICE Service,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ScmDereferenceServiceImage(Service->lpImage);
|
Service->lpImage->dwImageRunCount--;
|
||||||
|
if (Service->lpImage->dwImageRunCount == 0)
|
||||||
|
{
|
||||||
|
ScmRemoveServiceImage(Service->lpImage);
|
||||||
Service->lpImage = NULL;
|
Service->lpImage = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
|
DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
|
||||||
|
|
||||||
|
@ -2168,8 +2168,11 @@ ScmAutoShutdownServices(VOID)
|
||||||
CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
|
CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
|
||||||
{
|
{
|
||||||
/* shutdown service */
|
/* shutdown service */
|
||||||
DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
|
DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName);
|
||||||
ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
|
ScmControlService(CurrentService->lpImage->hControlPipe,
|
||||||
|
CurrentService->lpServiceName,
|
||||||
|
(SERVICE_STATUS_HANDLE)CurrentService,
|
||||||
|
SERVICE_CONTROL_SHUTDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceEntry = ServiceEntry->Flink;
|
ServiceEntry = ServiceEntry->Flink;
|
||||||
|
|
|
@ -1228,7 +1228,9 @@ RControlService(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send control code to the service */
|
/* Send control code to the service */
|
||||||
dwError = ScmControlService(lpService,
|
dwError = ScmControlService(lpService->lpImage->hControlPipe,
|
||||||
|
lpService->lpServiceName,
|
||||||
|
(SERVICE_STATUS_HANDLE)lpService,
|
||||||
dwControl);
|
dwControl);
|
||||||
|
|
||||||
/* Return service status information */
|
/* Return service status information */
|
||||||
|
@ -1725,6 +1727,28 @@ RSetServiceStatus(
|
||||||
/* Restore the previous service type */
|
/* Restore the previous service type */
|
||||||
lpService->Status.dwServiceType = dwPreviousType;
|
lpService->Status.dwServiceType = dwPreviousType;
|
||||||
|
|
||||||
|
/* Handle a stopped service */
|
||||||
|
if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
|
||||||
|
(lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
|
||||||
|
{
|
||||||
|
/* Decrement the image run counter */
|
||||||
|
lpService->lpImage->dwImageRunCount--;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Unlock the service database */
|
/* Unlock the service database */
|
||||||
ScmUnlockDatabase();
|
ScmUnlockDatabase();
|
||||||
|
|
||||||
|
@ -1773,6 +1797,8 @@ RSetServiceStatus(
|
||||||
lpLogStrings);
|
lpLogStrings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
|
DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
|
||||||
DPRINT("RSetServiceStatus() done\n");
|
DPRINT("RSetServiceStatus() done\n");
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,7 @@ DWORD ScmStartService(PSERVICE Service,
|
||||||
DWORD argc,
|
DWORD argc,
|
||||||
LPWSTR *argv);
|
LPWSTR *argv);
|
||||||
|
|
||||||
|
VOID ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage);
|
||||||
PSERVICE ScmGetServiceEntryByName(LPCWSTR lpServiceName);
|
PSERVICE ScmGetServiceEntryByName(LPCWSTR lpServiceName);
|
||||||
PSERVICE ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName);
|
PSERVICE ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName);
|
||||||
PSERVICE ScmGetServiceEntryByResumeCount(DWORD dwResumeCount);
|
PSERVICE ScmGetServiceEntryByResumeCount(DWORD dwResumeCount);
|
||||||
|
@ -174,7 +175,9 @@ DWORD ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
|
||||||
VOID ScmDeleteServiceRecord(PSERVICE lpService);
|
VOID ScmDeleteServiceRecord(PSERVICE lpService);
|
||||||
DWORD ScmMarkServiceForDelete(PSERVICE pService);
|
DWORD ScmMarkServiceForDelete(PSERVICE pService);
|
||||||
|
|
||||||
DWORD ScmControlService(PSERVICE Service,
|
DWORD ScmControlService(HANDLE hControlPipe,
|
||||||
|
PWSTR pServiceName,
|
||||||
|
SERVICE_STATUS_HANDLE hServiceStatus,
|
||||||
DWORD dwControl);
|
DWORD dwControl);
|
||||||
|
|
||||||
BOOL ScmLockDatabaseExclusive(VOID);
|
BOOL ScmLockDatabaseExclusive(VOID);
|
||||||
|
|
|
@ -544,7 +544,7 @@ ScServiceDispatcher(HANDLE hPipe,
|
||||||
{
|
{
|
||||||
DWORD Count;
|
DWORD Count;
|
||||||
BOOL bResult;
|
BOOL bResult;
|
||||||
DWORD dwRunningServices = 0;
|
BOOL bRunning = TRUE;
|
||||||
LPWSTR lpServiceName;
|
LPWSTR lpServiceName;
|
||||||
PACTIVE_SERVICE lpService;
|
PACTIVE_SERVICE lpService;
|
||||||
SCM_REPLY_PACKET ReplyPacket;
|
SCM_REPLY_PACKET ReplyPacket;
|
||||||
|
@ -555,7 +555,7 @@ ScServiceDispatcher(HANDLE hPipe,
|
||||||
if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
|
if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
while (TRUE)
|
while (bRunning)
|
||||||
{
|
{
|
||||||
/* Read command from the control pipe */
|
/* Read command from the control pipe */
|
||||||
bResult = ReadFile(hPipe,
|
bResult = ReadFile(hPipe,
|
||||||
|
@ -572,6 +572,14 @@ ScServiceDispatcher(HANDLE hPipe,
|
||||||
lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
||||||
TRACE("Service: %S\n", lpServiceName);
|
TRACE("Service: %S\n", lpServiceName);
|
||||||
|
|
||||||
|
if (lpServiceName[0] == UNICODE_NULL)
|
||||||
|
{
|
||||||
|
ERR("Stop dispatcher thread\n");
|
||||||
|
bRunning = FALSE;
|
||||||
|
dwError = ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
|
if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
|
||||||
lpActiveServices[0].bOwnProcess = TRUE;
|
lpActiveServices[0].bOwnProcess = TRUE;
|
||||||
|
|
||||||
|
@ -585,15 +593,11 @@ ScServiceDispatcher(HANDLE hPipe,
|
||||||
case SERVICE_CONTROL_START_OWN:
|
case SERVICE_CONTROL_START_OWN:
|
||||||
TRACE("Start command - received SERVICE_CONTROL_START\n");
|
TRACE("Start command - received SERVICE_CONTROL_START\n");
|
||||||
dwError = ScStartService(lpService, ControlPacket);
|
dwError = ScStartService(lpService, ControlPacket);
|
||||||
if (dwError == ERROR_SUCCESS)
|
|
||||||
dwRunningServices++;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SERVICE_CONTROL_STOP:
|
case SERVICE_CONTROL_STOP:
|
||||||
TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
|
TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
|
||||||
dwError = ScControlService(lpService, ControlPacket);
|
dwError = ScControlService(lpService, ControlPacket);
|
||||||
if (dwError == ERROR_SUCCESS)
|
|
||||||
dwRunningServices--;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -606,6 +610,7 @@ ScServiceDispatcher(HANDLE hPipe,
|
||||||
{
|
{
|
||||||
dwError = ERROR_SERVICE_DOES_NOT_EXIST;
|
dwError = ERROR_SERVICE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ReplyPacket.dwError = dwError;
|
ReplyPacket.dwError = dwError;
|
||||||
|
|
||||||
|
@ -620,9 +625,6 @@ ScServiceDispatcher(HANDLE hPipe,
|
||||||
ERR("Pipe write failed (Error: %lu)\n", GetLastError());
|
ERR("Pipe write failed (Error: %lu)\n", GetLastError());
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwRunningServices == 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
Loading…
Reference in a new issue