// functions
-DWORD WINAPI ThreadProc(LPVOID lpParam){
+DWORD WINAPI ThreadProc(LPVOID lpParam){
PipeStruct *p=(PipeStruct *) lpParam;
- while(!p->EOF_()){
- p->ReadInput();
+ 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;
+ 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);
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
- NULL // nameless
+ &dwThreadId // dropped, but needed for the call to work in Win9x
);
-
+ if(!hThread){
+ my_fatal("PipeStruct::Open(): %s",my_error());
+ }
set_Active();
}
CloseHandle(hProcess);
}
-bool PipeStruct::EOF_(void){ // EOF is defined
+bool PipeStruct::EOF_input(void){ // EOF is defined
int ret;
EnterCriticalSection(&CriticalSection);
ret=state&PIPE_EOF;
return ret;
}
-void PipeStruct::set_EOF_(void){
+void PipeStruct::set_EOF_input(void){
EnterCriticalSection(&CriticalSection);
state|=PIPE_EOF;
LeaveCriticalSection(&CriticalSection);
LeaveCriticalSection(&CriticalSection);
}
-
-
-int PipeStruct::ReadLine(void){
+int PipeStruct::ReadData(void){
DWORD dwBytes;
- int ret;
- int start=0;
- int start1;
-
- if(!bPipe){
- fgets(lpReadBuffer,LINE_INPUT_MAX_CHAR,stdin);
- start=strlen(lpReadBuffer);
- if(!start){
- set_EOF_();
- lpReadBuffer[0]='\0';
- }
- return start;
- }else{
- while(TRUE){
- // Unfortunately we need to use polling here.
- // Otherwise Windows returns single bytes if
- // the engine runs at low priority.
- // This kills performance.
- while(TRUE){
- ret=PeekNamedPipe(hInput,
- NULL, // don't read anything yet
- 0, // no buffer
- NULL, // no we don't read anything!
- &dwBytes,// now we're talking
- NULL); // nono we don't read anything
- if(!ret){
- set_EOF_();
- lpReadBuffer[0]='\0';
- return 0;
- }
- if(dwBytes>0){
- break;
- }else{
- Idle();
- }
-
- }
- ret=ReadFile(hInput,
- lpReadBuffer+start,
- LINE_INPUT_MAX_CHAR-start,
- &dwBytes,
- NULL);
- if(!ret){
- set_EOF_();
- lpReadBuffer[0]='\0';
- return 0;
- }else{
- start1=start;
- start+=dwBytes;
- if (memchr(lpReadBuffer+start1, '\n', dwBytes)){
- lpReadBuffer[start]='\0';
- return start;
- }
- }
- }
+ 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::ReadInput(void) {
DWORD dwBytes;
int ret;
- ret=ReadLine();
+ BOOL bSetEvent=FALSE;
+ // ReadData is outside the critical section otherwise everything
+ // would block during the blocking read
+ ret=ReadData();
EnterCriticalSection(&CriticalSection);
- if(!EOF_()){
+ if(!EOF_input()){
if(ret+nReadEnd>=LINE_INPUT_MAX_CHAR){
- my_fatal("PipeStruct::ReadInput(): buffer overflow\n");
+ my_fatal("PipeStruct::ReadInput(): Internal error: buffer overflow\n");
}
- memcpy(lpBuffer+nReadEnd,lpReadBuffer,ret);
+ 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);
- SetEvent(hEvent);
+ if(EOF_input() || bSetEvent){
+ SetEvent(hEvent);
+ }
}
-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);
+bool PipeStruct::EOF_(void){
+ int ret;
+ EnterCriticalSection(&CriticalSection);
+ if(lpFeedEnd != NULL){
+ ret=FALSE;
+ }else if(EOF_input()){
+ ret=TRUE;
}else{
- printf("%s\n",szLineStr);
- fflush(stdout);
+ ret=FALSE;
}
+ LeaveCriticalSection(&CriticalSection);
+ return ret;
}
bool PipeStruct::GetBuffer(char *szLineStr) {
- char *lpFeedEnd;
int nFeedEnd;
int ret;
EnterCriticalSection(&CriticalSection);
- lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
if (lpFeedEnd == NULL) {
ret=FALSE;
} else {
nFeedEnd ++;
nReadEnd -= nFeedEnd;
memcpy(lpBuffer, lpBuffer + nFeedEnd, nReadEnd);
+ lpFeedEnd = (char *) memchr(lpBuffer, '\n', nReadEnd);
ret=TRUE;
}
LeaveCriticalSection(&CriticalSection);
return ret;
}
+
+
void PipeStruct::LineInput(char *szLineStr) {
- while(!EOF_()){
+ while(!EOF_()){
if (GetBuffer(szLineStr)) {
break;
}else{
}
}
}
+
+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