From 3fd43cd5fcb22bb65bf2a92a25d95d801b11c9e0 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Wed, 1 Jun 2016 18:58:58 -0700 Subject: Initial checkin for typhoon chess engine. --- src/autoplay/child_process.cc | 188 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 src/autoplay/child_process.cc (limited to 'src/autoplay/child_process.cc') diff --git a/src/autoplay/child_process.cc b/src/autoplay/child_process.cc new file mode 100644 index 0000000..6486a0e --- /dev/null +++ b/src/autoplay/child_process.cc @@ -0,0 +1,188 @@ +#include "child_process.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace util { + +void ChildProcess::ParseCommandline(vector *args) { + char *p = commandline_; + bool in_quote; + do { + // Find the start of a chunk. + while(*p && isspace(*p)) p++; + if (!*p) break; + args->push_back(p); + in_quote = false; + + // Find the end of the chunk. + while (*p) { + if (*p == '"') { + in_quote = !in_quote; + } else if (isspace(*p) && !in_quote) { + break; + } + p++; + } + if (!*p) break; + *p = '\0'; + p++; + } while(1); + args->push_back(NULL); +} + +static volatile bool _child_ready = false; +static void SignalHandler(int signo) { + printf("SIGNAL!\n"); + _child_ready = true; +} + +void ChildProcess::Start() { + Stop(); + vector args; + ParseCommandline(&args); + + if (args.size() > 1) { + if (pipe(read_pipe_) != 0) { + perror("pipe"); + exit(-1); + } + if (pipe(write_pipe_) != 0) { + perror("pipe"); + exit(-1); + } + + // Prepare a signal handler to tell us when the child process is + // ready. + _child_ready = false; + if (signal(SIGUSR1, SignalHandler) == SIG_ERR) { + perror("signal"); + exit(-1); + } + sigset_t zeromask, mask, orig; + sigemptyset(&zeromask); + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + if (sigprocmask(SIG_BLOCK, &mask, &orig) < 0) { + perror("sigprocmask"); + exit(-1); + } + + // Fork. + pid_ = fork(); + if (pid_ < 0) { + perror("fork"); + exit(-1); + } + if (pid_ == 0) { + printf("In the child process...\n"); + + // In the child process we do not need the pipes for parent + // reads and writes. + close(write_pipe_[1]); + close(read_pipe_[0]); + if (dup2(write_pipe_[0], fileno(stdin)) < 0) { + perror("dup2"); + exit(-1); + } + close(write_pipe_[0]); + if (dup2(read_pipe_[1], fileno(stdout)) < 0) { + perror("dup2"); + exit(-1); + } + if (dup2(fileno(stdout), fileno(stderr)) < 0) { + perror("dup2"); + exit(-1); + } + close(read_pipe_[1]); + + // Tell the parent that the pipes are set up then exec the child + // image. + kill(getppid(), SIGUSR1); + execvp(args[0], &(args[0])); + perror("exec"); + exit(-1); + } else { + printf("In the parent process waiting...\n"); + while(!_child_ready) { + sigsuspend(&zeromask); + } + printf("PARENT WAKEUP!\n"); + _child_ready = false; + if (sigprocmask(SIG_SETMASK, &orig, NULL) < 0) { + perror("sigprocmask"); + exit(-1); + } + close(write_pipe_[0]); + close(read_pipe_[1]); + from_ = fdopen(read_pipe_[0], "r"); + to_ = fdopen(write_pipe_[1], "w"); + setbuf(from_, NULL); + setbuf(to_, NULL); + running_ = true; + name_ = args[0]; + } + } +} + +void ChildProcess::Stop() { + if (!running_) { + return; + } + fclose(to_); + fclose(from_); + close(write_pipe_[1]); + close(read_pipe_[0]); + kill(pid_, SIGTERM); + int x; + waitpid(pid_, &x, 0); +} + +void ChildProcess::Send(char *line) { + if (!running_) { + return; + } + fprintf(to_, "%s", line); + printf("%s sent: %s", name_, line); +} + +void ChildProcess::Receive(char *line, int size) { + if (!size) return; + *line = '\0'; + if (!running_) { + return; + } + if (!Poll()) { + return; + } + fgets(line, size, from_); + printf("%s recv: %s\n", name_, line); +} + +bool ChildProcess::Poll() { + fd_set myset; + FD_ZERO(&myset); + FD_SET(read_pipe_[0], &myset); + timeval mytime; + mytime.tv_sec = 0; + mytime.tv_usec = 0; + return select(read_pipe_[0] + 1, &myset, NULL, NULL, &mytime) > 0; +} + +void ChildProcess::Flush() { + static char line[1000]; + while (Poll()) { + Receive(line, 1000); + printf("flush: %s", line); + if (!line[0]) { + break; + } + } +} + +} // namespace -- cgit v1.3