Blame test/test-stdio-over-pipes.c

Packit Service 7c31a4
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit Service 7c31a4
 * of this software and associated documentation files (the "Software"), to
Packit Service 7c31a4
 * deal in the Software without restriction, including without limitation the
Packit Service 7c31a4
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit Service 7c31a4
 * sell copies of the Software, and to permit persons to whom the Software is
Packit Service 7c31a4
 * furnished to do so, subject to the following conditions:
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * The above copyright notice and this permission notice shall be included in
Packit Service 7c31a4
 * all copies or substantial portions of the Software.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service 7c31a4
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service 7c31a4
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit Service 7c31a4
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit Service 7c31a4
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit Service 7c31a4
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit Service 7c31a4
 * IN THE SOFTWARE.
Packit Service 7c31a4
 */
Packit Service 7c31a4
Packit Service 7c31a4
#include "uv.h"
Packit Service 7c31a4
#include "task.h"
Packit Service 7c31a4
Packit Service 7c31a4
#include <stdlib.h>
Packit Service 7c31a4
#include <string.h>
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static char exepath[1024];
Packit Service 7c31a4
static size_t exepath_size = 1024;
Packit Service 7c31a4
static char* args[3];
Packit Service 7c31a4
static uv_process_options_t options;
Packit Service 7c31a4
static int close_cb_called;
Packit Service 7c31a4
static int exit_cb_called;
Packit Service 7c31a4
static int on_read_cb_called;
Packit Service 7c31a4
static int after_write_cb_called;
Packit Service 7c31a4
static uv_pipe_t in;
Packit Service 7c31a4
static uv_pipe_t out;
Packit Service 7c31a4
static uv_loop_t* loop;
Packit Service 7c31a4
#define OUTPUT_SIZE 1024
Packit Service 7c31a4
static char output[OUTPUT_SIZE];
Packit Service 7c31a4
static int output_used;
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void close_cb(uv_handle_t* handle) {
Packit Service 7c31a4
  close_cb_called++;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void exit_cb(uv_process_t* process,
Packit Service 7c31a4
                    int64_t exit_status,
Packit Service 7c31a4
                    int term_signal) {
Packit Service 7c31a4
  printf("exit_cb\n");
Packit Service 7c31a4
  exit_cb_called++;
Packit Service 7c31a4
  ASSERT(exit_status == 0);
Packit Service 7c31a4
  ASSERT(term_signal == 0);
Packit Service 7c31a4
  uv_close((uv_handle_t*)process, close_cb);
Packit Service 7c31a4
  uv_close((uv_handle_t*)&in, close_cb);
Packit Service 7c31a4
  uv_close((uv_handle_t*)&out, close_cb);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void init_process_options(char* test, uv_exit_cb exit_cb) {
Packit Service 7c31a4
  int r = uv_exepath(exepath, &exepath_size);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
  exepath[exepath_size] = '\0';
Packit Service 7c31a4
  args[0] = exepath;
Packit Service 7c31a4
  args[1] = test;
Packit Service 7c31a4
  args[2] = NULL;
Packit Service 7c31a4
  options.file = exepath;
Packit Service 7c31a4
  options.args = args;
Packit Service 7c31a4
  options.exit_cb = exit_cb;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void on_alloc(uv_handle_t* handle,
Packit Service 7c31a4
                     size_t suggested_size,
Packit Service 7c31a4
                     uv_buf_t* buf) {
Packit Service 7c31a4
  buf->base = output + output_used;
Packit Service 7c31a4
  buf->len = OUTPUT_SIZE - output_used;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void after_write(uv_write_t* req, int status) {
Packit Service 7c31a4
  if (status) {
Packit Service 7c31a4
    fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
Packit Service 7c31a4
    ASSERT(0);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  /* Free the read/write buffer and the request */
Packit Service 7c31a4
  free(req);
Packit Service 7c31a4
Packit Service 7c31a4
  after_write_cb_called++;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* rdbuf) {
Packit Service 7c31a4
  uv_write_t* req;
Packit Service 7c31a4
  uv_buf_t wrbuf;
Packit Service 7c31a4
  int r;
Packit Service 7c31a4
Packit Service 7c31a4
  ASSERT(nread > 0 || nread == UV_EOF);
Packit Service 7c31a4
Packit Service 7c31a4
  if (nread > 0) {
Packit Service 7c31a4
    output_used += nread;
Packit Service 7c31a4
    if (output_used % 12 == 0) {
Packit Service 7c31a4
      ASSERT(memcmp("hello world\n", output, 12) == 0);
Packit Service 7c31a4
      wrbuf = uv_buf_init(output, 12);
Packit Service 7c31a4
      req = malloc(sizeof(*req));
Packit Service 7c31a4
      r = uv_write(req, (uv_stream_t*) &in, &wrbuf, 1, after_write);
Packit Service 7c31a4
      ASSERT(r == 0);
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  on_read_cb_called++;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void test_stdio_over_pipes(int overlapped) {
Packit Service 7c31a4
  int r;
Packit Service 7c31a4
  uv_process_t process;
Packit Service 7c31a4
  uv_stdio_container_t stdio[3];
Packit Service 7c31a4
Packit Service 7c31a4
  loop = uv_default_loop();
Packit Service 7c31a4
Packit Service 7c31a4
  init_process_options("stdio_over_pipes_helper", exit_cb);
Packit Service 7c31a4
Packit Service 7c31a4
  uv_pipe_init(loop, &out, 0);
Packit Service 7c31a4
  uv_pipe_init(loop, &in, 0);
Packit Service 7c31a4
Packit Service 7c31a4
  options.stdio = stdio;
Packit Service 7c31a4
  options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE |
Packit Service 7c31a4
      (overlapped ?  UV_OVERLAPPED_PIPE : 0);
Packit Service 7c31a4
  options.stdio[0].data.stream = (uv_stream_t*) ∈
Packit Service 7c31a4
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE |
Packit Service 7c31a4
      (overlapped ? UV_OVERLAPPED_PIPE : 0);
Packit Service 7c31a4
  options.stdio[1].data.stream = (uv_stream_t*) &out;
Packit Service 7c31a4
  options.stdio[2].flags = UV_INHERIT_FD;
Packit Service 7c31a4
  options.stdio[2].data.fd = 2;
Packit Service 7c31a4
  options.stdio_count = 3;
Packit Service 7c31a4
Packit Service 7c31a4
  r = uv_spawn(loop, &process, &options);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
Packit Service 7c31a4
  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
Packit Service 7c31a4
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
Packit Service 7c31a4
  ASSERT(on_read_cb_called > 1);
Packit Service 7c31a4
  ASSERT(after_write_cb_called == 2);
Packit Service 7c31a4
  ASSERT(exit_cb_called == 1);
Packit Service 7c31a4
  ASSERT(close_cb_called == 3);
Packit Service 7c31a4
  ASSERT(memcmp("hello world\nhello world\n", output, 24) == 0);
Packit Service 7c31a4
  ASSERT(output_used == 24);
Packit Service 7c31a4
Packit Service 7c31a4
  MAKE_VALGRIND_HAPPY();
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
TEST_IMPL(stdio_over_pipes) {
Packit Service 7c31a4
  test_stdio_over_pipes(0);
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
TEST_IMPL(stdio_emulate_iocp) {
Packit Service 7c31a4
  test_stdio_over_pipes(1);
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
/* Everything here runs in a child process. */
Packit Service 7c31a4
Packit Service 7c31a4
static int on_pipe_read_called;
Packit Service 7c31a4
static int after_write_called;
Packit Service 7c31a4
static uv_pipe_t stdin_pipe1;
Packit Service 7c31a4
static uv_pipe_t stdout_pipe1;
Packit Service 7c31a4
static uv_pipe_t stdin_pipe2;
Packit Service 7c31a4
static uv_pipe_t stdout_pipe2;
Packit Service 7c31a4
Packit Service 7c31a4
static void on_pipe_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) {
Packit Service 7c31a4
  ASSERT(nread > 0);
Packit Service 7c31a4
  ASSERT(memcmp("hello world\n", buf->base, nread) == 0);
Packit Service 7c31a4
  on_pipe_read_called++;
Packit Service 7c31a4
Packit Service 7c31a4
  free(buf->base);
Packit Service 7c31a4
Packit Service 7c31a4
  uv_read_stop(pipe);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void after_pipe_write(uv_write_t* req, int status) {
Packit Service 7c31a4
  ASSERT(status == 0);
Packit Service 7c31a4
  after_write_called++;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static void on_read_alloc(uv_handle_t* handle,
Packit Service 7c31a4
                          size_t suggested_size,
Packit Service 7c31a4
                          uv_buf_t* buf) {
Packit Service 7c31a4
  buf->base = malloc(suggested_size);
Packit Service 7c31a4
  buf->len = suggested_size;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int stdio_over_pipes_helper(void) {
Packit Service 7c31a4
  /* Write several buffers to test that the write order is preserved. */
Packit Service 7c31a4
  char* buffers[] = {
Packit Service 7c31a4
    "he",
Packit Service 7c31a4
    "ll",
Packit Service 7c31a4
    "o ",
Packit Service 7c31a4
    "wo",
Packit Service 7c31a4
    "rl",
Packit Service 7c31a4
    "d",
Packit Service 7c31a4
    "\n"
Packit Service 7c31a4
  };
Packit Service 7c31a4
Packit Service 7c31a4
  uv_write_t write_req[ARRAY_SIZE(buffers)];
Packit Service 7c31a4
  uv_buf_t buf[ARRAY_SIZE(buffers)];
Packit Service 7c31a4
  unsigned int i;
Packit Service 7c31a4
  int j;
Packit Service 7c31a4
  int r;
Packit Service 7c31a4
  uv_loop_t* loop = uv_default_loop();
Packit Service 7c31a4
Packit Service 7c31a4
  ASSERT(UV_NAMED_PIPE == uv_guess_handle(0));
Packit Service 7c31a4
  ASSERT(UV_NAMED_PIPE == uv_guess_handle(1));
Packit Service 7c31a4
Packit Service 7c31a4
  r = uv_pipe_init(loop, &stdin_pipe1, 0);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
  r = uv_pipe_init(loop, &stdout_pipe1, 0);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
  r = uv_pipe_init(loop, &stdin_pipe2, 0);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
  r = uv_pipe_init(loop, &stdout_pipe2, 0);
Packit Service 7c31a4
  ASSERT(r == 0);
Packit Service 7c31a4
Packit Service 7c31a4
  uv_pipe_open(&stdin_pipe1, 0);
Packit Service 7c31a4
  uv_pipe_open(&stdout_pipe1, 1);
Packit Service 7c31a4
  uv_pipe_open(&stdin_pipe2, 0);
Packit Service 7c31a4
  uv_pipe_open(&stdout_pipe2, 1);
Packit Service 7c31a4
Packit Service 7c31a4
  for (j = 0; j < 2; j++) {
Packit Service 7c31a4
    /* Unref both stdio handles to make sure that all writes complete. */
Packit Service 7c31a4
    uv_unref((uv_handle_t*) &stdin_pipe1);
Packit Service 7c31a4
    uv_unref((uv_handle_t*) &stdout_pipe1);
Packit Service 7c31a4
    uv_unref((uv_handle_t*) &stdin_pipe2);
Packit Service 7c31a4
    uv_unref((uv_handle_t*) &stdout_pipe2);
Packit Service 7c31a4
Packit Service 7c31a4
    for (i = 0; i < ARRAY_SIZE(buffers); i++) {
Packit Service 7c31a4
      buf[i] = uv_buf_init((char*) buffers[i], strlen(buffers[i]));
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    for (i = 0; i < ARRAY_SIZE(buffers); i++) {
Packit Service 7c31a4
      r = uv_write(&write_req[i],
Packit Service 7c31a4
                   (uv_stream_t*) (j == 0 ? &stdout_pipe1 : &stdout_pipe2),
Packit Service 7c31a4
                   &buf[i],
Packit Service 7c31a4
                   1,
Packit Service 7c31a4
                   after_pipe_write);
Packit Service 7c31a4
      ASSERT(r == 0);
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    notify_parent_process();
Packit Service 7c31a4
    uv_run(loop, UV_RUN_DEFAULT);
Packit Service 7c31a4
Packit Service 7c31a4
    ASSERT(after_write_called == 7 * (j + 1));
Packit Service 7c31a4
    ASSERT(on_pipe_read_called == j);
Packit Service 7c31a4
    ASSERT(close_cb_called == 0);
Packit Service 7c31a4
Packit Service 7c31a4
    uv_ref((uv_handle_t*) &stdout_pipe1);
Packit Service 7c31a4
    uv_ref((uv_handle_t*) &stdin_pipe1);
Packit Service 7c31a4
    uv_ref((uv_handle_t*) &stdout_pipe2);
Packit Service 7c31a4
    uv_ref((uv_handle_t*) &stdin_pipe2);
Packit Service 7c31a4
Packit Service 7c31a4
    r = uv_read_start((uv_stream_t*) (j == 0 ? &stdin_pipe1 : &stdin_pipe2),
Packit Service 7c31a4
                      on_read_alloc,
Packit Service 7c31a4
                      on_pipe_read);
Packit Service 7c31a4
    ASSERT(r == 0);
Packit Service 7c31a4
Packit Service 7c31a4
    uv_run(loop, UV_RUN_DEFAULT);
Packit Service 7c31a4
Packit Service 7c31a4
    ASSERT(after_write_called == 7 * (j + 1));
Packit Service 7c31a4
    ASSERT(on_pipe_read_called == j + 1);
Packit Service 7c31a4
    ASSERT(close_cb_called == 0);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv_close((uv_handle_t*)&stdin_pipe1, close_cb);
Packit Service 7c31a4
  uv_close((uv_handle_t*)&stdout_pipe1, close_cb);
Packit Service 7c31a4
  uv_close((uv_handle_t*)&stdin_pipe2, close_cb);
Packit Service 7c31a4
  uv_close((uv_handle_t*)&stdout_pipe2, close_cb);
Packit Service 7c31a4
Packit Service 7c31a4
  uv_run(loop, UV_RUN_DEFAULT);
Packit Service 7c31a4
Packit Service 7c31a4
  ASSERT(after_write_called == 14);
Packit Service 7c31a4
  ASSERT(on_pipe_read_called == 2);
Packit Service 7c31a4
  ASSERT(close_cb_called == 4);
Packit Service 7c31a4
Packit Service 7c31a4
  MAKE_VALGRIND_HAPPY();
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}