diff options
author | Russ Allbery <eagle@eyrie.org> | 2014-01-21 22:23:50 -0800 |
---|---|---|
committer | Russ Allbery <rra@stanford.edu> | 2014-01-22 12:25:05 -0800 |
commit | 074e56057b8da3f3783c81f47324f12581463d1d (patch) | |
tree | 5430deaba02cf0e2c55f5eb0ac933e78ed339365 /server | |
parent | 7d2f2dbe8b3ccd28bbae15553cce56334c53444d (diff) |
Use an evbuffer to store input data for a process
Start isolating the process event loop from the rest of the code
by not reusing the struct iovec representation of the input data.
Instead, convert it to an evbuffer first.
This does make another copy of the data. We will rethink this if
it shows up as a performance issue.
Change-Id: Ie37dea0e9b4a58fa4f481ed0a4fd5ba8bb7ebdab
Reviewed-on: https://gerrit.stanford.edu/1389
Reviewed-by: Russ Allbery <rra@stanford.edu>
Tested-by: Russ Allbery <rra@stanford.edu>
Diffstat (limited to 'server')
-rw-r--r-- | server/commands.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/server/commands.c b/server/commands.c index 84348d2..0143b24 100644 --- a/server/commands.c +++ b/server/commands.c @@ -35,17 +35,23 @@ * themselves when needed. */ struct process { - struct event_base *loop; /* Event base for the process event loop. */ - struct bufferevent *inout; /* Input and output from process. */ - struct bufferevent *err; /* Standard error from process. */ - struct event *sigchld; /* Handle the SIGCHLD signal for exit. */ - struct evbuffer *output; /* Buffer of output from process. */ struct client *client; /* Pointer to corresponding remctl client. */ + + /* Process data. */ socket_type stdinout_fd; /* File descriptor for input and output. */ socket_type stderr_fd; /* File descriptor for standard error. */ - struct iovec *input; /* Data to pass on standard input. */ pid_t pid; /* Process ID of child. */ int status; /* Exit status. */ + + /* Event loop. */ + struct event_base *loop; /* Event base for the process event loop. */ + struct bufferevent *inout; /* Input and output from process. */ + struct bufferevent *err; /* Standard error from process. */ + struct event *sigchld; /* Handle the SIGCHLD signal for exit. */ + struct evbuffer *input; /* Buffer of input to process. */ + struct evbuffer *output; /* Buffer of output from process. */ + + /* State flags. */ bool reaped; /* Whether we've reaped the process. */ bool saw_output; /* Whether we saw process output. */ }; @@ -235,8 +241,7 @@ server_process_output(struct client *client, struct process *process) else { writecb = handle_input_end; bufferevent_enable(process->inout, EV_READ | EV_WRITE); - if (bufferevent_write(process->inout, process->input->iov_base, - process->input->iov_len) < 0) + if (bufferevent_write_buffer(process->inout, process->input) < 0) sysdie("cannot queue input for process"); } if (client->protocol == 1) { @@ -692,14 +697,21 @@ create_argv_command(struct confline *cline, struct process *process, else stdin_arg = (size_t) cline->stdin_arg; for (i = 1, j = 1; i < count; i++) { + const char *data = argv[i]->iov_base; + size_t length = argv[i]->iov_len; + if (i == stdin_arg) { - process->input = argv[i]; + process->input = evbuffer_new(); + if (process->input == NULL) + die("internal error: cannot create input buffer"); + if (evbuffer_add(process->input, data, length) < 0) + die("internal error: cannot add data to input buffer"); continue; } - if (argv[i]->iov_len == 0) + if (length == 0) req_argv[j] = xstrdup(""); else - req_argv[j] = xstrndup(argv[i]->iov_base, argv[i]->iov_len); + req_argv[j] = xstrndup(data, length); j++; } req_argv[j] = NULL; |