diff options
Diffstat (limited to 'src/autoplay')
| -rw-r--r-- | src/autoplay/._child_process.cc | bin | 0 -> 4096 bytes | |||
| -rwxr-xr-x | src/autoplay/a.out | bin | 0 -> 33640 bytes | |||
| -rw-r--r-- | src/autoplay/child_process.cc | 188 | ||||
| -rw-r--r-- | src/autoplay/child_process.h | 53 | ||||
| -rw-r--r-- | src/autoplay/child_process_test.cc | 13 | ||||
| -rwxr-xr-x | src/autoplay/foo | bin | 0 -> 33672 bytes |
6 files changed, 254 insertions, 0 deletions
diff --git a/src/autoplay/._child_process.cc b/src/autoplay/._child_process.cc Binary files differnew file mode 100644 index 0000000..dc5fc97 --- /dev/null +++ b/src/autoplay/._child_process.cc diff --git a/src/autoplay/a.out b/src/autoplay/a.out Binary files differnew file mode 100755 index 0000000..d157d18 --- /dev/null +++ b/src/autoplay/a.out 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 <vector> +#include <cstdio> +#include <cstdlib> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> + +namespace util { + +void ChildProcess::ParseCommandline(vector<char *> *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<char *> 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 diff --git a/src/autoplay/child_process.h b/src/autoplay/child_process.h new file mode 100644 index 0000000..6c03ecd --- /dev/null +++ b/src/autoplay/child_process.h @@ -0,0 +1,53 @@ +// child_process.h -- description + +#ifndef _CHILD_PROCESS_H_ +#define _CHILD_PROCESS_H_ + +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <vector> +using namespace std; + +namespace util { + +class ChildProcess { + public: + explicit ChildProcess(const char *commandline) + : commandline_(strdup(commandline)), + name_(NULL), + running_(false), + pid_(-1), + to_(NULL), + from_(NULL), + child_ready_(false) {} + virtual ~ChildProcess() { + Stop(); + free(commandline_); + commandline_ = NULL; + } + + virtual void Start(); + virtual void Stop(); + void Send(char *line); + void Receive(char *line, int size); + bool Poll(); + void Flush(); + + private: + void ParseCommandline(vector<char *> *args); + char *commandline_; + char *name_; + bool running_; + pid_t pid_; + int write_pipe_[2]; + int read_pipe_[2]; + FILE *to_; + FILE *from_; + volatile bool child_ready_; +}; + +} // namespace + +#endif /* _CHILD_PROCESS_H_ */ diff --git a/src/autoplay/child_process_test.cc b/src/autoplay/child_process_test.cc new file mode 100644 index 0000000..d723701 --- /dev/null +++ b/src/autoplay/child_process_test.cc @@ -0,0 +1,13 @@ +#include "child_process.h" +#include "gtest/gtest.h" + +TEST(ChildProcessTest, BasicUsage) { + util::ChildProcess ps("/usr/bin/bc"); + ps.Start(); + ps.Flush(); + ps.Send("1 + 1\n"); + char buf[128]; + ps.Receive(buf, 128); + EXPECT_STREQ("2\n", buf); + ps.Stop(); +} diff --git a/src/autoplay/foo b/src/autoplay/foo Binary files differnew file mode 100755 index 0000000..3b87b38 --- /dev/null +++ b/src/autoplay/foo |
