[SERVICES]

- Add optional asynchronous io code for service control pipes. This is disabled by default due to bugs in NPFS.
- Read service pipe timeout value from the registry.

svn path=/trunk/; revision=53686
This commit is contained in:
Eric Kohl 2011-09-11 11:17:25 +00:00
parent 1b9f1974ad
commit 0d4f432270

View file

@ -23,6 +23,13 @@
*/ */
// #define USE_SERVICE_START_PENDING // #define USE_SERVICE_START_PENDING
/*
* Uncomment the line below to use asynchronous IO operations
* on the service control pipes.
*/
// #define USE_ASYNCHRONOUS_IO
/* GLOBALS *******************************************************************/ /* GLOBALS *******************************************************************/
LIST_ENTRY ImageListHead; LIST_ENTRY ImageListHead;
@ -32,6 +39,8 @@ static RTL_RESOURCE DatabaseLock;
static DWORD dwResumeCount = 1; static DWORD dwResumeCount = 1;
static CRITICAL_SECTION ControlServiceCriticalSection; static CRITICAL_SECTION ControlServiceCriticalSection;
static DWORD dwPipeTimeout = 30000; /* 30 Seconds */
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
@ -92,12 +101,16 @@ ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
DPRINT("PipeName: %S\n", szControlPipeName); DPRINT("PipeName: %S\n", szControlPipeName);
pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName, pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
#ifdef USE_ASYNCHRONOUS_IO
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
#else
PIPE_ACCESS_DUPLEX, PIPE_ACCESS_DUPLEX,
#endif
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
100, 100,
8000, 8000,
4, 4,
30000, dwPipeTimeout,
NULL); NULL);
DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
@ -921,6 +934,10 @@ ScmControlService(PSERVICE Service,
DWORD PacketSize; DWORD PacketSize;
PWSTR Ptr; PWSTR Ptr;
DWORD dwError = ERROR_SUCCESS; DWORD dwError = ERROR_SUCCESS;
BOOL bResult;
#ifdef USE_ASYNCHRONOUS_IO
OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
#endif
DPRINT("ScmControlService() called\n"); DPRINT("ScmControlService() called\n");
@ -951,20 +968,140 @@ ScmControlService(PSERVICE Service,
ControlPacket->dwArgumentsCount = 0; ControlPacket->dwArgumentsCount = 0;
ControlPacket->dwArgumentsOffset = 0; ControlPacket->dwArgumentsOffset = 0;
/* Send the control packet */ #ifdef USE_ASYNCHRONOUS_IO
WriteFile(Service->lpImage->hControlPipe, bResult = WriteFile(Service->lpImage->hControlPipe,
ControlPacket, ControlPacket,
PacketSize, PacketSize,
&dwWriteCount, &dwWriteCount,
NULL); &Overlapped);
if (bResult == FALSE)
{
DPRINT1("WriteFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
DPRINT1("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
dwPipeTimeout);
DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
bResult = CancelIo(Service->lpImage->hControlPipe);
if (bResult == FALSE)
{
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
goto Done;
}
else if (dwError == ERROR_SUCCESS)
{
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
&Overlapped,
&dwWriteCount,
TRUE);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
goto Done;
}
}
}
else
{
DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
goto Done;
}
}
/* Read the reply */ /* Read the reply */
ReadFile(Service->lpImage->hControlPipe, Overlapped.hEvent = (HANDLE) NULL;
&ReplyPacket,
sizeof(SCM_REPLY_PACKET),
&dwReadCount,
NULL);
bResult = ReadFile(Service->lpImage->hControlPipe,
&ReplyPacket,
sizeof(SCM_REPLY_PACKET),
&dwReadCount,
&Overlapped);
if (bResult == FALSE)
{
DPRINT1("ReadFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
DPRINT1("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
dwPipeTimeout);
DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
bResult = CancelIo(Service->lpImage->hControlPipe);
if (bResult == FALSE)
{
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
goto Done;
}
else if (dwError == ERROR_SUCCESS)
{
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
&Overlapped,
&dwReadCount,
TRUE);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
goto Done;
}
}
}
else
{
DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
goto Done;
}
}
#else
/* Send the control packet */
bResult = WriteFile(Service->lpImage->hControlPipe,
ControlPacket,
PacketSize,
&dwWriteCount,
NULL);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT("WriteFile() failed (Error %lu)\n", dwError);
goto Done;
}
/* Read the reply */
bResult = ReadFile(Service->lpImage->hControlPipe,
&ReplyPacket,
sizeof(SCM_REPLY_PACKET),
&dwReadCount,
NULL);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT("ReadFile() failed (Error %lu)\n", dwError);
}
#endif
Done:
/* Release the contol packet */ /* Release the contol packet */
HeapFree(GetProcessHeap(), HeapFree(GetProcessHeap(),
0, 0,
@ -1004,6 +1141,10 @@ ScmSendStartCommand(PSERVICE Service,
DWORD i; DWORD i;
PWSTR *pOffPtr; PWSTR *pOffPtr;
PWSTR pArgPtr; PWSTR pArgPtr;
BOOL bResult;
#ifdef USE_ASYNCHRONOUS_IO
OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
#endif
DPRINT("ScmSendStartCommand() called\n"); DPRINT("ScmSendStartCommand() called\n");
@ -1066,20 +1207,140 @@ ScmSendStartCommand(PSERVICE Service,
} }
} }
/* Send the start command */ #ifdef USE_ASYNCHRONOUS_IO
WriteFile(Service->lpImage->hControlPipe, bResult = WriteFile(Service->lpImage->hControlPipe,
ControlPacket, ControlPacket,
PacketSize, PacketSize,
&dwWriteCount, &dwWriteCount,
NULL); &Overlapped);
if (bResult == FALSE)
{
DPRINT1("WriteFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
DPRINT1("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
dwPipeTimeout);
DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
bResult = CancelIo(Service->lpImage->hControlPipe);
if (bResult == FALSE)
{
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
goto Done;
}
else if (dwError == ERROR_SUCCESS)
{
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
&Overlapped,
&dwWriteCount,
TRUE);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
goto Done;
}
}
}
else
{
DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
goto Done;
}
}
/* Read the reply */ /* Read the reply */
ReadFile(Service->lpImage->hControlPipe, Overlapped.hEvent = (HANDLE) NULL;
&ReplyPacket,
sizeof(SCM_REPLY_PACKET),
&dwReadCount,
NULL);
bResult = ReadFile(Service->lpImage->hControlPipe,
&ReplyPacket,
sizeof(SCM_REPLY_PACKET),
&dwReadCount,
&Overlapped);
if (bResult == FALSE)
{
DPRINT1("ReadFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
DPRINT1("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
dwPipeTimeout);
DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
bResult = CancelIo(Service->lpImage->hControlPipe);
if (bResult == FALSE)
{
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
goto Done;
}
else if (dwError == ERROR_SUCCESS)
{
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
&Overlapped,
&dwReadCount,
TRUE);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
goto Done;
}
}
}
else
{
DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
goto Done;
}
}
#else
/* Send the start command */
bResult = WriteFile(Service->lpImage->hControlPipe,
ControlPacket,
PacketSize,
&dwWriteCount,
NULL);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT("WriteFile() failed (Error %lu)\n", dwError);
goto Done;
}
/* Read the reply */
bResult = ReadFile(Service->lpImage->hControlPipe,
&ReplyPacket,
sizeof(SCM_REPLY_PACKET),
&dwReadCount,
NULL);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT("ReadFile() failed (Error %lu)\n", dwError);
}
#endif
Done:
/* Release the contol packet */ /* Release the contol packet */
HeapFree(GetProcessHeap(), HeapFree(GetProcessHeap(),
0, 0,
@ -1096,6 +1357,166 @@ ScmSendStartCommand(PSERVICE Service,
} }
static DWORD
ScmWaitForServiceConnect(PSERVICE Service)
{
DWORD dwRead = 0;
DWORD dwProcessId = 0;
DWORD dwError = ERROR_SUCCESS;
BOOL bResult;
#ifdef USE_ASYNCHRONOUS_IO
OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
#endif
DPRINT1("ScmWaitForServiceConnect()\n");
#ifdef USE_ASYNCHRONOUS_IO
Overlapped.hEvent = (HANDLE)NULL;
bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
&Overlapped);
if (bResult == FALSE)
{
DPRINT1("ConnectNamedPipe() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
DPRINT1("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
dwPipeTimeout);
DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
bResult = CancelIo(Service->lpImage->hControlPipe);
if (bResult == FALSE)
{
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
return ERROR_SERVICE_REQUEST_TIMEOUT;
}
else if (dwError == ERROR_SUCCESS)
{
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
&Overlapped,
&dwRead,
TRUE);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
return dwError;
}
}
}
else if (dwError != ERROR_PIPE_CONNECTED)
{
DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError);
return dwError;
}
}
DPRINT1("Control pipe connected!\n");
Overlapped.hEvent = (HANDLE) NULL;
/* Read the process id from pipe */
bResult = ReadFile(Service->lpImage->hControlPipe,
(LPVOID)&dwProcessId,
sizeof(DWORD),
&dwRead,
&Overlapped);
if (bResult == FALSE)
{
DPRINT1("ReadFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
DPRINT1("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
dwPipeTimeout);
if (dwError == WAIT_TIMEOUT)
{
DPRINT1("WaitForSingleObject() returned WAIT_TIMEOUT\n");
bResult = CancelIo(Service->lpImage->hControlPipe);
if (bResult == FALSE)
{
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
return ERROR_SERVICE_REQUEST_TIMEOUT;
}
else if (dwError == ERROR_SUCCESS)
{
DPRINT1("WaitForSingleObject() returned ERROR_SUCCESS\n");
DPRINT1("Process Id: %lu\n", dwProcessId);
bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
&Overlapped,
&dwRead,
TRUE);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
return dwError;
}
}
else
{
DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
}
}
else
{
DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
return dwError;
}
}
DPRINT1("ScmWaitForServiceConnect() done\n");
return ERROR_SUCCESS;
#else
/* Connect control pipe */
if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
{
DPRINT("Control pipe connected!\n");
/* Read SERVICE_STATUS_HANDLE from pipe */
bResult = ReadFile(Service->lpImage->hControlPipe,
(LPVOID)&dwProcessId,
sizeof(DWORD),
&dwRead,
NULL);
if (bResult == FALSE)
{
dwError = GetLastError();
DPRINT1("Reading the service control pipe failed (Error %lu)\n",
dwError);
}
}
else
{
DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
}
return dwError;
#endif
}
static DWORD static DWORD
ScmStartUserModeService(PSERVICE Service, ScmStartUserModeService(PSERVICE Service,
DWORD argc, DWORD argc,
@ -1105,7 +1526,6 @@ ScmStartUserModeService(PSERVICE Service,
STARTUPINFOW StartupInfo; STARTUPINFOW StartupInfo;
BOOL Result; BOOL Result;
DWORD dwError = ERROR_SUCCESS; DWORD dwError = ERROR_SUCCESS;
DWORD dwProcessId;
DPRINT("ScmStartUserModeService(%p)\n", Service); DPRINT("ScmStartUserModeService(%p)\n", Service);
@ -1156,35 +1576,20 @@ ScmStartUserModeService(PSERVICE Service,
ResumeThread(ProcessInformation.hThread); ResumeThread(ProcessInformation.hThread);
/* Connect control pipe */ /* Connect control pipe */
if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ? dwError = ScmWaitForServiceConnect(Service);
TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED) if (dwError == ERROR_SUCCESS)
{ {
DWORD dwRead = 0; /* Send start command */
dwError = ScmSendStartCommand(Service,
DPRINT("Control pipe connected!\n"); argc,
argv);
/* Read SERVICE_STATUS_HANDLE from pipe */
if (!ReadFile(Service->lpImage->hControlPipe,
(LPVOID)&dwProcessId,
sizeof(DWORD),
&dwRead,
NULL))
{
dwError = GetLastError();
DPRINT1("Reading the service control pipe failed (Error %lu)\n",
dwError);
}
else
{
DPRINT("Received service process ID %lu\n", dwProcessId);
/* Send start command */
dwError = ScmSendStartCommand(Service, argc, argv);
}
} }
else else
{ {
DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
Service->lpImage->dwProcessId = 0;
Service->lpImage->hProcess = NULL;
CloseHandle(ProcessInformation.hProcess);
} }
/* Close thread handle */ /* Close thread handle */
@ -1531,7 +1936,29 @@ ScmUnlockDatabase(VOID)
VOID VOID
ScmInitNamedPipeCriticalSection(VOID) ScmInitNamedPipeCriticalSection(VOID)
{ {
HKEY hKey;
DWORD dwKeySize;
DWORD dwError;
InitializeCriticalSection(&ControlServiceCriticalSection); InitializeCriticalSection(&ControlServiceCriticalSection);
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control",
0,
KEY_READ,
&hKey);
if (dwError == ERROR_SUCCESS)
{
dwKeySize = sizeof(DWORD);
RegQueryValueExW(hKey,
L"ServicesPipeTimeout",
0,
NULL,
(LPBYTE)&dwPipeTimeout,
&dwKeySize);
RegCloseKey(hKey);
}
} }