mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 10:01:43 +00:00
[SERVICES] Fix services delay on stopping (#7375)
Retry of @yagoulas PR #1225. JIRA issues: CORE-16949 and CORE-15064
This commit is contained in:
parent
f4cb10f596
commit
2f824a4a18
3 changed files with 252 additions and 128 deletions
|
@ -852,6 +852,105 @@ ScmDeleteServiceRecord(PSERVICE lpService)
|
|||
DPRINT("Done\n");
|
||||
}
|
||||
|
||||
DWORD
|
||||
Int_EnumDependentServicesW(HKEY hServicesKey,
|
||||
PSERVICE lpService,
|
||||
DWORD dwServiceState,
|
||||
PSERVICE *lpServices,
|
||||
LPDWORD pcbBytesNeeded,
|
||||
LPDWORD lpServicesReturned);
|
||||
|
||||
DWORD ScmDeleteService(PSERVICE lpService)
|
||||
{
|
||||
DWORD dwError;
|
||||
DWORD pcbBytesNeeded = 0;
|
||||
DWORD dwServicesReturned = 0;
|
||||
HKEY hServicesKey;
|
||||
|
||||
ASSERT(lpService->RefCount == 0);
|
||||
|
||||
/* Open the Services Reg key */
|
||||
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"System\\CurrentControlSet\\Services",
|
||||
0,
|
||||
KEY_SET_VALUE | KEY_READ,
|
||||
&hServicesKey);
|
||||
if (dwError != ERROR_SUCCESS)
|
||||
{
|
||||
DPRINT1("Failed to open services key\n");
|
||||
return dwError;
|
||||
}
|
||||
|
||||
/* Call the function with NULL, just to get bytes we need */
|
||||
Int_EnumDependentServicesW(hServicesKey,
|
||||
lpService,
|
||||
SERVICE_ACTIVE,
|
||||
NULL,
|
||||
&pcbBytesNeeded,
|
||||
&dwServicesReturned);
|
||||
|
||||
/* If pcbBytesNeeded returned a value then there are services running that are dependent on this service */
|
||||
if (pcbBytesNeeded)
|
||||
{
|
||||
DPRINT1("Deletion failed due to running dependencies\n");
|
||||
RegCloseKey(hServicesKey);
|
||||
return ERROR_DEPENDENT_SERVICES_RUNNING;
|
||||
}
|
||||
|
||||
/* There are no references and no running dependencies,
|
||||
it is now safe to delete the service */
|
||||
|
||||
/* Delete the Service Key */
|
||||
dwError = ScmDeleteRegKey(hServicesKey, lpService->lpServiceName);
|
||||
|
||||
RegCloseKey(hServicesKey);
|
||||
|
||||
if (dwError != ERROR_SUCCESS)
|
||||
{
|
||||
DPRINT1("Failed to delete the Service Registry key\n");
|
||||
return dwError;
|
||||
}
|
||||
|
||||
/* Delete the Service */
|
||||
ScmDeleteServiceRecord(lpService);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function allows the caller to be sure that the service won't be freed unexpectedly.
|
||||
* In order to be sure that lpService will be valid until the reference is added
|
||||
* the caller needs to hold the database lock.
|
||||
* A running service will keep a reference for the whole time it is not SERVICE_STOPPED.
|
||||
* A service handle will also keep a reference to a service. Keeping a reference is
|
||||
* really needed so that ScmControlService can be called without keeping the database locked.
|
||||
* This means that eventually the correct order of operations to send a control message to
|
||||
* a service looks like: lock, reference, unlock, send control, lock, dereference, unlock.
|
||||
*/
|
||||
DWORD
|
||||
ScmReferenceService(PSERVICE lpService)
|
||||
{
|
||||
return InterlockedIncrement(&lpService->RefCount);
|
||||
}
|
||||
|
||||
/* This function must be called with the database lock held exclusively as
|
||||
it can end up deleting the service */
|
||||
DWORD
|
||||
ScmDereferenceService(PSERVICE lpService)
|
||||
{
|
||||
DWORD ref;
|
||||
|
||||
ASSERT(lpService->RefCount > 0);
|
||||
|
||||
ref = InterlockedDecrement(&lpService->RefCount);
|
||||
|
||||
if (ref == 0 && lpService->bDeleted &&
|
||||
lpService->Status.dwCurrentState == SERVICE_STOPPED)
|
||||
{
|
||||
ScmDeleteService(lpService);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
static DWORD
|
||||
CreateServiceListEntry(LPCWSTR lpServiceName,
|
||||
|
@ -1310,6 +1409,10 @@ ScmGetBootAndSystemDriverState(VOID)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* ScmControlService must never be called with the database lock being held.
|
||||
* The service passed must always be referenced instead.
|
||||
*/
|
||||
DWORD
|
||||
ScmControlService(HANDLE hControlPipe,
|
||||
PWSTR pServiceName,
|
||||
|
@ -1327,7 +1430,7 @@ ScmControlService(HANDLE hControlPipe,
|
|||
BOOL bResult;
|
||||
OVERLAPPED Overlapped = {0};
|
||||
|
||||
DPRINT("ScmControlService() called\n");
|
||||
DPRINT("ScmControlService(%S, %d) called\n", pServiceName, dwControl);
|
||||
|
||||
/* Acquire the service control critical section, to synchronize requests */
|
||||
EnterCriticalSection(&ControlServiceCriticalSection);
|
||||
|
@ -1364,23 +1467,24 @@ ScmControlService(HANDLE hControlPipe,
|
|||
&Overlapped);
|
||||
if (bResult == FALSE)
|
||||
{
|
||||
DPRINT("WriteFile() returned FALSE\n");
|
||||
DPRINT1("WriteFile(%S, %d) returned FALSE\n", pServiceName, dwControl);
|
||||
|
||||
dwError = GetLastError();
|
||||
if (dwError == ERROR_IO_PENDING)
|
||||
{
|
||||
DPRINT("dwError: ERROR_IO_PENDING\n");
|
||||
DPRINT("(%S, %d) dwError: ERROR_IO_PENDING\n", pServiceName, dwControl);
|
||||
|
||||
dwError = WaitForSingleObject(hControlPipe,
|
||||
PipeTimeout);
|
||||
DPRINT("WaitForSingleObject() returned %lu\n", dwError);
|
||||
DPRINT("WaitForSingleObject(%S, %d) returned %lu\n", pServiceName, dwControl, dwError);
|
||||
|
||||
if (dwError == WAIT_TIMEOUT)
|
||||
{
|
||||
DPRINT1("WaitForSingleObject(%S, %d) timed out\n", pServiceName, dwControl, dwError);
|
||||
bResult = CancelIo(hControlPipe);
|
||||
if (bResult == FALSE)
|
||||
{
|
||||
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
|
||||
DPRINT1("CancelIo(%S, %d) failed (Error: %lu)\n", pServiceName, dwControl, GetLastError());
|
||||
}
|
||||
|
||||
dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
|
||||
|
@ -1395,7 +1499,7 @@ ScmControlService(HANDLE hControlPipe,
|
|||
if (bResult == FALSE)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
|
||||
DPRINT1("GetOverlappedResult(%S, %d) failed (Error %lu)\n", pServiceName, dwControl, dwError);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
@ -1403,7 +1507,7 @@ ScmControlService(HANDLE hControlPipe,
|
|||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
|
||||
DPRINT1("WriteFile(%S, %d) failed (Error %lu)\n", pServiceName, dwControl, dwError);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
@ -1418,23 +1522,24 @@ ScmControlService(HANDLE hControlPipe,
|
|||
&Overlapped);
|
||||
if (bResult == FALSE)
|
||||
{
|
||||
DPRINT("ReadFile() returned FALSE\n");
|
||||
DPRINT1("ReadFile(%S, %d) returned FALSE\n", pServiceName, dwControl);
|
||||
|
||||
dwError = GetLastError();
|
||||
if (dwError == ERROR_IO_PENDING)
|
||||
{
|
||||
DPRINT("dwError: ERROR_IO_PENDING\n");
|
||||
DPRINT("(%S, %d) dwError: ERROR_IO_PENDING\n", pServiceName, dwControl);
|
||||
|
||||
dwError = WaitForSingleObject(hControlPipe,
|
||||
PipeTimeout);
|
||||
DPRINT("WaitForSingleObject() returned %lu\n", dwError);
|
||||
DPRINT("WaitForSingleObject(%S, %d) returned %lu\n", pServiceName, dwControl, dwError);
|
||||
|
||||
if (dwError == WAIT_TIMEOUT)
|
||||
{
|
||||
DPRINT1("WaitForSingleObject(%S, %d) timed out\n", pServiceName, dwControl, dwError);
|
||||
bResult = CancelIo(hControlPipe);
|
||||
if (bResult == FALSE)
|
||||
{
|
||||
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
|
||||
DPRINT1("CancelIo(%S, %d) failed (Error: %lu)\n", pServiceName, dwControl, GetLastError());
|
||||
}
|
||||
|
||||
dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
|
||||
|
@ -1449,7 +1554,7 @@ ScmControlService(HANDLE hControlPipe,
|
|||
if (bResult == FALSE)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
|
||||
DPRINT1("GetOverlappedResult(%S, %d) failed (Error %lu)\n", pServiceName, dwControl, dwError);
|
||||
|
||||
goto Done;
|
||||
}
|
||||
|
@ -1457,7 +1562,7 @@ ScmControlService(HANDLE hControlPipe,
|
|||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
|
||||
DPRINT1("ReadFile(%S, %d) failed (Error %lu)\n", pServiceName, dwControl, dwError);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
@ -1475,7 +1580,7 @@ Done:
|
|||
|
||||
LeaveCriticalSection(&ControlServiceCriticalSection);
|
||||
|
||||
DPRINT("ScmControlService() done\n");
|
||||
DPRINT("ScmControlService(%S, %d) done\n", pServiceName, dwControl);
|
||||
|
||||
return dwError;
|
||||
}
|
||||
|
@ -2052,6 +2157,7 @@ ScmLoadService(PSERVICE Service,
|
|||
{
|
||||
Service->Status.dwCurrentState = SERVICE_START_PENDING;
|
||||
Service->Status.dwControlsAccepted = 0;
|
||||
ScmReferenceService(Service);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue