#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