/* DroidFish - An Android chess program. Copyright (C) 2011 Peter Ă–sterlund, peterosterlund2@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include int main(int argc, char* argv[]); static int fdFromChild = -1; static int fdToChild = -1; /* * Class: org_petero_droidfish_engine_NativePipedProcess * Method: startProcess * Signature: ()V */ extern "C" JNIEXPORT void JNICALL Java_org_petero_droidfish_engine_NativePipedProcess_startProcess (JNIEnv* env, jobject obj) { int fd1[2]; /* parent -> child */ int fd2[2]; /* child -> parent */ if (pipe(fd1) < 0) exit(1); if (pipe(fd2) < 0) exit(1); int childpid = fork(); if (childpid == -1) { exit(1); } if (childpid == 0) { close(fd1[1]); close(fd2[0]); close(0); dup(fd1[0]); close(fd1[0]); close(1); dup(fd2[1]); close(fd2[1]); close(2); dup(1); static char* argv[] = {(char*)"stockfish", NULL}; nice(10); main(1, argv); _exit(0); } else { close(fd1[0]); close(fd2[1]); fdFromChild = fd2[0]; fdToChild = fd1[1]; fcntl(fdFromChild, F_SETFL, O_NONBLOCK); } } static std::deque inBuf; static bool getNextChar(int& c, int timeoutMillis) { if (inBuf.empty()) { fd_set readfds, writefds; FD_ZERO(&readfds); FD_SET(fdFromChild, &readfds); struct timeval tv; tv.tv_sec = timeoutMillis / 1000; tv.tv_usec = (timeoutMillis % 1000) * 1000; int ret = select(fdFromChild + 1, &readfds, NULL, NULL, &tv); if (ret < 0) return false; static char buf[4096]; int len = read(fdFromChild, &buf[0], sizeof(buf)); for (int i = 0; i < len; i++) inBuf.push_back(buf[i]); } if (inBuf.empty()) { c = -1; return true; } c = inBuf.front(); inBuf.pop_front(); return true; } static std::vector lineBuf; /* * Class: org_petero_droidfish_engine_NativePipedProcess * Method: readFromProcess * Signature: (I)Ljava/lang/String; */ extern "C" JNIEXPORT jstring JNICALL Java_org_petero_droidfish_engine_NativePipedProcess_readFromProcess (JNIEnv* env, jobject obj, jint timeoutMillis) { struct timeval tv0, tv1; while (true) { int c; gettimeofday(&tv0, NULL); if (!getNextChar(c, timeoutMillis)) return 0; // Error gettimeofday(&tv1, NULL); int elapsedMillis = (tv1.tv_sec - tv0.tv_sec) * 1000 + (tv1.tv_usec - tv0.tv_usec) / 1000; if (elapsedMillis > 0) { timeoutMillis -= elapsedMillis; if (timeoutMillis < 0) timeoutMillis = 0; } if (c == -1) { // Timeout static char emptyString = 0; return (*env).NewStringUTF(&emptyString); } if (c == '\n' || (c == '\r')) { if (lineBuf.size() > 0) { lineBuf.push_back(0); jstring ret = (*env).NewStringUTF(&lineBuf[0]); lineBuf.clear(); return ret; } } else { lineBuf.push_back((char)c); } } } /* * Class: org_petero_droidfish_engine_NativePipedProcess * Method: writeToProcess * Signature: (Ljava/lang/String;)V */ extern "C" JNIEXPORT void JNICALL Java_org_petero_droidfish_engine_NativePipedProcess_writeToProcess (JNIEnv* env, jobject obj, jstring msg) { const char* str = (*env).GetStringUTFChars(msg, NULL); if (str) { int len = strlen(str); int written = 0; while (written < len) { int n = write(fdToChild, &str[written], len - written); if (n <= 0) break; written += n; } (*env).ReleaseStringUTFChars(msg, str); } } /* * Class: org_petero_droidfish_engine_NativePipedProcess * Method: getNPhysicalProcessors * Signature: ()I */ extern "C" JNIEXPORT jint JNICALL Java_org_petero_droidfish_engine_NativePipedProcess_getNPhysicalProcessors (JNIEnv *, jclass) { return sysconf(_SC_NPROCESSORS_ONLN); }