From 64739477abdd86edbea682069de301b3affddddc Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Sat, 14 Jan 2012 11:56:13 +0100 Subject: [PATCH] Eliminate polling in Linux The sleep-spaced polling for readyok or bestmove has now been replaced by pipe-based blocking of the waiting thread, waking it up by writing a character into the pipe. --- UCI2WB.c | 107 +++++++++++++++++++++++++++++++++++++------------------------- 1 files changed, 64 insertions(+), 43 deletions(-) diff --git a/UCI2WB.c b/UCI2WB.c index 6b454de..e709384 100644 --- a/UCI2WB.c +++ b/UCI2WB.c @@ -4,15 +4,15 @@ #include #include -#ifdef WIN32 -# include +#ifdef WIN32 +# include # include HANDLE process; DWORD thread_id; -#else -# include -# include -# define NO_ERROR 0 +#else +# include +# include +# define NO_ERROR 0 # include int GetTickCount() // with thanks to Tord { struct timeval t; gettimeofday(&t, NULL); return t.tv_sec*1000 + t.tv_usec/1000; } @@ -41,6 +41,25 @@ int statDepth, statScore, statNodes, statTime, currNr, size; char currMove[20]; FILE *toE, *fromE; int pid; +#define INIT 0 +#define WAKEUP 1 +#define PAUSE 2 + +void +Sync (int action) +{ +#ifdef WIN32 + if(action == PAUSE) while(pause) SLEEP(); // in Windows we still rely on polling. :-( +#else + static int syncPipe[2]; char c; + switch(action) { + case INIT: pipe(syncPipe); break; + case WAKEUP: write(syncPipe[1], "\n", 1); break; + case PAUSE: read(syncPipe[0], &c, 1); + } +#endif +} + void StartSearch(char *ponder) { // send the 'go' command to engine. Suffix by ponder. @@ -61,8 +80,8 @@ StopPonder(int pondering) { if(!pondering) return; pause = 1; - fprintf(toE, "stop\n");printf("# stop\n"); // note: 'pondering' remains set until engine acknowledges 'stop' with 'bestmove' - while(pause) SLEEP(); // wait for engine to acknowledge 'stop' with 'bestmove'. + fprintf(toE, "stop\n"); fflush(toE); printf("# stop\n"); // note: 'pondering' remains set until engine acknowledges 'stop' with 'bestmove' + Sync(PAUSE); // wait for engine to acknowledge 'stop' with 'bestmove'. } void @@ -99,10 +118,10 @@ Engine2GUI() while((line[i] = x = fgetc(fromE)) != EOF && line[i] != '\n') i++; line[++i] = 0; if(x == EOF) exit(0); -printf("# engine said: %s", line); +printf("# engine said: %s", line); fflush(stdout); sscanf(line, "%s", command); if(!strcmp(command, "bestmove")) { - if(pause) { pondering = pause = 0; continue; } // bestmove was reply to ponder miss or analysis result; ignore. + if(pause) { pondering = pause = 0; Sync(WAKEUP); continue; } // bestmove was reply to ponder miss or analysis result; ignore. // move was a move to be played if(strstr(line+9, "resign")) { printf("resign\n"); computer = NONE; } if(strstr(line+9, "(none)") || strstr(line+9, "null") || @@ -194,7 +213,7 @@ printf("# ponder on %s\n", move[moveNr]); char name[256]; if(sscanf(line, "id name %s", name) == 1) printf("feature myname=\"%s (U%cI2WB)\"\n", name, sc-32); } - else if(!strcmp(command, "readyok")) pause = 0; // resume processing of GUI commands + else if(!strcmp(command, "readyok")) { pause = 0; Sync(WAKEUP); } // resume processing of GUI commands else if(sscanf(command, "u%ciok", &c)==1 && c==sc) printf("feature smp=1 memory=%d done=1\n", hasHash); // done with options } } @@ -218,9 +237,8 @@ printf("# start search\n"); nomove: fflush(toE); fflush(stdout); i = 0; while((x = getchar()) != EOF && (line[i] = x) != '\n') i++; - line[++i] = 0; if(x == EOF) { printf("# EOF\n"); exit(-1); } + line[++i] = 0; if(x == EOF) { printf("# EOF\n"); exit(-1); } sscanf(line, "%s", command); - while(pause) SLEEP(); // wait for readyok if(!strcmp(command, "new")) { computer = BLACK; moveNr = 0; depth = -1; stm = WHITE; strcpy(iniPos, "position startpos"); @@ -229,7 +247,8 @@ printf("# start search\n"); // we can set other options here pause = 1; // wait for option settings to take effect fprintf(toE, "isready\n"); - fprintf(toE, "u%cinewgame\n", sc); + fprintf(toE, "u%cinewgame\n", sc); fflush(toE); + Sync(PAUSE); // wait for readyok } else if(!strcmp(command, "usermove")) { if(sc == 's') { @@ -318,7 +337,7 @@ printf("# start search\n"); int StartEngine(char *cmdLine, char *dir) -{ +{ #ifdef WIN32 HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr; @@ -379,30 +398,30 @@ StartEngine(char *cmdLine, char *dir) 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 - char *argv[10], *p, buf[200]; - int i, toEngine[2], fromEngine[2]; - - if (dir && dir[0] && chdir(dir)) { perror(dir); exit(1); } - pipe(toEngine); pipe(fromEngine); // create two pipes - - if ((pid = fork()) == 0) { // Child - dup2(toEngine[0], 0); close(toEngine[0]); close(toEngine[1]); // stdin from toE pipe - dup2(fromEngine[1], 1); close(fromEngine[0]); close(fromEngine[1]); // stdout into fromE pipe - dup2(1, fileno(stderr)); // stderr into frome pipe - - strcpy(buf, cmdLine); p = buf; - for (i=0;;) { argv[i++] = p; p = strchr(p, ' '); if (p == NULL) break; *p++ = 0; } - argv[i] = NULL; - execvp(argv[0], argv); // startup engine - - perror(argv[0]); exit(1); // could not start engine; quit. - } - signal(SIGPIPE, SIG_IGN); - close(toEngine[0]); close(fromEngine[1]); // close engine ends of pipes in adapter - - fromE = (FILE*) fdopen(fromEngine[0], "r"); // make into high-level I/O - toE = (FILE*) fdopen(toEngine[1], "w"); +#else + char *argv[10], *p, buf[200]; + int i, toEngine[2], fromEngine[2]; + + if (dir && dir[0] && chdir(dir)) { perror(dir); exit(1); } + pipe(toEngine); pipe(fromEngine); // create two pipes + + if ((pid = fork()) == 0) { // Child + dup2(toEngine[0], 0); close(toEngine[0]); close(toEngine[1]); // stdin from toE pipe + dup2(fromEngine[1], 1); close(fromEngine[0]); close(fromEngine[1]); // stdout into fromE pipe + dup2(1, fileno(stderr)); // stderr into frome pipe + + strcpy(buf, cmdLine); p = buf; + for (i=0;;) { argv[i++] = p; p = strchr(p, ' '); if (p == NULL) break; *p++ = 0; } + argv[i] = NULL; + execvp(argv[0], argv); // startup engine + + perror(argv[0]); exit(1); // could not start engine; quit. + } + signal(SIGPIPE, SIG_IGN); + close(toEngine[0]); close(fromEngine[1]); // close engine ends of pipes in adapter + + fromE = (FILE*) fdopen(fromEngine[0], "r"); // make into high-level I/O + toE = (FILE*) fdopen(toEngine[1], "w"); #endif return NO_ERROR; } @@ -420,11 +439,13 @@ main(int argc, char **argv) // spawn engine proc if(StartEngine(argv[1], dir) != NO_ERROR) { perror(argv[1]), exit(-1); } + Sync(INIT); + // create separate thread to handle engine->GUI traffic -#ifdef WIN32 - CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Engine2GUI, (LPVOID) NULL, 0, &thread_id); -#else - { pthread_t t; signal(SIGINT, SIG_IGN); pthread_create(&t, NULL, Engine2GUI, NULL); } +#ifdef WIN32 + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Engine2GUI, (LPVOID) NULL, 0, &thread_id); +#else + { pthread_t t; signal(SIGINT, SIG_IGN); pthread_create(&t, NULL, Engine2GUI, NULL); } #endif // handle GUI->engine traffic in original thread -- 1.7.0.4