#ifdef _WIN32
#include "pipe.h"
#include "util.h"
+
+// functions
+
+DWORD WINAPI ThreadProc(LPVOID lpParam){
+ PipeStruct *p=(PipeStruct *) lpParam;
+ while(!p->EOF_input()){
+ if(p->nReadEnd<LINE_INPUT_MAX_CHAR-1){
+ p->ReadInput();
+ }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 {
}
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