14 #define ErrorBufferSize 4096
15 #define dwMaxHandles 32
19 static char ErrorBuffer[ErrorBufferSize];
23 static bool pipex_eof_input(pipex_t *pipex);
24 static void pipex_set_eof_input(pipex_t *pipex);
25 static void pipex_set_active(pipex_t *pipex);
26 static int pipex_read_data(pipex_t *pipex);
27 static void pipex_read_input(pipex_t *pipex);
33 static char * win32_error(){
35 FORMAT_MESSAGE_FROM_SYSTEM,
47 static DWORD WINAPI ThreadProc(LPVOID lpParam){
48 pipex_t *p=(pipex_t *) lpParam;
49 while(!pipex_eof_input(p)){
50 if(p->nReadEnd<LINE_INPUT_MAX_CHAR-1){
53 // wait until there is room in buffer
62 void pipex_open(pipex_t *pipex, const char *szName, const char *szProcFile) {
63 DWORD dwMode, dwThreadId;
64 HANDLE hStdinRead, hStdinWrite, hStdoutRead, hStdoutWrite, hThread;
65 SECURITY_ATTRIBUTES sa;
67 PROCESS_INFORMATION pi;
72 if (szProcFile == NULL) {
73 pipex->hInput = GetStdHandle(STD_INPUT_HANDLE);
74 pipex->hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
75 pipex->bConsole = GetConsoleMode(pipex->hInput, &dwMode);
78 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
79 sa.bInheritHandle = TRUE;
80 sa.lpSecurityDescriptor = NULL;
81 CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0);
82 CreatePipe(&hStdoutRead, &hStdoutWrite, &sa, 0);
83 si.cb = sizeof(STARTUPINFO);
84 si.lpReserved = si.lpDesktop = si.lpTitle = NULL;
85 si.dwFlags = STARTF_USESTDHANDLES;
87 si.lpReserved2 = NULL;
88 si.hStdInput = hStdinRead;
89 si.hStdOutput = hStdoutWrite;
90 si.hStdError = hStdoutWrite;
91 if(CreateProcess(NULL,
96 DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
101 pipex->hProcess=pi.hProcess;
102 CloseHandle(pi.hThread);
103 CloseHandle(hStdinRead);
104 CloseHandle(hStdoutWrite);
105 pipex->hInput = hStdoutRead;
106 pipex->hOutput = hStdinWrite;
107 pipex->bConsole = FALSE;
110 my_fatal("pipex_open(): %s",win32_error());
113 if (pipex->bConsole) {
114 SetConsoleMode(pipex->hInput,
115 dwMode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
116 FlushConsoleInputBuffer(pipex->hInput);
118 fdInput=_open_osfhandle((long) pipex->hInput,_O_RDONLY);
120 my_fatal("pipex_open(): %s",strerror(errno));
122 pipex->fpInput=fdopen(fdInput,"r");
123 if(pipex->fpInput==NULL){
124 my_fatal("pipex_open(): %s",strerror(errno));
127 pipex->lpFeedEnd = NULL;
128 InitializeCriticalSection(&(pipex->CriticalSection));
129 pipex->hEvent=CreateEvent(NULL, // default security
131 FALSE, // not signaled
134 if(!(pipex->hEvent)){
135 my_fatal("pipex_open(): %s",win32_error());
137 hThread=CreateThread(NULL, // default security
138 0, // default stacksize
139 ThreadProc, // worker function
140 pipex, // tell worker about ourselves
141 0, // run immediately
142 &dwThreadId // dropped, but needed for the call to work in Win9x
145 my_fatal("pipex_open(): %s",win32_error());
147 pipex_set_active(pipex);
150 // pipex_wait_event(pipex)
152 void pipex_wait_event(pipex_t *pipex[]){
153 HANDLE hHandles[dwMaxHandles];
154 DWORD dwHandleCount=0;
156 while((p=pipex[dwHandleCount])!=NULL){
157 ASSERT((p->hEvent)!=0);
158 if(dwHandleCount>=dwMaxHandles){
159 my_fatal("pipex_wait_event(): Too many objects to wait for");
161 hHandles[dwHandleCount++]=p->hEvent;
163 WaitForMultipleObjects(dwHandleCount, // count
165 FALSE, // return if one object is signaled
166 INFINITE // no timeout
173 void pipex_send_eof(pipex_t *pipex) {
174 my_log("Adapter->%s: EOF\n",pipex->name);
175 CloseHandle(pipex->hOutput);
180 void pipex_exit(pipex_t *pipex) {
181 CloseHandle(pipex->hInput);
182 CloseHandle(pipex->hOutput);
185 if(GetExitCodeProcess(pipex->hProcess,&lpexit)){
186 if(lpexit==STILL_ACTIVE)
187 //must be java,hammer it down!
188 TerminateProcess(pipex->hProcess,lpexit);
190 CloseHandle(pipex->hProcess);
195 static bool pipex_eof_input(pipex_t *pipex){
197 EnterCriticalSection(&(pipex->CriticalSection));
198 ret=(pipex->state)&PIPEX_EOF;
199 LeaveCriticalSection(&(pipex->CriticalSection));
203 // pipex_set_eof_input()
205 static void pipex_set_eof_input(pipex_t *pipex){
206 EnterCriticalSection(&(pipex->CriticalSection));
207 (pipex->state)|=PIPEX_EOF;
208 LeaveCriticalSection(&(pipex->CriticalSection));
209 // not quit the right place
210 my_log("%s->Adapter: EOF\n",pipex->name);
217 * This function returns TRUE if and only if the pipes have succesfully
218 * been created and the client has been started.
222 bool pipex_active(pipex_t *pipex){
224 EnterCriticalSection(&(pipex->CriticalSection));
225 ret=(pipex->state)&PIPEX_ACTIVE;
226 LeaveCriticalSection(&(pipex->CriticalSection));
230 // pipex_set_active()
232 static void pipex_set_active(pipex_t *pipex){
233 EnterCriticalSection(&(pipex->CriticalSection));
234 (pipex->state)|=PIPEX_ACTIVE;
235 LeaveCriticalSection(&(pipex->CriticalSection));
240 static int pipex_read_data(pipex_t *pipex){
243 // No protection. Access to nReadEnd is atomic.
244 // It is not a problem that nReadEnd becomes smaller after the call.
245 // This just means we have read less than we could have.
246 ret=fgets(pipex->lpReadBuffer,
247 LINE_INPUT_MAX_CHAR-(pipex->nReadEnd),
250 pipex_set_eof_input(pipex);
251 (pipex->lpReadBuffer)[0]='\0';
254 dwBytes=strlen(pipex->lpReadBuffer);
255 (pipex->lpReadBuffer)[dwBytes]='\0';
259 // pipex_read_input()
261 static void pipex_read_input(pipex_t *pipex) {
263 BOOL bSetEvent=FALSE;
264 // ReadData is outside the critical section otherwise everything
265 // would block during the blocking read
266 ret=pipex_read_data(pipex);
267 EnterCriticalSection(&(pipex->CriticalSection));
268 if(!pipex_eof_input(pipex)){
269 if(ret+(pipex->nReadEnd)>=LINE_INPUT_MAX_CHAR){
270 my_fatal("pipex_read_input(): Internal error: buffer overflow\n");
272 memcpy((pipex->lpBuffer)+(pipex->nReadEnd),(pipex->lpReadBuffer),ret+1);
273 (pipex->nReadEnd) += ret;
274 if(!(pipex->lpFeedEnd)){
276 (char *) memchr(pipex->lpBuffer,'\n',pipex->nReadEnd);
278 if(pipex->lpFeedEnd){
280 }else if((pipex->nReadEnd)>=LINE_INPUT_MAX_CHAR-1){
281 my_fatal("pipex_read_input(): 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);
284 LeaveCriticalSection(&(pipex->CriticalSection));
285 if(pipex_eof_input(pipex) || bSetEvent){
286 SetEvent(pipex->hEvent);
293 * This function returns TRUE if and only if the input buffer does not
294 * contain a full line of data and EOF was encountered by
295 * the working thread.
299 bool pipex_eof(pipex_t *pipex){
301 EnterCriticalSection(&(pipex->CriticalSection));
302 if((pipex->lpFeedEnd) != NULL){
304 }else if(pipex_eof_input(pipex)){
309 LeaveCriticalSection(&(pipex->CriticalSection));
316 * This function returns FALSE if and only if the asynchronously filled
317 * input buffer does not contain a full line of data.
318 * In other words it operates in non-blocking mode.
322 bool pipex_readln_nb(pipex_t *pipex, char *szLineStr) {
327 EnterCriticalSection(&(pipex->CriticalSection));
328 if ((pipex->lpFeedEnd) == NULL) {
331 nFeedEnd = pipex->lpFeedEnd - pipex->lpBuffer;
332 memcpy(szLineStr, pipex->lpBuffer, nFeedEnd+1);
333 szLineStr[nFeedEnd] = '\0';
335 // temp hack: stolen from util.c
336 // remove CRs and LFs
339 while ((c=szLineStr[src++]) != '\0') {
340 if (c != '\r' && c != '\n') szLineStr[dst++] = c;
342 szLineStr[dst] = '\0';
343 ASSERT(strchr(szLineStr,'\n')==NULL)
344 ASSERT(strchr(szLineStr,'\r')==NULL)
347 pipex->nReadEnd -= nFeedEnd;
348 memcpy(pipex->lpBuffer, pipex->lpBuffer + nFeedEnd, pipex->nReadEnd+1);
350 (char *) memchr(pipex->lpBuffer, '\n', pipex->nReadEnd);
353 LeaveCriticalSection(&(pipex->CriticalSection));
355 my_log("%s->Adapter: %s\n",pipex->name,szLineStr);
363 * This function returns FALSE if and only if EOF has been encountered by
364 * the working thread and no full line of data is present in the input buffer.
366 * If there is a full line of data present in the input buffer it returns
369 * If none of these conditions is satisfied it blocks.
371 * As the name say this function is strictly for line input.
372 * An incomplete line of data (i.e. not ending with \n) is lost when EOF
377 bool pipex_readln(pipex_t *pipex, char *szLineStr) {
378 while(!pipex_eof(pipex)){
379 if (pipex_readln_nb(pipex,szLineStr)) {
382 WaitForSingleObject(pipex->hEvent,INFINITE);
389 // GetWin32Priority()
391 static DWORD GetWin32Priority(int nice)
394 REALTIME_PRIORITY_CLASS 0x00000100
395 HIGH_PRIORITY_CLASS 0x00000080
396 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
397 NORMAL_PRIORITY_CLASS 0x00000020
398 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
399 IDLE_PRIORITY_CLASS 0x00000040
401 if (nice < -15) return 0x00000080;
402 if (nice < 0) return 0x00008000;
403 if (nice == 0) return 0x00000020;
404 if (nice < 15) return 0x00004000;
408 // pipex_set_priority()
410 void pipex_set_priority(pipex_t *pipex, int value){
412 if(!SetPriorityClass(pipex->hProcess,
413 GetWin32Priority(value))){
414 my_log("POLYGLOT Unable to change priority\n");
419 // pipex_set_affinit()
421 void pipex_set_affinity(pipex_t *pipex, int value){
422 if(pipex->hProcess) return;
423 if(value==-1) return;
425 typedef void (WINAPI *SPAM)(HANDLE, int);
427 pSPAM = (SPAM) GetProcAddress(
428 GetModuleHandle(TEXT("kernel32.dll")),
429 "SetProcessAffinityMask");
431 // [HGM] avoid crash on Win95 by first checking if API call exists
432 pSPAM(pipex->hProcess,value);
434 my_log("POLYGLOT API call \"SetProcessAffinityMask\" not available\n");
440 void pipex_writeln(pipex_t *pipex, const char *szLineStr) {
443 char szWriteBuffer[LINE_INPUT_MAX_CHAR];
444 my_log("Adapter->%s: %s\n",pipex->name,szLineStr);
446 nStrLen = strlen(szLineStr);
447 memcpy(szWriteBuffer, szLineStr, nStrLen);
448 szWriteBuffer[nStrLen] = '\r';
449 szWriteBuffer[nStrLen + 1] = '\n';
450 WriteFile(pipex->hOutput, szWriteBuffer, nStrLen + 2, &dwBytes, NULL);
452 printf("%s\n",szLineStr);