Author: ekohl Date: Sun Sep 11 11:17:25 2011 New Revision: 53686
URL: http://svn.reactos.org/svn/reactos?rev=53686&view=rev Log: [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.
Modified: trunk/reactos/base/system/services/database.c
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 Sep 11 11:17:25 2011 @@ -23,6 +23,13 @@ */ // #define USE_SERVICE_START_PENDING
+/* + * Uncomment the line below to use asynchronous IO operations + * on the service control pipes. + */ +// #define USE_ASYNCHRONOUS_IO + + /* GLOBALS *******************************************************************/
LIST_ENTRY ImageListHead; @@ -32,6 +39,8 @@ static DWORD dwResumeCount = 1;
static CRITICAL_SECTION ControlServiceCriticalSection; +static DWORD dwPipeTimeout = 30000; /* 30 Seconds */ +
/* FUNCTIONS *****************************************************************/
@@ -92,12 +101,16 @@ DPRINT("PipeName: %S\n", szControlPipeName);
pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName, +#ifdef USE_ASYNCHRONOUS_IO + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, +#else PIPE_ACCESS_DUPLEX, +#endif PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 100, 8000, 4, - 30000, + dwPipeTimeout, NULL); DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) @@ -921,6 +934,10 @@ DWORD PacketSize; PWSTR Ptr; DWORD dwError = ERROR_SUCCESS; + BOOL bResult; +#ifdef USE_ASYNCHRONOUS_IO + OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; +#endif
DPRINT("ScmControlService() called\n");
@@ -951,20 +968,140 @@ ControlPacket->dwArgumentsCount = 0; ControlPacket->dwArgumentsOffset = 0;
+#ifdef USE_ASYNCHRONOUS_IO + bResult = WriteFile(Service->lpImage->hControlPipe, + ControlPacket, + PacketSize, + &dwWriteCount, + &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 */ + Overlapped.hEvent = (HANDLE) 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 */ - WriteFile(Service->lpImage->hControlPipe, - ControlPacket, - PacketSize, - &dwWriteCount, - NULL); + 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 */ - ReadFile(Service->lpImage->hControlPipe, - &ReplyPacket, - sizeof(SCM_REPLY_PACKET), - &dwReadCount, - NULL); - + 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 */ HeapFree(GetProcessHeap(), 0, @@ -1004,6 +1141,10 @@ DWORD i; PWSTR *pOffPtr; PWSTR pArgPtr; + BOOL bResult; +#ifdef USE_ASYNCHRONOUS_IO + OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; +#endif
DPRINT("ScmSendStartCommand() called\n");
@@ -1066,20 +1207,140 @@ } }
+#ifdef USE_ASYNCHRONOUS_IO + bResult = WriteFile(Service->lpImage->hControlPipe, + ControlPacket, + PacketSize, + &dwWriteCount, + &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 */ + Overlapped.hEvent = (HANDLE) 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 */ - WriteFile(Service->lpImage->hControlPipe, - ControlPacket, - PacketSize, - &dwWriteCount, - NULL); + 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 */ - ReadFile(Service->lpImage->hControlPipe, - &ReplyPacket, - sizeof(SCM_REPLY_PACKET), - &dwReadCount, - NULL); - + 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 */ HeapFree(GetProcessHeap(), 0, @@ -1097,6 +1358,166 @@
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 ScmStartUserModeService(PSERVICE Service, DWORD argc, LPWSTR *argv) @@ -1105,7 +1526,6 @@ STARTUPINFOW StartupInfo; BOOL Result; DWORD dwError = ERROR_SUCCESS; - DWORD dwProcessId;
DPRINT("ScmStartUserModeService(%p)\n", Service);
@@ -1156,35 +1576,20 @@ ResumeThread(ProcessInformation.hThread);
/* Connect control pipe */ - if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ? - TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED) - { - DWORD dwRead = 0; - - DPRINT("Control pipe connected!\n"); - - /* 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); - } + dwError = ScmWaitForServiceConnect(Service); + if (dwError == ERROR_SUCCESS) + { + /* Send start command */ + dwError = ScmSendStartCommand(Service, + argc, + argv); } else { DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); + Service->lpImage->dwProcessId = 0; + Service->lpImage->hProcess = NULL; + CloseHandle(ProcessInformation.hProcess); }
/* Close thread handle */ @@ -1531,7 +1936,29 @@ VOID ScmInitNamedPipeCriticalSection(VOID) { + HKEY hKey; + DWORD dwKeySize; + DWORD dwError; + 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); + } }