Eliminate polling in Linux
authorH.G. Muller <h.g.muller@hccnet.nl>
Sat, 14 Jan 2012 10:56:13 +0000 (11:56 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 14 Jan 2012 10:56:13 +0000 (11:56 +0100)
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

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