Permalink
Browse files

Implement stdout/stderr separation

Breaks a bunch of other things
  • Loading branch information...
1 parent 01df2b6 commit d15c54de8cf631e5bf91cded9b25fe3efa147d5d @felixge felixge committed with piscisaureus Sep 9, 2011
Showing with 88 additions and 27 deletions.
  1. +7 −3 include/uv.h
  2. +46 −16 src/unix/process.c
  3. +2 −0 test/test-list.h
  4. +33 −8 test/test-spawn-sync.c
View
@@ -885,9 +885,13 @@ typedef struct uv_spawn_sync_t{
int combine;
- char *output;
- int output_size;
- int output_read;
+ char *stdout_buf;
+ int stdout_size;
+ int stdout_read;
+
+ char *stderr_buf;
+ int stderr_size;
+ int stderr_read;
int pid;
int exit_code;
View
@@ -313,7 +313,8 @@ void SyncCHLDHandler(int sig) {
}
int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
- int out_pipe[2];
+ int stdout_pipe[2];
+ int stderr_pipe[2];
int nfds;
int64_t start_time;
struct sigaction siga;
@@ -325,9 +326,14 @@ int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
spawn->pid = -1;
spawn->exit_code = -1;
spawn->exit_signal = -1;
- spawn->output_read = 0;
+ spawn->stdout_read = 0;
- if (pipe(out_pipe)) {
+ if (pipe(stdout_pipe)) {
+ perror("pipe");
+ return -1;
+ }
+
+ if (pipe(stderr_pipe)) {
perror("pipe");
return -1;
}
@@ -343,9 +349,12 @@ int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
return -1;
case 0: /* child */
- close(out_pipe[0]); /* close read end */
- dup2(out_pipe[1], STDOUT_FILENO);
- dup2(out_pipe[1], STDERR_FILENO);
+ /* close read ends */
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
+
+ dup2(stdout_pipe[1], STDOUT_FILENO);
+ dup2(stderr_pipe[1], STDERR_FILENO);
execvp(spawn->file, spawn->args);
perror("execvp()");
@@ -354,9 +363,11 @@ int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
}
/* parent */
- close(out_pipe[1]); /* close the write end of the pipe. */
+ /* close the write ends */
+ close(stdout_pipe[1]);
+ close(stderr_pipe[1]);
- nfds = MAX(out_pipe[0], spawn_sync_pipe[0]) + 1;
+ nfds = MAX(MAX(stdout_pipe[0], stderr_pipe[0]), spawn_sync_pipe[0]) + 1;
start_time = uv_now(loop); /* time in ms */
/* Set up sighandling */
@@ -375,7 +386,8 @@ int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
int r;
FD_ZERO(&pipes);
- FD_SET(out_pipe[0], &pipes);
+ FD_SET(stdout_pipe[0], &pipes);
+ FD_SET(stderr_pipe[0], &pipes);
FD_SET(spawn_sync_pipe[0], &pipes);
elapsed = uv_now(loop) - start_time;
@@ -399,25 +411,41 @@ int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
/* timeout */
close(spawn_sync_pipe[0]);
close(spawn_sync_pipe[1]);
- close(out_pipe[0]);
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
kill(spawn->pid, SIGKILL);
perror("timeout");
return -1;
}
- if (FD_ISSET(out_pipe[0], &pipes)) {
+ if (FD_ISSET(stdout_pipe[0], &pipes)) {
+ /* Check for buffer overflow. */
+ if (spawn->stdout_size - spawn->stdout_read <= 0) {
+ perror("buffer overflow");
+ goto error;
+ }
+ r = read(stdout_pipe[0], spawn->stdout_buf + spawn->stdout_read, spawn->stdout_size - spawn->stdout_read);
+ if (r == -1) {
+ perror("read");
+ goto error;
+ }
+
+ spawn->stdout_read += r;
+ }
+
+ if (FD_ISSET(stderr_pipe[0], &pipes)) {
/* Check for buffer overflow. */
- if (spawn->output_size - spawn->output_read <= 0) {
+ if (spawn->stderr_size - spawn->stderr_read <= 0) {
perror("buffer overflow");
goto error;
}
- r = read(out_pipe[0], spawn->output + spawn->output_read, spawn->output_size - spawn->output_read);
+ r = read(stderr_pipe[0], spawn->stderr_buf + spawn->stderr_read, spawn->stderr_size - spawn->stderr_read);
if (r == -1) {
perror("read");
goto error;
}
- spawn->output_read += r;
+ spawn->stderr_read += r;
}
if (FD_ISSET(spawn_sync_pipe[0], &pipes)) {
@@ -432,7 +460,8 @@ int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
close(spawn_sync_pipe[0]);
close(spawn_sync_pipe[1]);
- close(out_pipe[0]);
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
if (WIFEXITED(status)) {
spawn->exit_code = WEXITSTATUS(status);
@@ -451,7 +480,8 @@ int uv_spawn_sync(uv_loop_t* loop, uv_spawn_sync_t* spawn) {
error:
close(spawn_sync_pipe[0]);
close(spawn_sync_pipe[1]);
- close(out_pipe[0]);
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
kill(spawn->pid, SIGKILL);
return -1;
}
View
@@ -81,6 +81,7 @@ TEST_DECLARE (spawn_stdin)
TEST_DECLARE (spawn_and_kill)
TEST_DECLARE (spawn_sync_exit_code)
TEST_DECLARE (spawn_sync_exit_signal)
+TEST_DECLARE (spawn_sync_stdio)
TEST_DECLARE (spawn_sync_combine_stdio)
TEST_DECLARE (fs_file_noent)
TEST_DECLARE (fs_file_async)
@@ -206,6 +207,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_sync_exit_code)
TEST_ENTRY (spawn_sync_exit_signal)
+ TEST_ENTRY (spawn_sync_stdio)
TEST_ENTRY (spawn_sync_combine_stdio)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
@@ -23,6 +23,7 @@
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
static char exepath[1024];
static size_t exepath_size = 1024;
@@ -42,16 +43,19 @@ static void init_process_options(char* test) {
spawn.timeout = 1000;
spawn.file = exepath;
spawn.args = args;
- spawn.output_size = 1024;
- spawn.output = malloc(spawn.output_size);
+
+ spawn.stdout_size = 1024;
+ spawn.stdout_buf = malloc(spawn.stdout_size);
+ spawn.stderr_size = 1024;
+ spawn.stderr_buf = malloc(spawn.stdout_size);
}
void debug(int r) {
fprintf(stderr, "r: %i\n", r);
fprintf(stderr, "spawn.pid: %i\n", spawn.pid);
- fprintf(stderr, "spawn.output_read: %i\n", spawn.output_read);
- fprintf(stderr, "spawn.output_size: %i\n", spawn.output_size);
- fprintf(stderr, "spawn.output: %s\n", spawn.output);
+ fprintf(stderr, "spawn.stdout_read: %i\n", spawn.stdout_read);
+ fprintf(stderr, "spawn.stdout_size: %i\n", spawn.stdout_size);
+ fprintf(stderr, "spawn.stdout: %s\n", spawn.stdout_buf);
fprintf(stderr, "spawn.exit_code: %i\n", spawn.exit_code);
fprintf(stderr, "spawn.exit_signal: %i\n", spawn.exit_signal);
}
@@ -87,9 +91,30 @@ TEST_IMPL(spawn_sync_exit_signal) {
return 0;
}
+TEST_IMPL(spawn_sync_stdio) {
+ int r;
+ char *expected_stdout = "stdout\n";
+ char *expected_stderr = "stderr\n";
+ uv_init();
+
+ init_process_options("stdout_stderr");
+
+ r = uv_spawn_sync(uv_default_loop(), &spawn);
+
+ debug(r);
+
+ ASSERT(r == 0);
+ ASSERT(strcmp(spawn.stdout_buf, expected_stdout) == 0);
+ ASSERT(strcmp(spawn.stderr_buf, expected_stderr) == 0);
+ ASSERT(spawn.stdout_read == strlen(expected_stdout));
+ ASSERT(spawn.stderr_read == strlen(expected_stderr));
+
+ return 0;
+}
+
TEST_IMPL(spawn_sync_combine_stdio) {
int r;
- char *expected_output = "stdout\nstderr\n";
+ char *expected_stdout = "stdout\nstderr\n";
uv_init();
init_process_options("stdout_stderr");
@@ -101,8 +126,8 @@ TEST_IMPL(spawn_sync_combine_stdio) {
debug(r);
ASSERT(r == 0);
- ASSERT(strcmp(spawn.output, expected_output) == 0);
- ASSERT(spawn.output_read == strlen(expected_output));
+ ASSERT(strcmp(spawn.stdout_buf, expected_stdout) == 0);
+ ASSERT(spawn.stdout_read == strlen(expected_stdout));
return 0;
}

0 comments on commit d15c54d

Please sign in to comment.