From: H.G.Muller Date: Tue, 18 Jun 2019 10:48:20 +0000 (+0200) Subject: Kill engines that do not respond to 'quit' in time X-Git-Url: http://hgm.nubati.net/cgi-bin/gitweb.cgi?p=uci2wb.git;a=commitdiff_plain;h=99c8c5430513460d625bbeb59281c3e5812d250e Kill engines that do not respond to 'quit' in time If an engine process is still alive 50ms after the adapter received a 'quit' command, it will now be killed. This is done by the GUI thread (which now also causes the adapter to exit), because the engine thread might be tied up in listening to an engine that has no intention to respond to 'stop'. (Which would be a necessary condition for the engine thread to relay the queued 'quit' command.) --- diff --git a/UCI2WB.c b/UCI2WB.c index 10b1f6d..4ca1598 100644 --- a/UCI2WB.c +++ b/UCI2WB.c @@ -18,16 +18,19 @@ # include HANDLE process; DWORD thread_id; + void Bury(int s) { if(WaitForSingleObject(process, 1000*s+50) != WAIT_OBJECT_0) TerminateProcess(process, 0); } #else # include # include # include # define NO_ERROR 0 # include +# include int GetTickCount() // with thanks to Tord { struct timeval t; gettimeofday(&t, NULL); return t.tv_sec*1000 + t.tv_usec/1000; } //# include int Sleep(int msec) { return usleep(1000*msec); } + int pid; void Bury(int msec) { Sleep(msec+50); if(waitpid(-1, NULL, WNOHANG) <= 0) kill(pid, SIGKILL); } #endif #include #include @@ -52,10 +55,9 @@ int statDepth, statScore, statNodes, statTime, currNr, size, collect, nr, sm, in char currMove[20], moveMap[500][10], /* for analyze mode */ canPonder[20], threadOpt[20], varList[8000], anaOpt[20], checkOptions[8192] = "Ponder"; char pvs[99][999], board[100]; // XQ board for UCCI char *nameWord = "name ", *valueWord = "value ", *wTime = "w", *bTime = "b", *wInc = "winc", *bInc = "binc", newGame; // keywords that differ in UCCI -int unit = 1, drawOffer, scores[99], mpvSP, maxDepth, ponderAlways, newCnt, priority; +int unit = 1, drawOffer, scores[99], mpvSP, maxDepth, ponderAlways, newCnt, priority, killDelay; FILE *toE, *fromE, *fromF; -int pid; char *strcasestr (char *p, char *q) { while(*p) { char *r=p++, *s=q; while(tolower(*r++) == tolower(*s) && *s) s++; if(!*s) return p-1; } return NULL; } @@ -533,7 +535,7 @@ GUI2Engine() p = line; while(qEnd < queue+10000 && (*qEnd++ = *p++) != '\n') {} Sync(WAKEUP); // when 'stop' doesn't catch engine's attention in reasonable time, so the GUI might kill us: - if(!strcmp(command, "quit")) { Sleep(500); EPRINT((f, "quit\n")); } // make sure 'quit' is still sent + if(!strcmp(command, "quit")) { Bury(killDelay); exit(0); } // kill the engine and exit } } } @@ -632,7 +634,7 @@ DoCommand () if(sc == 's') EPRINT((f, "# gameover %s\n", line[8] == '/' ? "draw" : (line[7] == '0') == mySide ? "win" : "lose")) computer = NONE; } - else if(!strcmp(command, "quit")) { EPRINT((f, "# quit\n")) fflush(toE), exit(atoi(line+4)); } + else if(!strcmp(command, "quit")) { EPRINT((f, "# quit\n")) fflush(toE); } else printf("Error (unknown command): %s\n", command); fflush(stdout); @@ -704,7 +706,6 @@ StartEngine(char *cmdLine, char *dir) CloseHandle(hChildStdoutWr); process = piProcInfo.hProcess; - pid = piProcInfo.dwProcessId; fromE = (FILE*) _fdopen( _open_osfhandle((long)hChildStdoutRd, _O_TEXT|_O_RDONLY), "r"); toE = (FILE*) _fdopen( _open_osfhandle((long)hChildStdinWr, _O_WRONLY), "w"); #else