예제 #1
0
파일: jl_uv.c 프로젝트: seanita/julia
DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop,
                       uv_process_t *proc, jl_value_t *julia_struct,
                       uv_handle_type stdin_type, uv_pipe_t *stdin_pipe,
                       uv_handle_type stdout_type, uv_pipe_t *stdout_pipe,
                       uv_handle_type stderr_type, uv_pipe_t *stderr_pipe, 
                       int detach, char **env)
{
    uv_process_options_t opts;
    uv_stdio_container_t stdio[3];
    int error;
    opts.file = name;
    opts.env = env;
#ifdef _OS_WINDOWS_
    opts.flags = 0;
#else
    opts.flags = UV_PROCESS_RESET_SIGPIPE;
#endif
    opts.cwd = NULL;
    opts.args = argv;
    if (detach)
        opts.flags |= UV_PROCESS_DETACHED;
    opts.stdio = stdio;
    opts.stdio_count = 3;
    stdio[0].type = stdin_type;
    stdio[0].data.stream = (uv_stream_t*)(stdin_pipe);
    stdio[1].type = stdout_type;
    stdio[1].data.stream = (uv_stream_t*)(stdout_pipe);
    stdio[2].type = stderr_type;
    stdio[2].data.stream = (uv_stream_t*)(stderr_pipe);
    opts.exit_cb = &jl_uv_return_spawn;
    error = uv_spawn(loop,proc,opts);
    return error;
}
예제 #2
0
static void spawn(void) {
  uv_stdio_container_t stdio[2];
  int r;

  ASSERT(process_open == 0);
  ASSERT(pipe_open == 0);

  args[0] = exepath;
  args[1] = "spawn_helper";
  args[2] = NULL;
  options.file = exepath;
  options.args = args;
  options.exit_cb = exit_cb;

  uv_pipe_init(loop, &out, 0);

  options.stdio = stdio;
  options.stdio_count = 2;
  options.stdio[0].flags = UV_IGNORE;
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
  options.stdio[1].data.stream = (uv_stream_t*)&out;

  r = uv_spawn(loop, &process, options);
  ASSERT(r == 0);

  process_open = 1;
  pipe_open = 1;
  output_used = 0;

  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
  ASSERT(r == 0);
}
예제 #3
0
파일: jl_uv.c 프로젝트: pao/julia
DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop,
                       uv_process_t *proc, jl_value_t *julia_struct,
                       uv_handle_type stdin_type,uv_pipe_t *stdin_pipe,
                       uv_handle_type stdout_type,uv_pipe_t *stdout_pipe,
                       uv_handle_type stderr_type,uv_pipe_t *stderr_pipe)
{
#ifdef __APPLE__
    char **environ = *_NSGetEnviron();
#endif
    uv_process_options_t opts;
    uv_stdio_container_t stdio[3];
    int error;
    opts.file = name;
#ifndef __WIN32__
    opts.env = environ;
#else
    opts.env = NULL;
#endif
    opts.cwd = NULL;
    opts.args = argv;
    opts.flags = 0;
    opts.stdio = stdio;
    opts.stdio_count = 3;
    stdio[0].type = stdin_type;
    stdio[0].data.stream = (uv_stream_t*)(stdin_pipe);
    stdio[1].type = stdout_type;
    stdio[1].data.stream = (uv_stream_t*)(stdout_pipe);
    stdio[2].type = stderr_type;
    stdio[2].data.stream = (uv_stream_t*)(stderr_pipe);
    //opts.detached = 0; #This has been removed upstream to be uncommented once it is possible again
    opts.exit_cb = &jl_return_spawn;
    error = uv_spawn(loop,proc,opts);
    proc->data = julia_struct;
    return error;
}
예제 #4
0
파일: process.c 프로젝트: ifzz/LuaIO
static int LuaIO_process_exec(lua_State* L) {
  const char* cmd;
  if (lua_type(L, 1) == LUA_TSTRING) {
    cmd = lua_tostring(L, 1);
  } else {
    return luaL_argerror(L, 2, "process.exec(cmd) error: cmd is required and must be [string]\n"); 
  }

  /*shell, -c, cmd, null*/
  char** args = LuaIO_malloc(sizeof(char*) * 4);
  args[0] = "/bin/sh";
  args[1] = "-c";
  args[2] = (char*)cmd;
  args[3] = NULL;

  if (!LuaIO_process_stdio_ptr) { 
    LuaIO_process_stdio[0].flags = UV_INHERIT_FD;
    LuaIO_process_stdio[0].data.fd = 0;
    LuaIO_process_stdio[1].flags = UV_INHERIT_FD;
    LuaIO_process_stdio[1].data.fd = 1;
    LuaIO_process_stdio[2].flags = UV_INHERIT_FD;
    LuaIO_process_stdio[2].data.fd = 2;
    LuaIO_process_stdio_ptr = LuaIO_process_stdio;
  }

  uv_process_options_t* options = LuaIO_malloc(sizeof(uv_process_options_t));
  if (!options) {
    LuaIO_free(args);
    return luaL_error(L, "process.exec(cmd) error: no memory for uv_process_options_t options\n");
  }
  LuaIO_memzero(options, sizeof(uv_process_options_t));
  options->exit_cb = LuaIO_process_onexit;
  options->file = "/bin/sh";
  options->args = args;
  options->stdio_count = 3;
  options->stdio = LuaIO_process_stdio_ptr;

  uv_process_t* handle = LuaIO_malloc(sizeof(uv_process_t));
  if (!handle) {
    LuaIO_process_free_options(options);
    return luaL_error(L, "process.exec(cmd) error: no memory for uv_process_t handle\n");
  }
  LuaIO_memzero(handle, sizeof(uv_process_t));

  int ret = uv_spawn(uv_default_loop(), handle, options);
  if (ret < 0) {
    LuaIO_process_free_options(options);
    uv_close((uv_handle_t*)handle, NULL);
    return luaL_error(L, "process.exec(cmd) uv_spawn() error: %s\n", uv_strerror(ret));
  }

  if (!LuaIO_process_signal_ptr) {
    uv_signal_init(uv_default_loop(), &LuaIO_process_signal);
    LuaIO_process_signal_ptr = &LuaIO_process_signal;
    uv_signal_start(LuaIO_process_signal_ptr, LuaIO_process_signal_callback, SIGQUIT);
  }

  lua_pushinteger(L, handle->pid);
  return 1;
}
예제 #5
0
파일: jl_uv.c 프로젝트: 0/julia
JL_DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop,
                          uv_process_t *proc, jl_value_t *julia_struct,
                          uv_handle_type stdin_type, uv_pipe_t *stdin_pipe,
                          uv_handle_type stdout_type, uv_pipe_t *stdout_pipe,
                          uv_handle_type stderr_type, uv_pipe_t *stderr_pipe,
                          int flags, char **env, char *cwd, uv_exit_cb cb)
{
    uv_process_options_t opts;
    uv_stdio_container_t stdio[3];
    int error;
    opts.file = name;
    opts.env = env;
#ifdef _OS_WINDOWS_
    opts.flags = flags;
#else
    opts.flags = flags | UV_PROCESS_RESET_SIGPIPE;
#endif
    opts.cwd = cwd;
    opts.args = argv;
    opts.stdio = stdio;
    opts.stdio_count = 3;
    stdio[0].type = stdin_type;
    stdio[0].data.stream = (uv_stream_t*)(stdin_pipe);
    stdio[1].type = stdout_type;
    stdio[1].data.stream = (uv_stream_t*)(stdout_pipe);
    stdio[2].type = stderr_type;
    stdio[2].data.stream = (uv_stream_t*)(stderr_pipe);
    opts.exit_cb = cb;
    error = uv_spawn(loop,proc,&opts);
    return error;
}
예제 #6
0
static void spawn() {
  int r;

  ASSERT(process_open == 0);
  ASSERT(pipe_open == 0);

  args[0] = exepath;
  args[1] = "spawn_helper";
  args[2] = NULL;
  options.file = exepath;
  options.args = args;
  options.exit_cb = exit_cb;

  uv_pipe_init(&out);
  options.stdout_stream = &out;

  r = uv_spawn(&process, options);
  ASSERT(r == 0);

  process_open = 1;
  pipe_open = 1;
  output_used = 0;

  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
  ASSERT(r == 0);
}
예제 #7
0
int main(int argc, char** argv)
{
	char* priv = NULL;
	char** arguments = NULL;
	uv_process_t* child_req = NULL;
	uv_process_options_t* options = NULL;

	priv = calloc(1, sizeof(uv_process_t) + sizeof(uv_process_options_t) + 2 * sizeof(char*));
	if (priv == NULL) {
		fprintf(stderr, "Failed to allocate the memory block\n");
		return -1;
	}

	child_req = (void*)priv;
	options   = (void*)(priv + sizeof(uv_process_t));
	arguments = (void*)(priv + sizeof(uv_process_t) + sizeof(uv_process_options_t));

	arguments[0] = "./subproc";
	arguments[1] = NULL;

	options->exit_cb = _on_subproc_exit;
	options->file = "./subproc";
	options->args = arguments;

	if (uv_spawn(uv_default_loop(), child_req, *options)) {
		fprintf(stderr, "Failed to start the process");
		return -1;
	}

	uv_run(uv_default_loop());

	return 0;
}
예제 #8
0
파일: forza.c 프로젝트: revington/forza
void spawn() {
  int i;
  char** env = NULL;

  env = env_copy(environ, env);

  child = malloc(sizeof(uv_process_t));
  uv_stdio_container_t stdio[4];
  uv_process_options_t options;

  uv_pipe_init(loop, &child_stdout, 0);
  uv_pipe_init(loop, &child_stderr, 0);
  uv_pipe_init(loop, &child_ipc, 0);

  //
  // Setup child's stdio. stdout and stderr are pipes so that we can read
  // child process' output.
  // FD 3 is a pipe used for IPC.
  //
  options.stdio_count = 4;
  stdio[0].flags = UV_INHERIT_FD;
  stdio[0].data.fd = 0;
  stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
  stdio[1].data.stream = (uv_stream_t*) &child_stdout;
  stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
  stdio[2].data.stream = (uv_stream_t*) &child_stderr;
  stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
  stdio[3].data.stream = (uv_stream_t*) &child_ipc;

  options.env = env;
  options.cwd = NULL;
  options.file = arguments[0];
  options.args = arguments;
  options.flags = 0;
  options.stdio = stdio;
  options.exit_cb = on_process_exit;

  for (i = 0; i < PLUGIN_COUNT; i++) {
    if (plugins[i].process_options_cb) {
      plugins[i].process_options_cb(&options);
    }
  }

  if (uv_spawn(loop, child, options)) {
    fprintf(stderr, "uv_spawn: %s\n", uv_err_name(uv_last_error(loop)));
    return;
  }

  for (i = 0; i < PLUGIN_COUNT; i++) {
    if (plugins[i].process_spawned_cb) {
      plugins[i].process_spawned_cb(child, &options);
    }
  }

  uv_read_start(options.stdio[1].data.stream, forza__on_alloc, forza__on_stdout_read);
  uv_read_start(options.stdio[2].data.stream, forza__on_alloc, forza__on_stderr_read);
  uv_read_start(options.stdio[3].data.stream, forza__on_alloc, forza__on_ipc_read);
}
예제 #9
0
파일: process.cpp 프로젝트: API92/pruv
bool process::start(uv_loop_t *loop, const char *file, const char * const *args,
        void *owner, uv_exit_cb on_exit, void (*deleter)(void *)) noexcept
{
    assert(loop);
    this->owner = owner;
    this->deleter = deleter;

    int r;
    ++wait_close;
    close_on_return close_in((uv_handle_t *)&in, close_cb);
    if ((r = uv_pipe_init(loop, &in, 0)) < 0) {
        pruv_log_uv_err(LOG_ERR, "uv_pipe_init in", r);
        return false;
    }

    ++wait_close;
    close_on_return close_out((uv_handle_t *)&out, close_cb);
    if ((r = uv_pipe_init(loop, &out, 0)) < 0) {
        pruv_log_uv_err(LOG_ERR, "uv_pipe_init out", r);
        return false;
    }

    uv_process_options_t options;
    memset(&options, 0, sizeof(options));
    options.exit_cb = on_exit;
    options.file = file;
    // http://pubs.opengroup.org/onlinepubs/009604499/functions/exec.html
    // RATIONALE section describes, why args can't be const.
    // It is only due to limitation of the ISO C.
    // In fact args is completely constant.
    options.args = const_cast<char **>(args);
    options.flags = UV_PROCESS_WINDOWS_HIDE;
    options.stdio_count = 2;
    uv_stdio_container_t stdio[2];
    options.stdio = stdio;
    options.stdio[0].flags = uv_stdio_flags(UV_CREATE_PIPE | UV_READABLE_PIPE);
    options.stdio[0].data.stream = (uv_stream_t *)&in;
    options.stdio[1].flags = uv_stdio_flags(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
    options.stdio[1].data.stream = (uv_stream_t *)&out;

    ++wait_close;
    close_on_return close_this_proc((uv_handle_t *)this, close_cb);
    if ((r = uv_spawn(loop, (uv_process_t *)this, &options)) < 0) {
        pruv_log_uv_err(LOG_ERR, "uv_spawn", r);
        return false;
    }

    close_in.h = close_out.h = close_this_proc.h = nullptr;
    return true;
}
예제 #10
0
파일: process.c 프로젝트: ifzz/LuaIO
static void LuaIO_process_onexit(uv_process_t* handle, int64_t status, int signal) {
  if (handle->data) {
    LuaIO_process_data_t* data = handle->data;
    fprintf(stderr,
            "process[%d] exit. status: %" PRId64 ", signal: %d, file: %s\n",
            handle->pid,
            status,
            signal,
            data->options->args[1]);

    data->options->file = LuaIO_process_exepath_ptr;
    data->options->args[0] = LuaIO_process_exepath_ptr;

    uv_process_t* process = (uv_process_t*) LuaIO_malloc(sizeof(uv_process_t));
    if (!process) {
      LuaIO_process_free_options(data->options);
      luaL_unref(LuaIO_get_main_thread(), LUA_REGISTRYINDEX, data->options_ref);
      LuaIO_free(data);
      fprintf(stderr,
              "process[%s] restart failed. no more memory for process\n", 
              data->options->args[1]);
    }
    LuaIO_memzero(process, sizeof(uv_process_t));
    process->data = data;

    int ret = uv_spawn(uv_default_loop(), process, data->options);
    if (ret < 0) {
      LuaIO_process_free_options(data->options);
      luaL_unref(LuaIO_get_main_thread(), LUA_REGISTRYINDEX, data->options_ref);
      LuaIO_free(data);
      uv_close((uv_handle_t*)process, NULL);
      fprintf(stderr,
              "process[%s] restart failed. uv_spawn() error: %s\n",
              data->options->args[1],
              uv_strerror(ret));
    }

    if (data->cpu >= 0) LuaIO_set_affinity(process->pid, data->cpu);

    return;
  }
    
  fprintf(stderr, 
          "process[%d] exit. status: %" PRId64 ", signal: %d\n",
          handle->pid,
          status,
          signal);
  
  uv_close((uv_handle_t*)handle, NULL);
}
예제 #11
0
파일: main.c 프로젝트: sunnyboy00/uvbook
void setup_workers() {
    size_t path_size = 500;
    uv_exepath(worker_path, &path_size);
    strcpy(worker_path + (strlen(worker_path) - strlen("multi-echo-server")), "worker");
    fprintf(stderr, "Worker path: %s\n", worker_path);

    char* args[2];
    args[0] = worker_path;
    args[1] = NULL;

    round_robin_counter = 0;

    // ...

    // launch same number of workers as number of CPUs
    uv_cpu_info_t *info;
    int cpu_count;
    uv_cpu_info(&info, &cpu_count);
    uv_free_cpu_info(info, cpu_count);

    child_worker_count = cpu_count;

    workers = calloc(sizeof(struct child_worker), cpu_count);
    while (cpu_count--) {
        struct child_worker *worker = &workers[cpu_count];
        uv_pipe_init(loop, &worker->pipe, 1);

        uv_stdio_container_t child_stdio[3];
        child_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
        child_stdio[0].data.stream = (uv_stream_t*) &worker->pipe;
        child_stdio[1].flags = UV_IGNORE;
        child_stdio[2].flags = UV_INHERIT_FD;
        child_stdio[2].data.fd = 2;

        worker->options.stdio = child_stdio;
        worker->options.stdio_count = 3;

        worker->options.exit_cb = close_process_handle;
        worker->options.file = args[0];
        worker->options.args = args;

        uv_spawn(loop, &worker->req, worker->options); 
        fprintf(stderr, "Started worker %d\n", worker->req.pid);
    }
}
예제 #12
0
int main() {
    loop = uv_default_loop();

    char* args[3];
    args[0] = "mkdir";
    args[1] = "test-dir";
    args[2] = NULL;

    options.exit_cb = on_exit;
    options.file = "mkdir";
    options.args = args;

    if (uv_spawn(loop, &child_req, options)) {
        fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop)));
        return 1;
    }

    return uv_run(loop, UV_RUN_DEFAULT);
}
예제 #13
0
void spawn_helper(uv_pipe_t* channel,
                  uv_process_t* process,
                  const char* helper) {
  uv_process_options_t options;
  size_t exepath_size;
  char exepath[1024];
  char* args[3];
  int r;
  uv_stdio_container_t stdio[3];

  r = uv_pipe_init(uv_default_loop(), channel, 1);
  ASSERT(r == 0);
  ASSERT(channel->ipc);

  exepath_size = sizeof(exepath);
  r = uv_exepath(exepath, &exepath_size);
  ASSERT(r == 0);

  exepath[exepath_size] = '\0';
  args[0] = exepath;
  args[1] = (char*)helper;
  args[2] = NULL;

  memset(&options, 0, sizeof(options));
  options.file = exepath;
  options.args = args;
  options.exit_cb = exit_cb;
  options.stdio = stdio;
  options.stdio_count = ARRAY_SIZE(stdio);

  stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE;
  stdio[0].data.stream = (uv_stream_t*) channel;
  stdio[1].flags = UV_INHERIT_FD;
  stdio[1].data.fd = 1;
  stdio[2].flags = UV_INHERIT_FD;
  stdio[2].data.fd = 2;

  r = uv_spawn(uv_default_loop(), process, &options);
  ASSERT(r == 0);
}
예제 #14
0
파일: main.c 프로젝트: cloud-hot/libuv-dox
void setup_workers() {
  int r;
  exepath_for_worker();

  char* args[2];
  args[0] = exepath;
  args[1] = NULL;

  round_robin_counter = 0;
  int cpu_count = get_cpu_count();
  child_worker_count = cpu_count;

  workers = calloc(sizeof(struct child_worker), cpu_count);
  while (cpu_count--) {
    struct child_worker *worker = &workers[cpu_count];
    // pipe is acting as IPC channel
    uv_pipe_init(loop, &worker->pipe, IPC);

    // https://github.com/thlorenz/libuv-dox/blob/master/types.md#uv_stdio_container_t
    // https://github.com/thlorenz/libuv-dox/blob/master/types.md#uv_stdio_flags
    uv_stdio_container_t child_stdio[3];
    child_stdio[STDIN].flags       =  UV_CREATE_PIPE | UV_READABLE_PIPE;
    child_stdio[STDIN].data.stream =  (uv_stream_t*) &worker->pipe;
    child_stdio[STDOUT].flags      =  UV_IGNORE;
    child_stdio[STDERR].flags      =  UV_INHERIT_FD;
    child_stdio[STDERR].data.fd    =  STDERR;

    // https://github.com/thlorenz/libuv-dox/blob/master/types.md#uv_process_options_t
    worker->options.stdio_count =  3;
    worker->options.stdio       =  child_stdio;
    worker->options.exit_cb     =  on_exit;
    worker->options.file        =  exepath;
    worker->options.args        =  args;

    r = uv_spawn(loop, &worker->req, &worker->options);
    if (r) ERROR("spawning worker", r);

    fprintf(stderr, "Started worker %d\n", worker->req.pid);
  }
}
예제 #15
0
파일: aeternum.c 프로젝트: 4nodejs/aeternum
void spawn_child(int detach) {
  uv_stdio_container_t stdio[3];
  int i;

  options.stdio_count = 3;

  if (detach) {
    for (i = 0; i < options.stdio_count; i++) {
      stdio[i].flags = UV_IGNORE;
    }
  }
  else {
    for (i = 0; i < options.stdio_count; i++) {
      stdio[i].flags = UV_INHERIT_FD;
      stdio[i].data.fd = i;
    }
  }

  options.file = opts.child_args[0];
  options.args = opts.child_args;
  options.stdio = stdio;
  options.env = environ;
  options.exit_cb = detach ? NULL : spawn_cb;
  if (detach) options.flags = UV_PROCESS_DETACHED;

  if (uv_spawn(loop, &child_req, options)) {
    fprintf(stderr, "Error %s\n", uv_err_name(uv_last_error(loop)));
    fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop)));
  }

  if (detach) {
    uv_unref((uv_handle_t*)&child_req);
    return;
  }

  if (opts.pidname != NULL) {
    write_pid_file(child_req.pid, opts.pidname);
  }
}
예제 #16
0
파일: main.c 프로젝트: 343829084/uvbook
int main() {
    loop = uv_default_loop();

    char* args[3];
    args[0] = "sleep";
    args[1] = "100";
    args[2] = NULL;

    options.exit_cb = NULL;
    options.file = "sleep";
    options.args = args;
    options.flags = UV_PROCESS_DETACHED;

    if (uv_spawn(loop, &child_req, options)) {
        fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop)));
        return 1;
    }
    fprintf(stderr, "Launched sleep with PID %d\n", child_req.pid);
    uv_unref((uv_handle_t*) &child_req);

    return uv_run(loop, UV_RUN_DEFAULT);
}
예제 #17
0
MVMObject * MVM_file_openpipe(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env, MVMString *err_path) {
    MVMint64 spawn_result = 0;
    uv_process_t *process = calloc(1, sizeof(uv_process_t));
    uv_process_options_t process_options = {0};
    uv_stdio_container_t process_stdio[3];
    int i;
    int status;
    int readable = 1;
    uv_pipe_t *out, *in;

    char * const cmdin = MVM_string_utf8_encode_C_string(tc, cmd);
    char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd);
    const MVMuint64 size = MVM_repr_elems(tc, env);
    MVMIter * const iter = (MVMIter *)MVM_iter(tc, env);
    char **_env = malloc((size + 1) * sizeof(char *));

#ifdef _WIN32
    const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */
    char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec"));
    char *args[3];
    args[0] = "/c";
    {
        MVMint64 len = strlen(cmdin);
        MVMint64 i;
        for (i = 0; i < len; i++)
            if (cmdin[i] == '/')
                cmdin[i] = '\\';
    }
    args[1] = cmdin;
    args[2] = NULL;
#else
    char * const _cmd = "/bin/sh";
    char *args[4];
    args[0] = "/bin/sh";
    args[1] = "-c";
    args[2] = cmdin;
    args[3] = NULL;
#endif

    INIT_ENV();
    /* Making openpipe distinguish between :rp and :wp and all other options
     * is left as an excercise for the reader. 
    readable = strncmp(cmdin, "/usr/bin/wc", 11) != 0; */

    if (readable) {
        /* We want to read from the child's stdout. */
        out = malloc(sizeof(uv_pipe_t));
        uv_pipe_init(tc->loop, out, 0);
        uv_pipe_open(out, 0);
        process_stdio[0].flags       = UV_INHERIT_FD; // child's stdin
        process_stdio[0].data.fd     = 0;
        process_stdio[1].flags       = UV_CREATE_PIPE | UV_WRITABLE_PIPE; // child's stdout
        process_stdio[1].data.stream = (uv_stream_t*)out;
    }
    else {
        /* We want to print to the child's stdin. */
        in  = malloc(sizeof(uv_pipe_t));
        uv_pipe_init(tc->loop, in, 0);
        uv_pipe_open(in, 1);
        process_stdio[0].flags       = UV_CREATE_PIPE | UV_READABLE_PIPE; // child's stdin
        process_stdio[0].data.stream = (uv_stream_t*)in;
        process_stdio[1].flags       = UV_INHERIT_FD; // child's stdout
        process_stdio[1].data.fd     = 1;
    }
    process_stdio[2].flags      = UV_INHERIT_FD; // child's stderr
    process_stdio[2].data.fd    = 2;
    process_options.stdio       = process_stdio;
    process_options.file        = _cmd;
    process_options.args        = args;
    process_options.cwd         = _cwd;
    process_options.flags       = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_WINDOWS_HIDE;
    process_options.env         = _env;
    process_options.stdio_count = 3;
    process_options.exit_cb     = spawn_on_exit;
    uv_ref((uv_handle_t *)process);
    spawn_result = uv_spawn(tc->loop, process, &process_options);
    if (spawn_result) {
        FREE_ENV();
        free(_cwd);
        free(cmdin);
        uv_unref((uv_handle_t *)process);
        MVM_exception_throw_adhoc(tc, "Failed to open pipe: %d", errno);
    }

    FREE_ENV();
    free(_cwd);
    free(cmdin);
    uv_unref((uv_handle_t *)process);

    return MVM_io_syncpipe(tc, (uv_stream_t *)(readable ? out : in), process);
}
예제 #18
0
파일: shell.c 프로젝트: MarcWeber/neovim
int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
{
  uv_stdio_container_t proc_stdio[3];
  uv_process_options_t proc_opts;
  uv_process_t proc;
  uv_pipe_t proc_stdin, proc_stdout;
  uv_write_t write_req;
  int expected_exits = 1;
  ProcessData pdata = {
    .reading = false,
    .exited = 0,
    .old_mode = cur_tmode,
    .old_state = State,
    .shell_stdin = (uv_stream_t *)&proc_stdin,
    .wbuffer = NULL,
  };

  out_flush();
  if (opts & kShellOptCooked) {
    // set to normal mode
    settmode(TMODE_COOK);
  }

  // While the child is running, ignore terminating signals
  signal_reject_deadly();

  // Create argv for `uv_spawn`
  // TODO(tarruda): we can use a static buffer for small argument vectors. 1024
  // bytes should be enough for most of the commands and if more is necessary
  // we can allocate a another buffer
  proc_opts.args = shell_build_argv(cmd, extra_shell_arg);
  proc_opts.file = proc_opts.args[0];
  proc_opts.exit_cb = exit_cb;
  // Initialize libuv structures
  proc_opts.stdio = proc_stdio;
  proc_opts.stdio_count = 3;
  // Hide window on Windows :)
  proc_opts.flags = UV_PROCESS_WINDOWS_HIDE;
  proc_opts.cwd = NULL;
  proc_opts.env = NULL;

  // The default is to inherit all standard file descriptors(this will change
  // when the UI is moved to an external process)
  proc_stdio[0].flags = UV_INHERIT_FD;
  proc_stdio[0].data.fd = 0;
  proc_stdio[1].flags = UV_INHERIT_FD;
  proc_stdio[1].data.fd = 1;
  proc_stdio[2].flags = UV_INHERIT_FD;
  proc_stdio[2].data.fd = 2;

  if (opts & (kShellOptHideMess | kShellOptExpand)) {
    // Ignore the shell stdio(redirects to /dev/null on unixes)
    proc_stdio[0].flags = UV_IGNORE;
    proc_stdio[1].flags = UV_IGNORE;
    proc_stdio[2].flags = UV_IGNORE;
  } else {
    State = EXTERNCMD;

    if (opts & kShellOptWrite) {
      // Write from the current buffer into the process stdin
      uv_pipe_init(uv_default_loop(), &proc_stdin, 0);
      write_req.data = &pdata;
      proc_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
      proc_stdio[0].data.stream = (uv_stream_t *)&proc_stdin;
    }

    if (opts & kShellOptRead) {
      // Read from the process stdout into the current buffer
      uv_pipe_init(uv_default_loop(), &proc_stdout, 0);
      proc_stdout.data = &pdata;
      proc_stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
      proc_stdio[1].data.stream = (uv_stream_t *)&proc_stdout;
      ga_init(&pdata.ga, 1, BUFFER_LENGTH);
    }
  }

  if (uv_spawn(uv_default_loop(), &proc, &proc_opts)) {
    // Failed, probably due to `sh` not being executable
    if (!emsg_silent) {
      MSG_PUTS(_("\nCannot execute shell "));
      msg_outtrans(p_sh);
      msg_putchar('\n');
    }

    return proc_cleanup_exit(&pdata, &proc_opts, opts);
  }

  // Assign the flag address after `proc` is initialized by `uv_spawn`
  proc.data = &pdata;

  if (opts & kShellOptWrite) {
    // Queue everything for writing to the shell stdin
    write_selection(&write_req);
    expected_exits++;
  }

  if (opts & kShellOptRead) {
    // Start the read stream for the shell stdout
    uv_read_start((uv_stream_t *)&proc_stdout, alloc_cb, read_cb);
    expected_exits++;
  }

  // Keep running the loop until all three handles are completely closed
  while (pdata.exited < expected_exits) {
    uv_run(uv_default_loop(), UV_RUN_ONCE);

    if (got_int) {
      // Forward SIGINT to the shell
      // TODO(tarruda): for now this is only needed if the terminal is in raw
      // mode, but when the UI is externalized we'll also need it, so leave it
      // here
      uv_process_kill(&proc, SIGINT);
      got_int = false;
    }
  }

  if (opts & kShellOptRead) {
    if (pdata.ga.ga_len > 0) {
      // If there's an unfinished line in the growable array, append it now.
      append_ga_line(&pdata.ga);
      // remember that the NL was missing
      curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
    } else {
      curbuf->b_no_eol_lnum = 0;
    }
    ga_clear(&pdata.ga);
  }

  if (opts & kShellOptWrite) {
    free(pdata.wbuffer);
  }

  return proc_cleanup_exit(&pdata, &proc_opts, opts);
}

static int tokenize(char_u *str, char **argv)
{
  int argc = 0, len;
  char_u *p = str;

  while (*p != NUL) {
    len = word_length(p);

    if (argv != NULL) {
      // Fill the slot
      argv[argc] = xmalloc(len + 1);
      memcpy(argv[argc], p, len);
      argv[argc][len] = NUL;
    }

    argc++;
    p += len;
    p = skipwhite(p);
  }

  return argc;
}
예제 #19
0
// Initializes uv_process_t and starts the process.
int luv_spawn(lua_State* L) {
  int before = lua_gettop(L);
  uv_pipe_t* stdin_stream = (uv_pipe_t*)luv_checkudata(L, 1, "pipe");
  uv_pipe_t* stdout_stream = (uv_pipe_t*)luv_checkudata(L, 2, "pipe");
  uv_pipe_t* stderr_stream = (uv_pipe_t*)luv_checkudata(L, 3, "pipe");
  const char* command = luaL_checkstring(L, 4);
  luaL_checktype(L, 5, LUA_TTABLE); // args
  luaL_checktype(L, 6, LUA_TTABLE); // options

  // Parse the args array
  size_t argc = lua_objlen(L, 5) + 1;
  char** args = malloc(argc + 1);
  args[0] = (char*)command;
  int i;
  for (i = 1; i < argc; i++) {
    lua_rawgeti(L, 5, i);
    args[i] = (char*)lua_tostring(L, -1);
    lua_pop(L, 1);
  }
  args[argc] = NULL;

  // Get the cwd
  lua_getfield(L, 6, "cwd");
  char* cwd = (char*)lua_tostring(L, -1);
  lua_pop(L, 1);

  // Get the env
  lua_getfield(L, 6, "env");
  char** env = NULL;
  if (lua_type(L, -1) == LUA_TTABLE) {
    argc = lua_objlen(L, -1);
    env = malloc(argc + 1);
    for (i = 0; i < argc; i++) {
      lua_rawgeti(L, -1, i + 1);
      env[i] = (char*)lua_tostring(L, -1);
      lua_pop(L, 1);
    }
    env[argc] = NULL;
  }
  lua_pop(L, 1);

  uv_process_options_t options;
  options.exit_cb = luv_process_on_exit;
  options.file = command;
  options.args = args;
  options.env = env;
  options.cwd = cwd;
  options.stdin_stream = stdin_stream;
  options.stdout_stream = stdout_stream;
  options.stderr_stream = stderr_stream;

  // Create the userdata
  uv_process_t* handle = (uv_process_t*)lua_newuserdata(L, sizeof(uv_process_t));
  int r = uv_spawn(uv_default_loop(), handle, options);
  free(args);
  if (env) free(env);
  if (r) {
    uv_err_t err = uv_last_error(uv_default_loop());
    return luaL_error(L, "spawn: %s", uv_strerror(err));
  }

  // Set metatable for type
  luaL_getmetatable(L, "luv_process");
  lua_setmetatable(L, -2);

  // Create a local environment for storing stuff
  lua_newtable(L);
  lua_setfenv (L, -2);

  // Store a reference to the userdata in the handle
  luv_ref_t* ref = (luv_ref_t*)malloc(sizeof(luv_ref_t));
  ref->L = L;
  lua_pushvalue(L, -1); // duplicate so we can _ref it
  ref->r = luaL_ref(L, LUA_REGISTRYINDEX);
  handle->data = ref;

  assert(lua_gettop(L) == before + 1);
  // return the userdata
  return 1;
}
예제 #20
0
MVMint64 MVM_proc_spawn(MVMThreadContext *tc, MVMObject *argv, MVMString *cwd, MVMObject *env,
        MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) {
    MVMint64 result = 0, spawn_result;
    uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t));
    uv_process_options_t process_options = {0};
    uv_stdio_container_t process_stdio[3];
    int i;

    char   * const      _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd);
    const MVMuint64     size = MVM_repr_elems(tc, env);
    MVMIter * const     iter = (MVMIter *)MVM_iter(tc, env);
    char              **_env = MVM_malloc((size + 1) * sizeof(char *));
    const MVMuint64  arg_size = MVM_repr_elems(tc, argv);
    char             **args = MVM_malloc((arg_size + 1) * sizeof(char *));
    MVMRegister        reg;

    i = 0;
    while(i < arg_size) {
        REPR(argv)->pos_funcs.at_pos(tc, STABLE(argv), argv, OBJECT_BODY(argv), i, &reg, MVM_reg_obj);
        args[i++] = MVM_string_utf8_c8_encode_C_string(tc, MVM_repr_get_str(tc, reg.o));
    }
    args[arg_size] = NULL;

    INIT_ENV();
    setup_process_stdio(tc, in,  process, &process_stdio[0], 0, flags,      "spawn");
    setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "spawn");
    setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "spawn");

    process_options.stdio       = process_stdio;
    process_options.file        = arg_size ? args[0] : NULL;
    process_options.args        = args;
    process_options.cwd         = _cwd;
    process_options.flags       = UV_PROCESS_WINDOWS_HIDE;
    process_options.env         = _env;
    process_options.stdio_count = 3;
    process_options.exit_cb     = spawn_on_exit;
    if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) {
        process->data = MVM_calloc(1, sizeof(MVMint64));
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
    }
    else {
        process->data = &result;
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
        else
            uv_run(tc->loop, UV_RUN_DEFAULT);
    }

    FREE_ENV();
    MVM_free(_cwd);
    uv_unref((uv_handle_t *)process);

    i = 0;
    while(args[i])
        MVM_free(args[i++]);

    MVM_free(args);

    return result;
}
예제 #21
0
파일: process.c 프로젝트: kidaa/luv
static int luv_spawn(lua_State* L) {
  uv_process_t* handle;
  uv_process_options_t options;
  size_t i, len = 0;
  int ret;

  memset(&options, 0, sizeof(options));
  options.exit_cb = exit_cb;
  options.file = luaL_checkstring(L, 1);
  options.flags = 0;

  // Make sure the 2nd argument is a table
  luaL_checktype(L, 2, LUA_TTABLE);

  // get the args list
  lua_getfield(L, 2, "args");
  // +1 for inserted command at front
  if (lua_type(L, -1) == LUA_TTABLE) {
    len = 1 + lua_rawlen(L, -1);
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 3, "args option must be table");
  }
  else {
    len = 1;
  }
  // +1 for null terminator at end
  options.args = malloc((len + 1) * sizeof(*options.args));
  if (!options.args) {
    luv_clean_options(&options);
    return luaL_error(L, "Problem allocating args");
  }
  options.args[0] = (char*)options.file;
  for (i = 1; i < len; ++i) {
    lua_rawgeti(L, -1, i);
    options.args[i] = (char*)lua_tostring(L, -1);
    lua_pop(L, 1);
  }
  options.args[len] = NULL;
  lua_pop(L, 1);

  // get the stdio list
  lua_getfield(L, 2, "stdio");
  if (lua_type(L, -1) == LUA_TTABLE) {
    options.stdio_count = len = lua_rawlen(L, -1);
    options.stdio = malloc(len * sizeof(*options.stdio));
    if (!options.stdio) {
      luv_clean_options(&options);
      return luaL_error(L, "Problem allocating stdio");
    }
    for (i = 0; i < len; ++i) {
      lua_rawgeti(L, -1, i + 1);
      // integers are assumed to be file descripters
      if (lua_type(L, -1) == LUA_TNUMBER) {
        options.stdio[i].flags = UV_INHERIT_FD;
        options.stdio[i].data.fd = lua_tointeger(L, -1);
      }
      // userdata is assumed to be a uv_stream_t instance
      else if (lua_type(L, -1) == LUA_TUSERDATA) {
        uv_os_fd_t fd;
        uv_stream_t* stream = luv_check_stream(L, -1);
        int err = uv_fileno((uv_handle_t*)stream, &fd);
        if (err == UV_EINVAL || err == UV_EBADF) {
          options.stdio[i].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE;
        }
        else {
          options.stdio[i].flags = UV_INHERIT_STREAM;
        }
        options.stdio[i].data.stream = stream;
      }
      else if (lua_type(L, -1) == LUA_TNIL) {
        options.stdio[i].flags = UV_IGNORE;
      }
      else {
        luv_clean_options(&options);
        return luaL_argerror(L, 2, "stdio table entries must be nil, uv_stream_t, or integer");
      }
      lua_pop(L, 1);
    }
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "stdio option must be table");
  }
  lua_pop(L, 1);

  // Get the env
  lua_getfield(L, 2, "env");
  if (lua_type(L, -1) == LUA_TTABLE) {
    len = lua_rawlen(L, -1);
    options.env = malloc((len + 1) * sizeof(*options.env));
    if (!options.env) {
      luv_clean_options(&options);
      return luaL_error(L, "Problem allocating env");
    }
    for (i = 0; i < len; ++i) {
      lua_rawgeti(L, -1, i + 1);
      options.env[i] = (char*)lua_tostring(L, -1);
      lua_pop(L, 1);
    }
    options.env[len] = NULL;
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "env option must be table");
  }
  lua_pop(L, 1);

  // Get the cwd
  lua_getfield(L, 2, "cwd");
  if (lua_type(L, -1) == LUA_TSTRING) {
    options.cwd = (char*)lua_tostring(L, -1);
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "cwd option must be string");
  }
  lua_pop(L, 1);

  // Check for uid
  lua_getfield(L, 2, "uid");
  if (lua_type(L, -1) == LUA_TNUMBER) {
    options.uid = lua_tointeger(L, -1);
    options.flags |= UV_PROCESS_SETUID;
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "uid option must be number");
  }
  lua_pop(L, 1);

  // Check for gid
  lua_getfield(L, 2, "gid");
  if (lua_type(L, -1) == LUA_TNUMBER) {
    options.gid = lua_tointeger(L, -1);
    options.flags |= UV_PROCESS_SETGID;
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "gid option must be number");
  }
  lua_pop(L, 1);

  // Check for the boolean flags
  lua_getfield(L, 2, "verbatim");
  if (lua_toboolean(L, -1)) {
    options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
  }
  lua_pop(L, 1);
  lua_getfield(L, 2, "detached");
  if (lua_toboolean(L, -1)) {
    options.flags |= UV_PROCESS_DETACHED;
  }
  lua_pop(L, 1);
  lua_getfield(L, 2, "hide");
  if (lua_toboolean(L, -1)) {
    options.flags |= UV_PROCESS_WINDOWS_HIDE;
  }
  lua_pop(L, 1);

  handle = lua_newuserdata(L, sizeof(*handle));
  handle->type = UV_PROCESS;
  handle->data = luv_setup_handle(L);

  if (!lua_isnoneornil(L, 3)) {
    luv_check_callback(L, handle->data, LUV_EXIT, 3);
  }

  ret = uv_spawn(luv_loop(L), handle, &options);

  luv_clean_options(&options);
  if (ret < 0) {
    /* The async callback is required here because luajit GC may reclaim the
     * luv handle before libuv is done closing it down.
     */
    uv_close((uv_handle_t*)handle, luv_spawn_close_cb);
    return luv_error(L, ret);
  }
  lua_pushinteger(L, handle->pid);
  return 2;
}
예제 #22
0
파일: job.c 프로젝트: Saneyan/neovim
int job_start(char **argv,
              void *data,
              rstream_cb stdout_cb,
              rstream_cb stderr_cb,
              job_exit_cb job_exit_cb)
{
  int i;
  Job *job;

  // Search for a free slot in the table
  for (i = 0; i < MAX_RUNNING_JOBS; i++) {
    if (table[i] == NULL) {
      break;
    }
  }

  if (i == MAX_RUNNING_JOBS) {
    // No free slots
    return 0;
  }

  job = xmalloc(sizeof(Job));
  // Initialize
  job->id = i + 1;
  job->pending_refs = 3;
  job->pending_closes = 4;
  job->data = data;
  job->stdout_cb = stdout_cb;
  job->stderr_cb = stderr_cb;
  job->exit_cb = job_exit_cb;
  job->stopped = false;
  job->exit_timeout = EXIT_TIMEOUT;
  job->proc_opts.file = argv[0];
  job->proc_opts.args = argv;
  job->proc_opts.stdio = job->stdio;
  job->proc_opts.stdio_count = 3;
  job->proc_opts.flags = UV_PROCESS_WINDOWS_HIDE;
  job->proc_opts.exit_cb = exit_cb;
  job->proc_opts.cwd = NULL;
  job->proc_opts.env = NULL;
  job->proc.data = NULL;
  job->proc_stdin.data = NULL;
  job->proc_stdout.data = NULL;
  job->proc_stderr.data = NULL;

  // Initialize the job std{in,out,err}
  uv_pipe_init(uv_default_loop(), &job->proc_stdin, 0);
  job->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
  job->stdio[0].data.stream = (uv_stream_t *)&job->proc_stdin;

  uv_pipe_init(uv_default_loop(), &job->proc_stdout, 0);
  job->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
  job->stdio[1].data.stream = (uv_stream_t *)&job->proc_stdout;

  uv_pipe_init(uv_default_loop(), &job->proc_stderr, 0);
  job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
  job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr;

  // Spawn the job
  if (uv_spawn(uv_default_loop(), &job->proc, &job->proc_opts) != 0) {
    free_job(job);
    return -1;
  }

  // Give all handles a reference to the job
  handle_set_job((uv_handle_t *)&job->proc, job);
  handle_set_job((uv_handle_t *)&job->proc_stdin, job);
  handle_set_job((uv_handle_t *)&job->proc_stdout, job);
  handle_set_job((uv_handle_t *)&job->proc_stderr, job);

  job->in = wstream_new(JOB_WRITE_MAXMEM);
  wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin);
  // Start the readable streams
  job->out = rstream_new(read_cb, JOB_BUFFER_SIZE, job, true);
  job->err = rstream_new(read_cb, JOB_BUFFER_SIZE, job, true);
  rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout);
  rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr);
  rstream_start(job->out);
  rstream_start(job->err);
  // Save the job to the table
  table[i] = job;

  // Start polling job status if this is the first
  if (job_count == 0) {
    uv_prepare_start(&job_prepare, job_prepare_cb);
  }
  job_count++;

  return job->id;
}
예제 #23
0
pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked)
{
#if defined(__linux__)

    /* posix_spawnp of Linux does not return error if the executable does not exist, see
     * https://gist.github.com/kazuho/0c233e6f86d27d6e4f09
     */
    extern char **environ;
    int pipefds[2] = {-1, -1}, errnum;
    pid_t pid;

    /* create pipe, used for sending error codes */
    if (pipe2(pipefds, O_CLOEXEC) != 0)
        goto Error;

    /* fork */
    if (!cloexec_mutex_is_locked)
        pthread_mutex_lock(&cloexec_mutex);
    if ((pid = fork()) == 0) {
        /* in child process, map the file descriptors and execute; return the errnum through pipe if exec failed */
        if (mapped_fds != NULL) {
            for (; *mapped_fds != -1; mapped_fds += 2) {
                if (mapped_fds[1] != -1)
                    dup2(mapped_fds[0], mapped_fds[1]);
                close(mapped_fds[0]);
            }
        }
        char **env = build_spawn_env();
        if (env != NULL)
            environ = env;
        execvp(cmd, argv);
        errnum = errno;
        write(pipefds[1], &errnum, sizeof(errnum));
        _exit(EX_SOFTWARE);
    }
    if (!cloexec_mutex_is_locked)
        pthread_mutex_unlock(&cloexec_mutex);
    if (pid == -1)
        goto Error;

    /* parent process */
    close(pipefds[1]);
    pipefds[1] = -1;
    ssize_t rret;
    errnum = 0;
    while ((rret = read(pipefds[0], &errnum, sizeof(errnum))) == -1 && errno == EINTR)
        ;
    if (rret != 0) {
        /* spawn failed */
        while (waitpid(pid, NULL, 0) != pid)
            ;
        pid = -1;
        errno = errnum;
        goto Error;
    }

    /* spawn succeeded */
    close(pipefds[0]);
    return pid;

Error:
    errnum = errno;
    if (pipefds[0] != -1)
        close(pipefds[0]);
    if (pipefds[1] != -1)
        close(pipefds[1]);
    errno = errnum;
    return -1;

#elif defined _MSC_VER //-- : process : https://msdn.microsoft.com/en-us/library/20y988d2.aspx
	pid_t pid;
	extern char** environ;
	uv_loop_t *loop;
	uv_process_t child_req;
	uv_process_options_t options = { 0 }; //-- Default initialization must be 0
	loop = uv_default_loop();
	//-- Container for file descruptor
	uv_stdio_container_t child_stdio[3];
	child_stdio[0].flags = UV_IGNORE;
	child_stdio[1].flags = UV_INHERIT_FD; //STD_OUT should be redirected to calling function
	child_stdio[2].flags = UV_IGNORE;

	if (mapped_fds != NULL) {
		for (; *mapped_fds != -1; mapped_fds += 2) {
			if (mapped_fds[1] != -1)
				//dup2(mapped_fds[0], mapped_fds[1]); //Equivalent to dup2() in *inx systems.
				child_stdio[1].data.fd = mapped_fds[0]; //2 or 1?
														//close(mapped_fds[0]); //add or delete a close or open action to a spawn file actions object
		}
	}

	if (!cloexec_mutex_is_locked)
		uv_mutex_lock(&cloexec_mutex);

	options.stdio = child_stdio;
	options.exit_cb = waitpid; //This function will be executed when child exists.
	options.file = cmd;
	options.args = argv;
	options.env = environ;
	//If the process is successfully spawned, this function will return 0.
	errno = uv_spawn(loop, &child_req, &options);
	pid = child_req.pid;


	if (!cloexec_mutex_is_locked)
		uv_mutex_unlock(&cloexec_mutex);
	if (errno != 0)
		return -1;


	return pid;
#else
    posix_spawn_file_actions_t file_actions;
    pid_t pid;
    extern char **environ;
    char **env = build_spawn_env();
    posix_spawn_file_actions_init(&file_actions);
    if (mapped_fds != NULL) {
        for (; *mapped_fds != -1; mapped_fds += 2) {
            if (mapped_fds[1] != -1)
                posix_spawn_file_actions_adddup2(&file_actions, mapped_fds[0], mapped_fds[1]);
            posix_spawn_file_actions_addclose(&file_actions, mapped_fds[0]);
        }
    }
    if (!cloexec_mutex_is_locked)
        pthread_mutex_lock(&cloexec_mutex);
    errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, env != NULL ? env : environ);
    if (!cloexec_mutex_is_locked)
        pthread_mutex_unlock(&cloexec_mutex);
    free(env);
    if (errno != 0)
        return -1;

    return pid;

#endif
}
예제 #24
0
MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env,
        MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) {
    MVMint64 result = 0, spawn_result;
    uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t));
    uv_process_options_t process_options = {0};
    uv_stdio_container_t process_stdio[3];
    int i;

    char * const cmdin = MVM_string_utf8_c8_encode_C_string(tc, cmd);
    char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd);
    const MVMuint64 size = MVM_repr_elems(tc, env);
    MVMIter * const iter = (MVMIter *)MVM_iter(tc, env);
    char **_env = MVM_malloc((size + 1) * sizeof(char *));

#ifdef _WIN32
    const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */
    char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec"));
    char *args[3];
    args[0] = "/c";
    args[1] = cmdin;
    args[2] = NULL;
#else
    char * const _cmd = "/bin/sh";
    char *args[4];
    args[0] = "/bin/sh";
    args[1] = "-c";
    args[2] = cmdin;
    args[3] = NULL;
#endif

    INIT_ENV();
    setup_process_stdio(tc, in,  process, &process_stdio[0], 0, flags,      "shell");
    setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "shell");
    setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "shell");

    process_options.stdio       = process_stdio;
    process_options.file        = _cmd;
    process_options.args        = args;
    process_options.cwd         = _cwd;
    process_options.flags       = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_WINDOWS_HIDE;
    process_options.env         = _env;
    process_options.stdio_count = 3;
    process_options.exit_cb     = spawn_on_exit;
    if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) {
        process->data = MVM_calloc(1, sizeof(MVMint64));
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
    }
    else {
        process->data = &result;
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
        else
            uv_run(tc->loop, UV_RUN_DEFAULT);
    }

    FREE_ENV();
    MVM_free(_cwd);
#ifdef _WIN32
    MVM_free(_cmd);
#endif
    MVM_free(cmdin);
    uv_unref((uv_handle_t *)process);

    return result;
}
예제 #25
0
파일: process.c 프로젝트: ifzz/LuaIO
static int LuaIO_process_fork(lua_State* L) {
  if (lua_type(L, 1) != LUA_TTABLE) {
    return luaL_argerror(L, 1, "process.fork(options) error: options must be [table]\n"); 
  }

  if (!LuaIO_process_exepath_ptr) {
    size_t length = sizeof(LuaIO_process_exepath);
    int err = uv_exepath(LuaIO_process_exepath, &length);
    if (err < 0) {
      return luaL_error(L, "process.fork(options) uv_exepath() error: %s\n", uv_strerror(err));
    }

    LuaIO_process_exepath_ptr = LuaIO_process_exepath;
  }

  lua_getfield(L, 1, "file");
  const char* file;
  if (lua_type(L, -1) == LUA_TSTRING) {
    file = lua_tostring(L, -1);
  } else {
    return luaL_argerror(L, 2, "process.fork(options) error: options.file is required and must be [string]\n"); 
  }
  lua_pop(L, 1);

  lua_getfield(L, 1, "args");
  size_t args_length = 0;
  char** args = NULL;
  if (lua_type(L, -1) == LUA_TTABLE) {
    args_length = lua_rawlen(L, -1);
    /*execpath, file, null => args_length + 3*/
    args = LuaIO_malloc(sizeof(char*) * (args_length + 3));
    if (!args) {
      return luaL_error(L, "process.fork(options) error: no memory for args\n");
    }

    for (size_t i = 1; i <= args_length; ++i) {
      lua_rawgeti(L, -1, i);
      args[i + 1] = (char*)luaL_checkstring(L, -1);
      lua_pop(L, 1);
    }
  } else if (lua_type(L, -1) == LUA_TNIL) {
    /*execpath, file, null => args_length + 3*/
    args = LuaIO_malloc(sizeof(char*) * 3);
    if (!args) {
      return luaL_error(L, "process.fork(options) error: no memory for args\n");
    }
  } else {
    return luaL_argerror(L, 2, "process.fork(options) error: options.args must be [table]\n"); 
  }
  lua_pop(L, 1);

  args[0] = LuaIO_process_exepath_ptr;
  args[1] = (char*)file;
  args[args_length + 2] = NULL;

  if (!LuaIO_process_stdio_ptr) { 
    LuaIO_process_stdio[0].flags = UV_INHERIT_FD;
    LuaIO_process_stdio[0].data.fd = 0;
    LuaIO_process_stdio[1].flags = UV_INHERIT_FD;
    LuaIO_process_stdio[1].data.fd = 1;
    LuaIO_process_stdio[2].flags = UV_INHERIT_FD;
    LuaIO_process_stdio[2].data.fd = 2;
    LuaIO_process_stdio_ptr = LuaIO_process_stdio;
  }

  uv_process_options_t* options = LuaIO_malloc(sizeof(uv_process_options_t));
  if (!options) {
    LuaIO_free(args);
    return luaL_error(L, "process.fork(options) error: no memory for uv_process_options_t options\n");
  }
  LuaIO_memzero(options, sizeof(uv_process_options_t));
  options->exit_cb = LuaIO_process_onexit;
  options->file = LuaIO_process_exepath_ptr;
  options->args = args;
  options->stdio_count = 3;
  options->stdio = LuaIO_process_stdio_ptr;

  lua_getfield(L, 1, "uid");
  if (lua_type(L, -1) == LUA_TNUMBER) {
    options->uid = lua_tointeger(L, -1);
    options->flags |= UV_PROCESS_SETUID;
  } else if (lua_type(L, -1) != LUA_TNIL) {
    LuaIO_process_free_options(options);
    return luaL_argerror(L, 2, "process.fork(options) error: options.uid must be [number]\n"); 
  }
  lua_pop(L, 1);

  lua_getfield(L, 1, "gid");
  if (lua_type(L, -1) == LUA_TNUMBER) {
    options->gid = lua_tointeger(L, -1);
    options->flags |= UV_PROCESS_SETGID;
  } else if (lua_type(L, -1) != LUA_TNIL) {
    LuaIO_process_free_options(options);
    return luaL_argerror(L, 2, "process.fork(options) error: options.gid must be [number]\n"); 
  }
  lua_pop(L, 1);

  lua_getfield(L, 1, "detached");
  if (lua_toboolean(L, -1)) {
    options->flags |= UV_PROCESS_DETACHED;
  }
  lua_pop(L, 1);

  lua_getfield(L, 1, "forever");
  int forever = lua_toboolean(L, -1);
  lua_pop(L, 1);
  
  int cpu = -1; 
  lua_getfield(L, 1, "cpu");
  if (lua_type(L, -1) == LUA_TNUMBER) {
    cpu = lua_tointeger(L, -1);
  } else if (lua_type(L, -1) != LUA_TNIL) {
    LuaIO_process_free_options(options);
    return luaL_argerror(L, 2, "process.fork(options) error: options.cpu must be [number]\n"); 
  }
  lua_pop(L, 1);

  uv_process_t* handle = LuaIO_malloc(sizeof(uv_process_t));
  if (!handle) {
    LuaIO_process_free_options(options);
    return luaL_error(L, "process.fork(options) error: no memory for uv_process_t handle.\n");
  }
  LuaIO_memzero(handle, sizeof(uv_process_t));

  LuaIO_process_data_t* data = NULL;
  if (forever) {
    data = LuaIO_malloc(sizeof(LuaIO_process_data_t));
    if (!data) {
      LuaIO_process_free_options(options);
      return luaL_error(L, "process.fork(options) error:no memory for LuaIO_process_data_t data.\n");
    }
    
    lua_pushvalue(L, 1);
    data->options_ref = luaL_ref(L, LUA_REGISTRYINDEX);
    data->options = options;
    data->cpu = cpu;
    handle->data = data;
  }

  int ret = uv_spawn(uv_default_loop(), handle, options);
  if (ret < 0) {
    LuaIO_process_free_options(options);
    luaL_unref(L, LUA_REGISTRYINDEX, data->options_ref);
    LuaIO_free(data);
    uv_close((uv_handle_t*)handle, NULL);
    return luaL_error(L, "process.fork(options) uv_spawn() error: %s\n", uv_strerror(ret));
  }
  if (cpu >= 0) LuaIO_set_affinity(handle->pid, cpu);

  if (!LuaIO_process_signal_ptr) {
    uv_signal_init(uv_default_loop(), &LuaIO_process_signal);
    LuaIO_process_signal_ptr = &LuaIO_process_signal;
    uv_signal_start(LuaIO_process_signal_ptr, LuaIO_process_signal_callback, SIGQUIT);
  }

  lua_pushinteger(L, handle->pid);

  return 1;
}
예제 #26
0
파일: luv_process.c 프로젝트: Strongc/luv
static int luv_new_process(lua_State* L) {
  const char* cmd = luaL_checkstring(L, 1);
  size_t argc;
  char** args;
  int i;
  char* cwd;
  char** env;
  uv_process_options_t opts;
  int rv;

  luaL_checktype(L, 2, LUA_TTABLE); /* options */
  memset(&opts, 0, sizeof(uv_process_options_t));

  argc = lua_objlen(L, 2);
  args = (char**)malloc((argc + 1) * sizeof(char*));
  args[0] = (char*)cmd;
  for (i = 1; i <= argc; i++) {
    lua_rawgeti(L, -1, i);
    args[i] = (char*)lua_tostring(L, -1);
    lua_pop(L, 1);
  }

  args[argc + 1] = NULL;

  cwd = NULL;
  lua_getfield(L, 2, "cwd");
  if (!lua_isnil(L, -1)) {
    cwd = (char*)lua_tostring(L, -1);
  }
  lua_pop(L, 1);

  env = NULL;
  lua_getfield(L, 2, "env");
  if (!lua_isnil(L, -1)) {
    int i, len;
    const char* key;
    const char* val;
    len = 32;
    env = (char**)malloc(32 * sizeof(char*));

    lua_pushnil(L);
    i = 0;
    while (lua_next(L, -2) != 0) {
      if (i >= len) {
        len *= 2;
        env = (char**)realloc(env, len * sizeof(char*));
      }
      key = lua_tostring(L, -2);
      val = lua_tostring(L, -1);
      lua_pushfstring(L, "%s=%s", key, val);
      env[i++] = (char*)lua_tostring(L, -1);
      lua_pop(L, 2);
    }

    env[i] = NULL;
  }
  lua_pop(L, 1);

  opts.exit_cb = _exit_cb;
  opts.file    = cmd;
  opts.args    = args;
  opts.env     = env;
  opts.cwd     = cwd;

  uv_stdio_container_t stdio[3];
  opts.stdio_count = 3;

  const char* stdfh_names[] = { "stdin", "stdout", "stderr" };
  for (i = 0; i < 3; i++) {
    lua_getfield(L, 2, stdfh_names[i]);
    if (lua_isnil(L, -1)) {
      stdio[i].flags = UV_IGNORE;
    }
    else {
      luv_object_t* obj = (luv_object_t*)luaL_checkudata(L, -1, LUV_PIPE_T);
      stdio[i].flags = UV_INHERIT_STREAM;
      stdio[i].data.stream = &obj->h.stream;
    }
    lua_pop(L, 1);
  }

  opts.stdio = stdio;

  lua_getfield(L, 2, "detach");
  if (lua_toboolean(L, -1)) {
    opts.flags |= UV_PROCESS_DETACHED;
  }
  else {
    opts.flags = 0;
  }
  lua_pop(L, 1);

  luv_state_t*  curr = luvL_state_self(L);

  luv_object_t* self = (luv_object_t*)lua_newuserdata(L, sizeof(luv_object_t));
  luaL_getmetatable(L, LUV_PROCESS_T);
  lua_setmetatable(L, -2);

  luvL_object_init(curr, self);

  lua_insert(L, 1);
  lua_settop(L, 1);

  rv = uv_spawn(luvL_event_loop(L), &self->h.process, opts);

  free(args);
  if (env) free(env);
  if (rv) {
    uv_err_t err = uv_last_error(luvL_event_loop(L));
    return luaL_error(L, uv_strerror(err));
  }

  if (opts.flags & UV_PROCESS_DETACHED) {
    uv_unref((uv_handle_t*)&self->h.process);
    return 1;
  }
  else {
    return luvL_cond_wait(&self->rouse, curr);
  }
}
예제 #27
0
int ftw_libuv_spawn_process(struct ftw_libuv_callsite **callsite, LVUserEventRef *lv_event,
    char *exe, char *cmd, int64_t *exit_code, int64_t *signal)
{
    int rc;
    char *args [3];
    uv_loop_t loop;
    uv_pipe_t stdout_pipe;
    uv_pipe_t stderr_pipe;
    uv_process_t new_process;
    uv_process_options_t opts = {0};
    uv_stdio_container_t iostreams [3];
    struct ftw_libuv_process proc_data = {0};
    struct ftw_libuv_stream context;

    /*  Preconditions expected of LabVIEW. */
    ftw_assert(callsite && *callsite && lv_event && cmd);

    rc = uv_loop_init(&loop);
    if (rc) {
        return rc;
    }

    args[0] = exe;
    args[1] = cmd;
    args[2] = NULL;

    proc_data.exit_code = exit_code;
    proc_data.signal = signal;
    new_process.data = &proc_data;
    context.msg_to_lv_event = lv_event;
    stdout_pipe.data = &context;
    stderr_pipe.data = &context;

    rc = uv_pipe_init(&loop, &stdout_pipe, 0);
    if (rc) {
        uv_loop_close(&loop);
        return rc;
    }

    rc = uv_pipe_init(&loop, &stderr_pipe, 0);
    if (rc) {
        uv_loop_close(&loop);
        return rc;
    }

    opts.stdio_count = 3;
    opts.stdio = iostreams;
    opts.stdio[0].flags = UV_IGNORE;
    opts.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
    opts.stdio[1].data.stream = (uv_stream_t *) &stdout_pipe;
    opts.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
    opts.stdio[2].data.stream = (uv_stream_t *) &stderr_pipe;
    //opts.stdio[2].flags = UV_IGNORE;
    
    opts.file = exe;
    opts.args = args;
    opts.exit_cb = ftw_libuv_callback_process_exit;

    rc = uv_spawn(&loop, &new_process, &opts);
    if (rc) {
        uv_loop_close(&loop);
        return rc;
    }

    rc = uv_read_start((uv_stream_t*) &stdout_pipe, ftw_libuv_callback_alloc, ftw_libuv_callback_read_pipe);
    if (rc) {
        uv_loop_close(&loop);
        return rc;
    }

    rc = uv_read_start((uv_stream_t*) &stderr_pipe, ftw_libuv_callback_alloc, ftw_libuv_callback_read_pipe);
    if (rc) {
        uv_loop_close(&loop);
        return rc;
    }

    rc = uv_run(&loop, UV_RUN_DEFAULT);
    if (rc) {
        uv_loop_close(&loop);
        return rc;
    }

    rc = uv_loop_close(&loop);

    return rc;
}
예제 #28
0
static void launch_vice_with_config(PluginData* data) {
    int r, cmdIndex = 1;
    uv_process_options_t options = { 0 };

    log_debug("spawning vice...\n", "");

    char* args[10];
    args[0] = (char*)data->config.vice_exe;

    // TODO: Must generate the breakpoint file from the json one

    args[cmdIndex++] = "-remotemonitor";

    if (data->config.breakpoint_file) {
        //args[cmdIndex++] = "-moncommands";
        //args[cmdIndex++] = "examples/c64_vice/test_mon.txt";
    }

    //args[cmdIndex++] = (char*)data->config.prg_file;
    args[cmdIndex++] = NULL;

    options.exit_cb = 0;
    options.file = data->config.vice_exe;
    options.args = args;

    if ((r = uv_spawn(uv_default_loop(), &data->process, &options))) {
        MESSAGE_FUNCS->error("Unable to launch VICE", uv_strerror(r));
        return;
    }

    sleepMs(3000);

    connect_to_local_host(data);

    // if connected we load the image and make sure we get a reply back

    if (VICEConnection_isConnected(data->conn)) {
        log_debug("connected to vice...\n", "");

        if (!load_image(data, data->config.prg_file)) {
            return;
		}

        log_debug("image loaded ...\n", "");

        // parse the

        parse_mon_file(data, data->config.breakpoint_file);

        log_debug("start from basic...\n", "");

        // start vice!

        log_debug("started from basic\n", "");

        uint16_t address = 0; //get_basic_start(data);

        parse_mon_file(data, data->config.breakpoint_file);

        if (address != 0) {
            log_debug("start from %x\n", address);
            send_command(data, "g %x\n", address);
        }

        return;
    }

    log_debug("unable to make connection with vice\n", "");
}
예제 #29
0
파일: process.c 프로젝트: poupas/pyuv
static PyObject *
Process_func_spawn(Process *self, PyObject *args, PyObject *kwargs)
{
    int err, flags, len, stdio_count;
    unsigned int uid, gid;
    char *cwd, *cwd2, *file, *file2, *arg_str, *tmp_str, *key_str, *value_str;
    char **ptr, **process_args, **process_env;
    Py_ssize_t i, n, pos;
    PyObject *key, *value, *item, *tmp, *callback, *arguments, *env, *stdio, *ret;
    uv_process_options_t options;
    uv_stdio_container_t *stdio_container;

    static char *kwlist[] = {"file", "exit_callback", "args", "env", "cwd", "uid", "gid", "flags", "stdio", NULL};

    cwd = NULL;
    ptr = process_args = process_env = NULL;
    tmp = arguments = env = stdio = NULL;
    stdio_container = NULL;
    flags = uid = gid = stdio_count = 0;

    RAISE_IF_SPAWNED(self, NULL);

    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOO!sIIiO:__init__", kwlist, &file, &callback, &arguments, &PyDict_Type, &env, &cwd, &uid, &gid, &flags, &stdio)) {
        return NULL;
    }

    if (callback != Py_None && !PyCallable_Check(callback)) {
        PyErr_SetString(PyExc_TypeError, "a callable is required");
        return NULL;
    }

    if (arguments && !PySequence_Check(arguments)) {
        PyErr_SetString(PyExc_TypeError, "only iterable objects are supported for 'args'");
        return NULL;
    }

    if (stdio && !PySequence_Check(stdio)) {
        PyErr_SetString(PyExc_TypeError, "only iterable objects are supported for 'stdio'");
        return NULL;
    }

    memset(&options, 0, sizeof(uv_process_options_t));

    options.uid = uid;
    options.gid = gid;
    options.flags = flags;
    options.exit_cb = on_process_exit;

    file2 = PyMem_Malloc(strlen(file) + 1);
    if (!file2) {
        PyErr_NoMemory();
        ret = NULL;
        goto cleanup;
    }
    strcpy(file2, file);
    options.file = file2;

    if (arguments) {
        n = PySequence_Length(arguments);
        process_args = PyMem_Malloc(sizeof *process_args * (n + 2));
        if (!process_args) {
            PyErr_NoMemory();
            PyMem_Free(file2);
            ret = NULL;
            goto cleanup;
        }
        process_args[0] = file2;
        i = 0;
        while (i < n) {
            item = PySequence_GetItem(arguments, i);
            if (!item || !PyArg_Parse(item, "s;args contains a non-string value", &arg_str)) {
                Py_XDECREF(item);
                ret = NULL;
                goto cleanup;
            }
            tmp_str = PyMem_Malloc(strlen(arg_str) + 1);
            if (!tmp_str) {
                Py_DECREF(item);
                ret = NULL;
                goto cleanup;
            }
            strcpy(tmp_str, arg_str);
            process_args[i+1] = tmp_str;
            Py_DECREF(item);
            i++;
        }
        process_args[i+1] = NULL;
    } else {
        process_args = PyMem_Malloc(sizeof *process_args * 2);
        if (!process_args) {
            PyErr_NoMemory();
            PyMem_Free(file2);
            ret = NULL;
            goto cleanup;
        }
        process_args[0] = file2;
        process_args[1] = NULL;
    }
    options.args = process_args;

    if (cwd) {
        cwd2 = PyMem_Malloc(strlen(cwd) + 1);
        if (!cwd2) {
            PyErr_NoMemory();
            ret = NULL;
            goto cleanup;
        }
        strcpy(cwd2, cwd);
        options.cwd = cwd2;
    }

    if (env) {
        n = PyDict_Size(env);
        if (n > 0) {
            process_env = PyMem_Malloc(sizeof *process_env * (n + 1));
            if (!process_env) {
                PyErr_NoMemory();
                ret = NULL;
                goto cleanup;
            }
            i = 0;
            pos = 0;
            while (PyDict_Next(env, &pos, &key, &value)) {
                if (!PyArg_Parse(key, "s;env contains a non-string key", &key_str) || !PyArg_Parse(value, "s;env contains a non-string value", &value_str)) {
                    ret = NULL;
                    goto cleanup;
                }
                len = strlen(key_str) + strlen(value_str) + 2;
                tmp_str = PyMem_Malloc(len);
                if (!tmp_str) {
                    PyErr_NoMemory();
                    ret = NULL;
                    goto cleanup;
                }
                PyOS_snprintf(tmp_str, len, "%s=%s", key_str, value_str);
                process_env[i] = tmp_str;
                i++;
            }
            process_env[i] = NULL;
        }
    }
    options.env = process_env;

    if (stdio) {
        n = PySequence_Length(stdio);
        stdio_container = PyMem_Malloc(sizeof *stdio_container * n);
        if (!stdio_container) {
            PyErr_NoMemory();
            ret = NULL;
            goto cleanup;
        }
        item = NULL;
        for (i = 0;i < n; i++) {
            item = PySequence_GetItem(stdio, i);
            if (!item || !PyObject_TypeCheck(item, &StdIOType)) {
                Py_XDECREF(item);
                PyErr_SetString(PyExc_TypeError, "a StdIO instance is required");
                ret = NULL;
                goto cleanup;
            }
            stdio_count++;
            stdio_container[i].flags = ((StdIO *)item)->flags;
            if (((StdIO *)item)->flags & (UV_CREATE_PIPE | UV_INHERIT_STREAM)) {
                stdio_container[i].data.stream = (uv_stream_t *)(UV_HANDLE(((StdIO *)item)->stream));
            } else if (((StdIO *)item)->flags & UV_INHERIT_FD) {
                stdio_container[i].data.fd = ((StdIO *)item)->fd;
            }
            Py_DECREF(item);
        }
    }
    options.stdio = stdio_container;
    options.stdio_count = stdio_count;

    err = uv_spawn(UV_HANDLE_LOOP(self), &self->process_h, &options);
    if (err < 0) {
        RAISE_UV_EXCEPTION(err, PyExc_ProcessError);
        ret = NULL;
        goto cleanup;
    }

    tmp = (PyObject *)self->on_exit_cb;
    Py_INCREF(callback);
    self->on_exit_cb = callback;
    Py_XDECREF(tmp);

    tmp = self->stdio;
    Py_XINCREF(stdio);
    self->stdio = stdio;
    Py_XDECREF(tmp);

    HANDLE(self)->initialized = True;
    self->spawned = True;

    ret = Py_None;

    /* Increase refcount so that object is not removed before the exit callback is called */
    Py_INCREF(self);

cleanup:
    if (options.args) {
        for (ptr = options.args; *ptr != NULL; ptr++) {
            PyMem_Free(*ptr);
        }
    }

    if (options.env) {
        for (ptr = options.env; *ptr != NULL; ptr++) {
            PyMem_Free(*ptr);
        }
    }

    PyMem_Free(options.args);
    PyMem_Free(options.cwd);
    PyMem_Free(options.env);
    PyMem_Free(options.stdio);

    Py_XINCREF(ret);
    return ret;
}
예제 #30
0
파일: rust_uv.cpp 프로젝트: amishra-1/rust
extern "C" int
rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) {
  return uv_spawn(loop, p, options);
}