X-Git-Url: http://winboard.nl/cgi-bin?p=polyglot.git;a=blobdiff_plain;f=pipe.cpp;h=170da4a82001a1d8178f8276dbe093ba8055a7f9;hp=3f8da2e297cb6fb3e496e14065264b6767f11fcb;hb=acb140befabd8b0f1a8606470013b420d05b4fb7;hpb=64f72f31685ea1dff12b19b22cfaf7a53ccc079f diff --git a/pipe.cpp b/pipe.cpp index 3f8da2e..170da4a 100644 --- a/pipe.cpp +++ b/pipe.cpp @@ -1,125 +1,225 @@ #ifdef _WIN32 #include "pipe.h" #include "util.h" + +// functions + +DWORD WINAPI ThreadProc(LPVOID lpParam){ + PipeStruct *p=(PipeStruct *) lpParam; + while(!p->EOF_input()){ + if(p->nReadEndReadInput(); + }else{ + // wait until there is room in buffer + Sleep(10); + } + } + return 0; +} + + + void PipeStruct::Open(const char *szProcFile) { - DWORD dwMode; - HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite; - SECURITY_ATTRIBUTES sa; - STARTUPINFO si; - PROCESS_INFORMATION pi; - - if (szProcFile == NULL) { - hInput = GetStdHandle(STD_INPUT_HANDLE); - hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - bConsole = GetConsoleMode(hInput, &dwMode); - } else { - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0); - CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0); - si.cb = sizeof(STARTUPINFO); - si.lpReserved = si.lpDesktop = si.lpTitle = NULL; - si.dwFlags = STARTF_USESTDHANDLES; - si.cbReserved2 = 0; - si.lpReserved2 = NULL; - si.hStdInput = hStdinRead; - si.hStdOutput = hStdoutWrite; - si.hStdError = hStdoutWrite; - if(!CreateProcess(NULL, (LPSTR) szProcFile, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)){ - my_fatal("PipeStruct::Open(): Could not start \"%s\"\n",szProcFile); + DWORD dwMode, dwThreadId; + HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite; + SECURITY_ATTRIBUTES sa; + STARTUPINFO si; + PROCESS_INFORMATION pi; + int fdInput; + state=0; + if (szProcFile == NULL) { + hInput = GetStdHandle(STD_INPUT_HANDLE); + hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + bConsole = GetConsoleMode(hInput, &dwMode); + bPipe=FALSE; + } else { + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0); + CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0); + si.cb = sizeof(STARTUPINFO); + si.lpReserved = si.lpDesktop = si.lpTitle = NULL; + si.dwFlags = STARTF_USESTDHANDLES; + si.cbReserved2 = 0; + si.lpReserved2 = NULL; + si.hStdInput = hStdinRead; + si.hStdOutput = hStdoutWrite; + si.hStdError = hStdoutWrite; + if(CreateProcess(NULL, + (LPSTR) szProcFile, + NULL, + NULL, + TRUE, + DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, + NULL, + NULL, + &si, + &pi)){ + hProcess=pi.hProcess; + CloseHandle(pi.hThread); + CloseHandle(hStdinRead); + CloseHandle(hStdoutWrite); + hInput = hStdoutRead; + hOutput = hStdinWrite; + bConsole = FALSE; + bPipe=TRUE; + }else{ + my_fatal("PipeStruct::Open(): %s",my_error()); + } } - hProcess=pi.hProcess; - //CloseHandle(pi.hProcess);//not here,baby,but in pipe.close - CloseHandle(pi.hThread); - CloseHandle(hStdinRead); - CloseHandle(hStdoutWrite); - hInput = hStdoutRead; - hOutput = hStdinWrite; - bConsole = FALSE; - } - if (bConsole) { - SetConsoleMode(hInput, dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)); - FlushConsoleInputBuffer(hInput); - } else { - nBytesLeft = 0; - } - nReadEnd = 0; + if (bConsole) { + SetConsoleMode(hInput, + dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)); + FlushConsoleInputBuffer(hInput); + } + fdInput=_open_osfhandle((long) hInput,_O_RDONLY); + if(fdInput==-1){ + my_fatal("PipeStruct::Open(): %s",my_error()); + } + fpInput=fdopen(fdInput,"r"); + if(fpInput==NULL){ + my_fatal("PipeStruct::Open(): %s",my_error()); + } + nReadEnd = 0; + lpFeedEnd = NULL; + InitializeCriticalSection(&CriticalSection); + hEvent=CreateEvent(NULL, // default security + FALSE, // auto reset + FALSE, // not signaled + NULL // nameless + ); + if(!hEvent){ + my_fatal("PipeStruct::Open(): %s",my_error()); + } + hThread=CreateThread(NULL, // default security + 0, // default stacksize + ThreadProc, // worker function + this, // tell worker about ourselves + 0, // run immediately + &dwThreadId // dropped, but needed for the call to work in Win9x + ); + if(!hThread){ + my_fatal("PipeStruct::Open(): %s",my_error()); + } + set_Active(); } + void PipeStruct::Close(void) const { - CloseHandle(hInput); - CloseHandle(hOutput); - DWORD lpexit; - - my_log("POLYGLOT Closing child\n"); - if(GetExitCodeProcess(hProcess,&lpexit)){ - if(lpexit==STILL_ACTIVE) - my_log("POLYGLOT Process still active after \"quit\" "); - //must be java,hammer it down! - TerminateProcess(hProcess,lpexit); - } + CloseHandle(hOutput); +} + +void PipeStruct::Kill(void) const { + CloseHandle(hInput); + CloseHandle(hOutput); + DWORD lpexit; + + if(GetExitCodeProcess(hProcess,&lpexit)){ + if(lpexit==STILL_ACTIVE) + //must be java,hammer it down! + TerminateProcess(hProcess,lpexit); + } CloseHandle(hProcess); } -void PipeStruct::ReadInput(void) { - DWORD dwBytes; - if(!ReadFile(hInput, szBuffer + nReadEnd, LINE_INPUT_MAX_CHAR - nReadEnd, &dwBytes, NULL)){ - // TODO move this comment to a more suitable place - my_log("POLYGLOT *** EOF from Engine or GUI ***\n"); - exit(EXIT_SUCCESS); // if we are here there should be data! - } - nReadEnd += dwBytes; - if (nBytesLeft > 0) { - nBytesLeft -= dwBytes; - } +bool PipeStruct::EOF_input(void){ // EOF is defined + int ret; + EnterCriticalSection(&CriticalSection); + ret=state&PIPE_EOF; + LeaveCriticalSection(&CriticalSection); + return ret; } -bool PipeStruct::CheckInput(void) { - DWORD dwEvents, dwBytes; - if (bConsole) { // a tty, or an un-redirected handle - GetNumberOfConsoleInputEvents(hInput, &dwEvents); - if (dwEvents > 1) { - return TRUE; - } else { - return FALSE; - } - } else { // a handle redirected to a pipe or a file - if (nBytesLeft > 0) { - return TRUE; - } else { - if (PeekNamedPipe(hInput, NULL, 0, NULL, &dwBytes, NULL)) { - nBytesLeft = dwBytes; - return nBytesLeft > 0; // a pipe - } else { - return TRUE; // a file, always TRUE - } +void PipeStruct::set_EOF_input(void){ + EnterCriticalSection(&CriticalSection); + state|=PIPE_EOF; + LeaveCriticalSection(&CriticalSection); +} + +bool PipeStruct::Active(void){ + int ret; + EnterCriticalSection(&CriticalSection); + ret=state&PIPE_ACTIVE; + LeaveCriticalSection(&CriticalSection); + return ret; +} + +void PipeStruct::set_Active(void){ + EnterCriticalSection(&CriticalSection); + state|=PIPE_ACTIVE; + LeaveCriticalSection(&CriticalSection); +} + +int PipeStruct::ReadData(void){ + DWORD dwBytes; + char * ret; + // No protection. Access to nReadEnd is atomic. + // It is not a problem that nReadEnd becomes smaller after the call. + // This just means we have read less than we could have. + ret=fgets(lpReadBuffer,LINE_INPUT_MAX_CHAR-nReadEnd,fpInput); + if(!ret){ + set_EOF_input(); + lpReadBuffer[0]='\0'; + return 0; } - } + dwBytes=strlen(lpReadBuffer); + lpReadBuffer[dwBytes]='\0'; + return dwBytes; } -void PipeStruct::LineOutput(const char *szLineStr) const { +void PipeStruct::ReadInput(void) { DWORD dwBytes; - int nStrLen; - char szWriteBuffer[LINE_INPUT_MAX_CHAR]; - nStrLen = strlen(szLineStr); - memcpy(szWriteBuffer, szLineStr, nStrLen); - szWriteBuffer[nStrLen] = '\r'; - szWriteBuffer[nStrLen + 1] = '\n'; - WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL); + int ret; + BOOL bSetEvent=FALSE; + // ReadData is outside the critical section otherwise everything + // would block during the blocking read + ret=ReadData(); + EnterCriticalSection(&CriticalSection); + if(!EOF_input()){ + if(ret+nReadEnd>=LINE_INPUT_MAX_CHAR){ + my_fatal("PipeStruct::ReadInput(): Internal error: buffer overflow\n"); + } + memcpy(lpBuffer+nReadEnd,lpReadBuffer,ret+1); + nReadEnd += ret; + if(!lpFeedEnd){ + lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd); + } + if(lpFeedEnd){ + bSetEvent=TRUE; + }else if(nReadEnd>=LINE_INPUT_MAX_CHAR-1){ + my_fatal("PipeStruct::ReadInput(): LINE_INPUT_MAX_CHAR is equal to %d which is too small to contain a full line of engine output or GUI input.\n",LINE_INPUT_MAX_CHAR); + } + } + LeaveCriticalSection(&CriticalSection); + if(EOF_input() || bSetEvent){ + SetEvent(hEvent); + } } - +bool PipeStruct::EOF_(void){ + int ret; + EnterCriticalSection(&CriticalSection); + if(lpFeedEnd != NULL){ + ret=FALSE; + }else if(EOF_input()){ + ret=TRUE; + }else{ + ret=FALSE; + } + LeaveCriticalSection(&CriticalSection); + return ret; +} bool PipeStruct::GetBuffer(char *szLineStr) { - char *lpFeedEnd; int nFeedEnd; - lpFeedEnd = (char *) memchr(szBuffer, '\n', nReadEnd); + int ret; + EnterCriticalSection(&CriticalSection); if (lpFeedEnd == NULL) { - return FALSE; + ret=FALSE; } else { - nFeedEnd = lpFeedEnd - szBuffer; - memcpy(szLineStr, szBuffer, nFeedEnd); + nFeedEnd = lpFeedEnd - lpBuffer; + memcpy(szLineStr, lpBuffer, nFeedEnd); if (szLineStr[nFeedEnd - 1] == '\r') { szLineStr[nFeedEnd - 1] = '\0'; } else { @@ -127,32 +227,39 @@ bool PipeStruct::GetBuffer(char *szLineStr) { } nFeedEnd ++; nReadEnd -= nFeedEnd; - memcpy(szBuffer, szBuffer + nFeedEnd, nReadEnd); - return TRUE; + memcpy(lpBuffer, lpBuffer + nFeedEnd, nReadEnd); + lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd); + ret=TRUE; } + LeaveCriticalSection(&CriticalSection); + return ret; } -bool PipeStruct::LineInput(char *szLineStr) { - if (GetBuffer(szLineStr)) { - return TRUE; - } - if (CheckInput()) { - ReadInput(); - if (GetBuffer(szLineStr)) { - return TRUE; - } else { - if (nReadEnd == LINE_INPUT_MAX_CHAR) { - memcpy(szLineStr, szBuffer, LINE_INPUT_MAX_CHAR - 1); - szLineStr[LINE_INPUT_MAX_CHAR - 1] = '\0'; - szBuffer[0] = szBuffer[LINE_INPUT_MAX_CHAR - 1]; - nReadEnd = 1; - return TRUE; - } else { - return FALSE; - } + + +void PipeStruct::LineInput(char *szLineStr) { + while(!EOF_()){ + if (GetBuffer(szLineStr)) { + break; + }else{ + WaitForSingleObject(hEvent,INFINITE); + } } - } else { - return FALSE; +} + +void PipeStruct::LineOutput(const char *szLineStr) const { + DWORD dwBytes; + int nStrLen; + char szWriteBuffer[LINE_INPUT_MAX_CHAR]; + if(bPipe){ + nStrLen = strlen(szLineStr); + memcpy(szWriteBuffer, szLineStr, nStrLen); + szWriteBuffer[nStrLen] = '\r'; + szWriteBuffer[nStrLen + 1] = '\n'; + WriteFile(hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL); + }else{ + printf("%s\n",szLineStr); + fflush(stdout); } } #endif