Beispiel #1
0
/*
 * Starts an i3-nagbar instance with the given parameters. Takes care of
 * handling SIGCHLD and killing i3-nagbar when i3 exits.
 *
 * The resulting PID will be stored in *nagbar_pid and can be used with
 * kill_nagbar() to kill the bar later on.
 *
 */
void start_nagbar(pid_t *nagbar_pid, char *argv[]) {
    if (*nagbar_pid != -1) {
        DLOG("i3-nagbar already running (PID %d), not starting again.\n", *nagbar_pid);
        return;
    }

    *nagbar_pid = fork();
    if (*nagbar_pid == -1) {
        warn("Could not fork()");
        return;
    }

    /* child */
    if (*nagbar_pid == 0)
        exec_i3_utility("i3-nagbar", argv);

    DLOG("Starting i3-nagbar with PID %d\n", *nagbar_pid);

    /* parent */
    /* install a child watcher */
    ev_child *child = smalloc(sizeof(ev_child));
    ev_child_init(child, &nagbar_exited, *nagbar_pid, 0);
    child->data = nagbar_pid;
    ev_child_start(main_loop, child);

    /* install a cleanup watcher (will be called when i3 exits and i3-nagbar is
     * still running) */
    ev_cleanup *cleanup = smalloc(sizeof(ev_cleanup));
    ev_cleanup_init(cleanup, nagbar_cleanup);
    cleanup->data = nagbar_pid;
    ev_cleanup_start(main_loop, cleanup);
}
Beispiel #2
0
int setup_workers(struct ev_loop* loop, struct listener_s* listener) {
    char* ip = listener->argv[1];
    uint16_t port = (uint16_t)atoi(listener->argv[2]);

    int listen_fd;
#ifndef SO_REUSEPORT
    listen_fd = start_listen(ip, port);
#endif

    pid_t pid;
    int i;
    struct worker_s* workers = listener->workers;
    for (i = 0; i < listener->worker_count; i++) {
#ifdef SO_REUSEPORT
        listen_fd = start_listen(ip, port);
#endif
        workers[i].listen_fd = listen_fd;
        workers[i].worker_id = i;
        workers[i].listener = listener;
        pid = spawn_worker(&workers[i]);
        if (pid < 0) {
            return -1;
        }
        workers[i].pid = pid;
        ev_child_init(&workers[i].cwatcher, exit_cb, pid, 0);
        ev_child_start(loop, &workers[i].cwatcher);
    }

    return 0;
}
static guint
watch_child_full (MilterEventLoop *loop,
                  gint             priority,
                  GPid             pid,
                  GChildWatchFunc  function,
                  gpointer         data,
                  GDestroyNotify   notify)
{
    guint id;
    ev_child *watcher;
    ChildWatcherPrivate *watcher_priv;
    MilterLibevEventLoopPrivate *priv;

    priv = MILTER_LIBEV_EVENT_LOOP_GET_PRIVATE(loop);

    watcher_priv = g_new0(ChildWatcherPrivate, 1);
    watcher_priv->function = function;

    watcher = g_new0(ev_child, 1);
    watcher->data = watcher_priv;
    id = add_watcher(MILTER_LIBEV_EVENT_LOOP(loop),
                      (ev_watcher *)watcher,
                      WATCHER_STOP_FUNC(ev_child_stop),
                      NULL,
                      notify, data);

    ev_child_init(watcher, child_func, pid, FALSE);
    ev_child_start(priv->ev_loop, watcher);

    return id;
}
Beispiel #4
0
/**
 * Starts the child so it will be called by the specified event loop.
 *
 * Usage:
 *     child:start(loop [, is_daemon])
 *
 * [+0, -0, e]
 */
static int child_start(lua_State *L) {
    ev_child*       child = check_child(L, 1);
    struct ev_loop* loop = *check_loop_and_init(L, 2);
    int is_daemon        = lua_toboolean(L, 3);

    ev_child_start(loop, child);
    loop_start_watcher(L, loop, GET_WATCHER_DATA(child), 2, 1, is_daemon);

    return 0;
}
Beispiel #5
0
Datei: core.c Projekt: ifzz/lem
static int
signal_child_watch(lua_State *T)
{
	if (!signal_child_active()) {
		ev_child_start(LEM_ &signal_child_watcher);
		ev_unref(LEM); /* watcher shouldn't keep loop alive */
	}
	lua_pushboolean(T, 1);
	return 1;
}
Beispiel #6
0
void start_process(procnanny_t *pn, process_t *process) {
  program_t *program = pn_proc_program(process);
  program->state_cb = pn_proc_state_cb;
  pn_proc_start(process);
  ev_child *newwatcher = calloc(1, sizeof(ev_child));
  ev_child_init(newwatcher, child_proc_cb, pn_proc_pid(process), 0);
  ev_child_start(pn->loop, newwatcher);
  newwatcher->data = process;
  pn_proc_watch_io(pn->loop, process);
  //publish_proc_event(process, "starting");

  struct proc_data *procdata = process->data;
  procdata->running_state_timer = calloc(1, sizeof(ev_timer));
  procdata->running_state_timer->data = process;
  ev_timer_init(procdata->running_state_timer, running_state_timer_cb,
                program->minimum_run_duration, program->minimum_run_duration);
  ev_timer_start(pn->loop, procdata->running_state_timer);
} /* start_process */
Beispiel #7
0
static void spawn(child* c) {
	pid_t pid;

	if (c->tries++ > opts.retry) {
		g_printerr("Child[%i] died to often, not forking again\n", c->id);
		return;
	}

	switch (pid = fork()) {
	case -1:
		g_printerr("Fatal Error: Couldn't fork child[%i]: %s\n", c->id, g_strerror(errno));
		if (0 == c->d->running) {
			g_printerr("No child running and fork failed -> exit\n");
			c->d->return_status = -100;
			ev_unloop(c->d->loop, EVUNLOOP_ALL);
		}
		/* Do not retry... */
		break;
	case 0:
		/* child */

		/* Need to reset the signal mask; signal actions don't need to be reset
		 * according to libev documentation:
		 * http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#The_special_problem_of_inheritance_o
		 */
		{
			sigset_t set;
			sigemptyset(&set);
			sigprocmask(SIG_SETMASK, &set, NULL);
		}

		execv(opts.app[0], opts.app);
		g_printerr("Exec failed: %s\n", g_strerror(errno));
		exit(errno);
		break;
	default:
		c->pid = pid;
		c->d->running++;
		c->last_spawn = ev_now(c->d->loop);
		ev_child_set(&c->watcher, c->pid, 0);
		ev_child_start(c->d->loop, &c->watcher);
		break;
	}
}
Beispiel #8
0
void exit_cb(struct ev_loop* loop, struct ev_child* cwatcher, int status) {
    struct worker_s* worker = container_of(cwatcher, struct worker_s, cwatcher);
    ev_child_stop(loop, cwatcher);

    err("worker[pid:%d] exit with status:%d, stop_moniter:%d", worker->pid, cwatcher->rstatus, worker->listener->stop_moniter);

    struct timeval tv;
    gettimeofday(&tv, 0);

    if (worker->listener->stop_moniter || 2 > ((int)tv.tv_sec - worker->starttime)) {
        return;
    }

    worker->pid = spawn_worker(worker);
    if (-1 == worker->pid) {
        err("spawn worker failed, worker_id:%d", worker->worker_id);
        exit(EXIT_FAILURE);
    }

    err("worker %d restart, new pid: %d", worker->worker_id, worker->pid);

    ev_child_set(cwatcher, worker->pid, 0);
    ev_child_start(loop, cwatcher);
}
Beispiel #9
0
int main (void)
{
    // use the default event loop unless you have special needs
    struct ev_loop *loop = EV_DEFAULT; /* OR ev_default_loop(0) */

    pid_t pid = fork ();
    if (pid < 0) {            // error
        perror("fork()");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {    // child
        // the forked child executes here
        sleep(1);
        exit (EXIT_SUCCESS);
    } else {                  // parent
        ev_child_init (&cw, child_cb, pid, 0);
        ev_child_start (EV_DEFAULT_ &cw);
    }

    // now wait for events to arrive
    ev_run (loop, 0);

    // break was called, so exit
    return 0;
}
Beispiel #10
0
static void mon_interval_cb(struct ev_loop* loop, ev_timer* w, int revents V_UNUSED) {
    dmn_assert(loop); dmn_assert(w); dmn_assert(revents == EV_TIMER);

    mon_t* this_mon = w->data;
    dmn_assert(!this_mon->result_pending);

    this_mon->cmd_pid = fork();
    if(this_mon->cmd_pid == -1)
        log_fatal("fork() failed: %s", dmn_strerror(errno));

    if(!this_mon->cmd_pid) { // child
        // technically, we could go ahead and close off stdout/stderr
        //   here for the "startfg" case, but why bother?  If the user
        //   is debugging via startfg they might want to see this crap anyways.
        execv(this_mon->cmd->args[0], (char* const *)this_mon->cmd->args);
        log_fatal("execv(%s, ...) failed: %s", this_mon->cmd->args[0], dmn_strerror(errno));
    }

    this_mon->result_pending = true;
    ev_timer_set(this_mon->cmd_timeout, this_mon->cmd->timeout, 0);
    ev_timer_start(loop, this_mon->cmd_timeout);
    ev_child_set(this_mon->child_watcher, this_mon->cmd_pid, 0);
    ev_child_start(loop, this_mon->child_watcher);
}
Beispiel #11
0
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
    uv_process_options_t options) {
  /*
   * Save environ in the case that we get it clobbered
   * by the child process.
   */
  char** save_our_env = environ;
  int stdin_pipe[2] = { -1, -1 };
  int stdout_pipe[2] = { -1, -1 };
  int stderr_pipe[2] = { -1, -1 };
#if SPAWN_WAIT_EXEC
  int signal_pipe[2] = { -1, -1 };
  struct pollfd pfd;
#endif
  int status;
  pid_t pid;
  int flags;

  uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
  loop->counters.process_init++;

  process->exit_cb = options.exit_cb;

  if (options.stdin_stream &&
      uv__process_init_pipe(options.stdin_stream, stdin_pipe, 0)) {
    goto error;
  }

  if (options.stdout_stream &&
      uv__process_init_pipe(options.stdout_stream, stdout_pipe, 0)) {
    goto error;
  }

  if (options.stderr_stream &&
      uv__process_init_pipe(options.stderr_stream, stderr_pipe, 0)) {
    goto error;
  }

  /* This pipe is used by the parent to wait until
   * the child has called `execve()`. We need this
   * to avoid the following race condition:
   *
   *    if ((pid = fork()) > 0) {
   *      kill(pid, SIGTERM);
   *    }
   *    else if (pid == 0) {
   *      execve("/bin/cat", argp, envp);
   *    }
   *
   * The parent sends a signal immediately after forking.
   * Since the child may not have called `execve()` yet,
   * there is no telling what process receives the signal,
   * our fork or /bin/cat.
   *
   * To avoid ambiguity, we create a pipe with both ends
   * marked close-on-exec. Then, after the call to `fork()`,
   * the parent polls the read end until it sees POLLHUP.
   */
#if SPAWN_WAIT_EXEC
  if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK))
    goto error;
#endif

  pid = fork();

  if (pid == -1) {
#if SPAWN_WAIT_EXEC
    uv__close(signal_pipe[0]);
    uv__close(signal_pipe[1]);
#endif
    environ = save_our_env;
    goto error;
  }

  if (pid == 0) {
    if (stdin_pipe[0] >= 0) {
      uv__close(stdin_pipe[1]);
      dup2(stdin_pipe[0],  STDIN_FILENO);
    } else {
      /* Reset flags that might be set by Node */
      uv__cloexec(STDIN_FILENO, 0);
      uv__nonblock(STDIN_FILENO, 0);
    }

    if (stdout_pipe[1] >= 0) {
      uv__close(stdout_pipe[0]);
      dup2(stdout_pipe[1], STDOUT_FILENO);
    } else {
      /* Reset flags that might be set by Node */
      uv__cloexec(STDOUT_FILENO, 0);
      uv__nonblock(STDOUT_FILENO, 0);
    }

    if (stderr_pipe[1] >= 0) {
      uv__close(stderr_pipe[0]);
      dup2(stderr_pipe[1], STDERR_FILENO);
    } else {
      /* Reset flags that might be set by Node */
      uv__cloexec(STDERR_FILENO, 0);
      uv__nonblock(STDERR_FILENO, 0);
    }

    if (options.cwd && chdir(options.cwd)) {
      perror("chdir()");
      _exit(127);
    }

    environ = options.env;

    execvp(options.file, options.args);
    perror("execvp()");
    _exit(127);
    /* Execution never reaches here. */
  }

  /* Parent. */

  /* Restore environment. */
  environ = save_our_env;

#if SPAWN_WAIT_EXEC
  /* POLLHUP signals child has exited or execve()'d. */
  uv__close(signal_pipe[1]);
  do {
    pfd.fd = signal_pipe[0];
    pfd.events = POLLIN|POLLHUP;
    pfd.revents = 0;
    errno = 0, status = poll(&pfd, 1, -1);
  }
  while (status == -1 && (errno == EINTR || errno == ENOMEM));

  assert((status == 1) && "poll() on pipe read end failed");
  uv__close(signal_pipe[0]);
#endif

  process->pid = pid;

  ev_child_init(&process->child_watcher, uv__chld, pid, 0);
  ev_child_start(process->loop->ev, &process->child_watcher);
  process->child_watcher.data = process;

  if (stdin_pipe[1] >= 0) {
    assert(options.stdin_stream);
    assert(stdin_pipe[0] >= 0);
    uv__close(stdin_pipe[0]);
    uv__nonblock(stdin_pipe[1], 1);
    flags = UV_WRITABLE | (options.stdin_stream->ipc ? UV_READABLE : 0);
    uv__stream_open((uv_stream_t*)options.stdin_stream, stdin_pipe[1],
        flags);
  }

  if (stdout_pipe[0] >= 0) {
    assert(options.stdout_stream);
    assert(stdout_pipe[1] >= 0);
    uv__close(stdout_pipe[1]);
    uv__nonblock(stdout_pipe[0], 1);
    flags = UV_READABLE | (options.stdout_stream->ipc ? UV_WRITABLE : 0);
    uv__stream_open((uv_stream_t*)options.stdout_stream, stdout_pipe[0],
        flags);
  }

  if (stderr_pipe[0] >= 0) {
    assert(options.stderr_stream);
    assert(stderr_pipe[1] >= 0);
    uv__close(stderr_pipe[1]);
    uv__nonblock(stderr_pipe[0], 1);
    flags = UV_READABLE | (options.stderr_stream->ipc ? UV_WRITABLE : 0);
    uv__stream_open((uv_stream_t*)options.stderr_stream, stderr_pipe[0],
        flags);
  }

  return 0;

error:
  uv__set_sys_error(process->loop, errno);
  uv__close(stdin_pipe[0]);
  uv__close(stdin_pipe[1]);
  uv__close(stdout_pipe[0]);
  uv__close(stdout_pipe[1]);
  uv__close(stderr_pipe[0]);
  uv__close(stderr_pipe[1]);
  return -1;
}
Beispiel #12
0
int
main (int argc, char **argv)
{
  struct ev_loop *loop;
  struct timeval  tv[2];

  char  dirname[10];
  char *shmdata;
  int   rundir, rundirs[NUM_PROCS], sharedir;
  int   pagesize;
  int   i, j;

  // use the default event loop unless you have special needs
  loop = ev_default_loop (EVBACKEND_EPOLL); //EVFLAG_AUTO);
 
  rundir   = get_rundir();
  pagesize = getpagesize();
  
  // Prepare shared data directory
  if ((mkdirat(rundir, SHARE_DIR_NAME, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) != 0) {
    fprintf(stderr, "could not make share directory: %s\n", strerror(errno));
    return -1;
  }
  if ((sharedir = openat(rundir, SHARE_DIR_NAME, O_DIRECTORY)) < 0) {
    fprintf(stderr, "could not open share directory: %s\n", strerror(errno));
    return -1;
  }

  // Prepare worker rundirs
  for (i=0; i<NUM_PROCS; ++i) {
    sprintf(dirname, "%d", i);
    if ((mkdirat(rundir, dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) != 0) {
      fprintf(stderr, "worker %d: could not make runtime directory: %s\n", i, strerror(errno));
      return -1;
    }
    if ((rundirs[i] = openat(rundir, dirname, O_DIRECTORY)) < 0) {
      fprintf(stderr, "worker %d: could not open runtime directory: %s\n", i, strerror(errno));
      return -1;
    }

    if ((mkfifoat(rundirs[i], "inputfile", S_IRUSR | S_IWUSR)) != 0) {
      fprintf(stderr, "%s: could not create FIFO: %s\n", "inputfile", strerror(errno));
    }
  }

  // Memory map some data;
  for (j=0; j<NUM_SHMS; ++j) {
    // Maybe just use ids for shared SHM names
    shms[j] = openat(sharedir, "dbfile", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    ftruncate(shms[j], pagesize);
    shmdata = mmap((caddr_t)0, pagesize, PROT_WRITE, MAP_SHARED, shms[j], 0);
    strcpy(shmdata, "Very important DB data.");
    
    // Now "share" it
    for (i=0; i<NUM_PROCS; ++i) {
      linkat(sharedir, "dbfile", rundirs[i], "dbfile", 0);
    }
  }

  //ev_set_timeout_collect_interval (loop, 0.0001);
  //ev_set_io_collect_interval (loop, 0.0001);

  // Start children
  for (i=0; i<NUM_PROCS; ++i) {
    pid_t pid = fork();
    if (pid == 0) {
      // Child
      fchdir(rundirs[i]);
      if (execle(argv[1], gnu_basename(argv[1]), "outputfile", "dbfile", "inputfile", NULL, NULL)) {
	fputs("Could not exec: ", stderr);
	fputs(strerror(errno), stderr);
	fputc('\n', stderr);
	exit(EXIT_FAILURE);
      }
    }
    else if (pid > 0) {
      // Parent
    }
  }

  // Initialize watchers
  for (i=0; i<NUM_PROCS; ++i) {
    ev_io *wio = &input_watcher[i];

    fifos[i] = openat(rundirs[i], "inputfile", O_WRONLY);
    wio->data = (void*)i;
    ev_io_init(wio, input_cb, fifos[i], EV_WRITE);
    ev_io_start(loop, wio);
  }
  
  ev_child *wchld = &child_watcher;
  ev_child_init(wchld, child_cb, 0, 1);
  ev_child_start(loop, wchld);

  // now wait for events to arrive
  gettimeofday(tv+0, NULL);
  ev_loop (loop, 0);
  gettimeofday(tv+1, NULL);
  
  // unloop was called, so exit
  long t = (tv[1].tv_sec - tv[0].tv_sec) * 1000000
           + (tv[1].tv_usec - tv[0].tv_usec);

  printf("\nTime taken: %lfs (%lfms average)\n\n",
      ((double)t) / 1000000.0,
      ((double)t) * NUM_PROCS / NUM_JOBS);

  // Hang up
  /*
  puts("Closing pipes...");
  for (i=0; i<NUM_PROCS; ++i) {
    close(fifos[i]);
  }
  */

  puts("Waiting for children processes to terminate...");
  pid_t pid;
  do {
    pid = wait(NULL);
    if(pid == -1 && errno != ECHILD) {
      perror("Error during wait()");
      abort();
    }
  } while (pid > 0);

  // Cleanup shms
  puts("Cleaning SHMs...");
  for (j=0; j<NUM_SHMS; ++j) {
    ftruncate(shms[j], 0);
    close(shms[i]);
  }

  // Finally...
  puts("Done.");
  return 0;
}
Beispiel #13
0
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
    uv_process_options_t options) {
  /*
   * Save environ in the case that we get it clobbered
   * by the child process.
   */
  char** save_our_env = environ;

  int* pipes = malloc(2 * options.stdio_count * sizeof(int));

#if SPAWN_WAIT_EXEC
  int signal_pipe[2] = { -1, -1 };
  struct pollfd pfd;
#endif
  int status;
  pid_t pid;
  int i;

  if (pipes == NULL) {
    errno = ENOMEM;
    goto error;
  }

  assert(options.file != NULL);
  assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
                             UV_PROCESS_DETACHED |
                             UV_PROCESS_SETGID |
                             UV_PROCESS_SETUID)));


  uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
  loop->counters.process_init++;
  uv__handle_start(process);

  process->exit_cb = options.exit_cb;

  /* Init pipe pairs */
  for (i = 0; i < options.stdio_count; i++) {
    pipes[i * 2] = -1;
    pipes[i * 2 + 1] = -1;
  }

  /* Create socketpairs/pipes, or use raw fd */
  for (i = 0; i < options.stdio_count; i++) {
    if (uv__process_init_stdio(&options.stdio[i], pipes + i * 2, i != 0)) {
      goto error;
    }
  }

  /* This pipe is used by the parent to wait until
   * the child has called `execve()`. We need this
   * to avoid the following race condition:
   *
   *    if ((pid = fork()) > 0) {
   *      kill(pid, SIGTERM);
   *    }
   *    else if (pid == 0) {
   *      execve("/bin/cat", argp, envp);
   *    }
   *
   * The parent sends a signal immediately after forking.
   * Since the child may not have called `execve()` yet,
   * there is no telling what process receives the signal,
   * our fork or /bin/cat.
   *
   * To avoid ambiguity, we create a pipe with both ends
   * marked close-on-exec. Then, after the call to `fork()`,
   * the parent polls the read end until it sees POLLHUP.
   */
#if SPAWN_WAIT_EXEC
  if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK))
    goto error;
#endif

  pid = fork();

  if (pid == -1) {
#if SPAWN_WAIT_EXEC
    close(signal_pipe[0]);
    close(signal_pipe[1]);
#endif
    environ = save_our_env;
    goto error;
  }

  if (pid == 0) {
    /* Child */
    if (options.flags & UV_PROCESS_DETACHED) {
      setsid();
    }

    /* Dup fds */
    for (i = 0; i < options.stdio_count; i++) {
      /*
       * stdin has swapped ends of pipe
       * (it's the only one readable stream)
       */
      int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2];
      int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1];

      if (use_fd >= 0) {
        close(close_fd);
        dup2(use_fd, i);
      } else {
        /* Reset flags that might be set by Node */
        uv__cloexec(i, 0);
        uv__nonblock(i, 0);
      }
    }

    if (options.cwd && chdir(options.cwd)) {
      perror("chdir()");
      _exit(127);
    }

    if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
      perror("setgid()");
      _exit(127);
    }

    if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
      perror("setuid()");
      _exit(127);
    }

    environ = options.env;

    execvp(options.file, options.args);
    perror("execvp()");
    _exit(127);
    /* Execution never reaches here. */
  }

  /* Parent. */

  /* Restore environment. */
  environ = save_our_env;

#if SPAWN_WAIT_EXEC
  /* POLLHUP signals child has exited or execve()'d. */
  close(signal_pipe[1]);
  do {
    pfd.fd = signal_pipe[0];
    pfd.events = POLLIN|POLLHUP;
    pfd.revents = 0;
    errno = 0, status = poll(&pfd, 1, -1);
  }
  while (status == -1 && (errno == EINTR || errno == ENOMEM));

  assert((status == 1) && "poll() on pipe read end failed");
  close(signal_pipe[0]);
#endif

  process->pid = pid;

  ev_child_init(&process->child_watcher, uv__chld, pid, 0);
  ev_child_start(process->loop->ev, &process->child_watcher);
  process->child_watcher.data = process;

  for (i = 0; i < options.stdio_count; i++) {
    if (uv__process_open_stream(&options.stdio[i], pipes + i * 2, i == 0)) {
      int j;
      /* Close all opened streams */
      for (j = 0; j < i; j++) {
        uv__process_close_stream(&options.stdio[j]);
      }

      goto error;
    }
  }

  free(pipes);

  return 0;

error:
  uv__set_sys_error(process->loop, errno);

  for (i = 0; i < options.stdio_count; i++) {
    close(pipes[i * 2]);
    close(pipes[i * 2 + 1]);
  }

  free(pipes);

  return -1;
}
Beispiel #14
0
int main(int argc, char *argv[]) {
    static struct option long_options[] = {
        {"getmonitors_reply", required_argument, 0, 0},
        {0, 0, 0, 0},
    };
    char *options_string = "";
    int opt;
    int option_index = 0;

    while ((opt = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
        switch (opt) {
            case 0:
                if (strcmp(long_options[option_index].name, "getmonitors_reply") == 0) {
                    must_read_reply(optarg);
                }
                break;
            default:
                exit(EXIT_FAILURE);
        }
    }

    if (optind >= argc) {
        errx(EXIT_FAILURE, "syntax: %s [options] <command>\n", argv[0]);
    }

    int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (fd == -1) {
        err(EXIT_FAILURE, "socket(AF_UNIX)");
    }

    if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
        warn("Could not set FD_CLOEXEC");
    }

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = AF_UNIX;
    int i;
    bool bound = false;
    for (i = 0; i < 100; i++) {
        /* XXX: The path to X11 sockets differs on some platforms (e.g. Trusted
         * Solaris, HPUX), but since libxcb doesn’t provide a function to
         * generate the path, we’ll just have to hard-code it for now. */
        snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/.X11-unix/X%d", i);

        if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {
            warn("bind(%s)", addr.sun_path);
        } else {
            bound = true;
            /* Let the user know bind() was successful, so that they know the
             * error messages can be disregarded. */
            fprintf(stderr, "Successfuly bound to %s\n", addr.sun_path);
            sun_path = sstrdup(addr.sun_path);
            break;
        }
    }

    if (!bound) {
        err(EXIT_FAILURE, "bind()");
    }

    atexit(cleanup_socket);

    /* This program will be started for each testcase which requires it, so we
     * expect precisely one connection. */
    if (listen(fd, 1) == -1) {
        err(EXIT_FAILURE, "listen()");
    }

    pid_t child = fork();
    if (child == -1) {
        err(EXIT_FAILURE, "fork()");
    }
    if (child == 0) {
        char *display;
        sasprintf(&display, ":%d", i);
        setenv("DISPLAY", display, 1);
        free(display);

        char **child_args = argv + optind;
        execvp(child_args[0], child_args);
        err(EXIT_FAILURE, "exec()");
    }

    struct ev_loop *loop = ev_default_loop(0);

    ev_child cw;
    ev_child_init(&cw, child_cb, child, 0);
    ev_child_start(loop, &cw);

    ev_io watcher;
    ev_io_init(&watcher, uds_connection_cb, fd, EV_READ);
    ev_io_start(loop, &watcher);

    ev_run(loop, 0);
}
Beispiel #15
0
static void child_start (void *impl, flux_watcher_t *w)
{
    assert (w->signature == CHILD_SIG);
    ev_child_start (w->r->loop, (ev_child *)impl);
}
Beispiel #16
0
/**
 * Adds the event to the event loop.
 * 
 * This method will increase the refcount on the supplied Event, protecting it
 * from garbage collection. Refcount will be decreased on remove or if the
 * EventLoop object is GCd.
 * 
 * @param  Event
 * @return boolean
 */
PHP_METHOD(EventLoop, add)
{
	zval *zevent;
	event_object *event;
	event_loop_object *loop_obj = (event_loop_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
	
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zevent, event_ce) != SUCCESS) {
		return;
	}
	
	event = (event_object *)zend_object_store_get_object(zevent TSRMLS_CC);
	
	assert(loop_obj->loop);
	
	/* Check so the event is not associated with any EventLoop, also needs to check
	   for active, no need to perform logic if it already is started */
	if(loop_obj->loop && ! event_is_active(event))
	{
		if(event_has_loop(event))
		{
			if( ! event_in_loop(loop_obj, event))
			{
				/* Attempting to add a fed event to this EventLoop which
				   has been fed to another loop */
				IF_DEBUG(libev_printf("Attempting to add() an event already associated with another EventLoop\n"));
				RETURN_BOOL(0);
			}
		}
		
		EVENT_WATCHER_ACTION(event, loop_obj, start, io)
		else EVENT_WATCHER_ACTION(event, loop_obj, start, timer)
		else EVENT_WATCHER_ACTION(event, loop_obj, start, periodic)
		else EVENT_WATCHER_ACTION(event, loop_obj, start, signal)
		else if(instance_of_class(event->std.ce, child_event_ce))
		{
			/* Special logic, ev_child can only be attached to the default loop */
			if( ! ev_is_default_loop(loop_obj->loop))
			{
				/* TODO: libev-specific exception class here */
				zend_throw_exception(NULL, "libev\\ChildEvent can only be added to the default event-loop", 1 TSRMLS_DC);
				
				return;
			}
			
			ev_child_start(loop_obj->loop, (ev_child *)event->watcher);
			IF_DEBUG(libev_printf("Calling ev_child_start\n"));
		}
		else EVENT_WATCHER_ACTION(event, loop_obj, start, stat)
		else EVENT_WATCHER_ACTION(event, loop_obj, start, idle)
		else EVENT_WATCHER_ACTION(event, loop_obj, start, async)
		else EVENT_WATCHER_ACTION(event, loop_obj, start, cleanup)
		
		if( ! event_has_loop(event))
		{
			/* GC protection */
			EVENT_LOOP_REF_ADD(event, loop_obj);
		}
		
		RETURN_BOOL(1);
	}
	
	RETURN_BOOL(0);
}
Beispiel #17
0
static void mon_interval_cb(struct ev_loop* loop, ev_timer* w, int revents V_UNUSED) {
    dmn_assert(loop); dmn_assert(w); dmn_assert(revents == EV_TIMER);

    mon_t* this_mon = w->data;
    dmn_assert(!this_mon->result_pending);

    if (this_mon->cmd->max_proc > 0 && num_proc >= this_mon->cmd->max_proc) {
        // If more than max_proc processes are running, reschedule excess
        //   checks to run 0.1 seconds later. After a few passes, this will
        //   smooth the schedule out to prevent a thundering herd.
        ev_timer_stop(loop, this_mon->interval_timer);
        ev_timer_set(this_mon->interval_timer, 0.1, this_mon->cmd->interval);
        ev_timer_start(loop, this_mon->interval_timer);
        return;
    }

    // Before forking, block all signals and save the old mask
    //   to avoid a race condition where local sighandlers execute
    //   in the child between fork and exec().
    sigset_t all_sigs;
    sigfillset(&all_sigs);
    sigset_t saved_mask;
    sigemptyset(&saved_mask);
    if(pthread_sigmask(SIG_SETMASK, &all_sigs, &saved_mask))
        log_fatal("pthread_sigmask() failed");

    this_mon->cmd_pid = fork();
    if(this_mon->cmd_pid == -1)
        log_fatal("fork() failed: %s", dmn_logf_strerror(errno));

    if(!this_mon->cmd_pid) { // child
        // reset all signal handlers to default before unblocking
        struct sigaction defaultme;
        sigemptyset(&defaultme.sa_mask);
        defaultme.sa_handler = SIG_DFL;
        defaultme.sa_flags = 0;

        // we really don't care about error retvals here
        for(int i = 0; i < NSIG; i++)
            (void)sigaction(i, &defaultme, NULL);

        // unblock all
        sigset_t no_sigs;
        sigemptyset(&no_sigs);
        if(pthread_sigmask(SIG_SETMASK, &no_sigs, NULL))
            log_fatal("pthread_sigmask() failed");

        // technically, we could go ahead and close off stdout/stderr
        //   here for the "startfg" case, but why bother?  If the user
        //   is debugging via startfg they might want to see this crap anyways.
        execv(this_mon->cmd->args[0], this_mon->cmd->args);
        log_fatal("execv(%s, ...) failed: %s", this_mon->cmd->args[0], dmn_logf_strerror(errno));
    }
    num_proc++;

    // restore previous signal mask from before fork in parent
    if(pthread_sigmask(SIG_SETMASK, &saved_mask, NULL))
        log_fatal("pthread_sigmask() failed");

    this_mon->result_pending = true;
    ev_timer_set(this_mon->cmd_timeout, this_mon->cmd->timeout, 0);
    ev_timer_start(loop, this_mon->cmd_timeout);
    ev_child_set(this_mon->child_watcher, this_mon->cmd_pid, 0);
    ev_child_start(loop, this_mon->child_watcher);
}
Beispiel #18
0
// Handle input from an HTTP socket.
void process_http_cb(socket_t *socket)
{
	int used;
	
	connection_t *ptr = ilist_fetch(connections, socket->fd);
	if (ptr == NULL) {
		printf("%d: Tried to get from list, but got NULL.\n", socket->fd);
		return;
	}

	if (ptr->is_websocket) {
		// Try to decode a frame.
		frame_t *f = read_frame(socket->rbuf, socket->rbuf_len, &used);
		if (f == NULL) {
			return;
		}

		// TODO: Consume instead.
		bcopy(socket->rbuf, socket->rbuf + used, socket->rbuf_len - used);
		socket->rbuf_len -= used;
		
		char *p = malloc(f->len + 1);
		strncpy(p, f->payload, f->len);
		p[f->len] = 0;
		
		cmd_t *cmd = parse_msg(p);
		if (cmd != NULL && cmd->type == CMD_EXECUTE) {
			process_t *p = execute_cmd((cmd_execute_t *)cmd);

			ilist_insert(processes, p);


			sock_pid_t *sp = malloc(sizeof(sock_pid_t));
			sp->socket = socket;
			sp->pid = p;

			// Write new_process message?
			char format[] = 
			    "{\"newProcess\" : {"
			        "\"pid\" : %d, \"command\" : \"%s\","
			        "\"startTime\" : %ld,"
			        "\"requestId\" : %d}}";
			char str[1000];

			struct timeval tp;
			gettimeofday(&tp, NULL);
			long int time = tp.tv_sec * 1000 + tp.tv_usec;
			
			sprintf(str, format, p->pid, ((cmd_execute_t*)cmd)->command_str, time, ((cmd_execute_t*)cmd)->request_id);

			frame_t *frame = malloc(sizeof(frame_t *));
			frame->fin = 1;
			frame->len = strlen(str);
			frame->opcode = WS_OP_BIN;
			frame->payload = str;

			int fr_len;
			char *fr_str = write_frame(frame, &fr_len);

			socket_write(socket, fr_str, fr_len);

			socket_new(p->out, &process_child_out_cb, sp, socket);

			ev_child *child_watcher = (struct ev_child*) malloc (sizeof(struct ev_child));
			ev_child_init (child_watcher, child_cb, p->pid, 1);
			child_watcher->data = socket;
			ev_child_start(loop, child_watcher);
		}
	
		free(f->payload);
		free(f);
		free(p);
		return;
	}
	

	request_t *req = parse_request(socket->rbuf, socket->rbuf_len, &used);
	if (req) {
		printf("%d: New Request: %s %s\n", socket->fd, req->method, req->uri);

		// Take it out of the read buffer.
		// TODO: Consume
		bcopy(socket->rbuf, socket->rbuf + used, socket->rbuf_len - used);
		socket->rbuf_len -= used;

		// Got a request!


		int upgraded = try_upgrade(req, ptr);
		if (upgraded) {
			printf("%d: Upgraded to WebSocket!\n", socket->fd);
		} else if (!strcmp(req->uri, "/")) {
			serve_file(socket, "static/index.html");
		} else if (!strcmp(req->uri, "/tnrl.js")) {
			serve_file(socket, "static/tnrl.js");
		} else if (!strcmp(req->uri, "/tnrl.css")) {
			serve_file(socket, "static/tnrl.css");
		} else if (!strcmp(req->uri, "/favicon.ico")) {
			serve_file(socket, "static/favicon.ico");
		} else {
			// Unknown URL?
			char *str = "HTTP/1.1 404 Not Found\r\n\r\n";
			socket_write(socket, str, strlen(str));
		}

		request_delete(req);
		
	}
	//printf("%s", buf);
}
Beispiel #19
0
struct worker *
worker_start(EV_P_ struct session *session)
{
    struct worker *w;
    pid_t pid;
    int stdin_fds [2] = {-1, -1};
    int stdout_fds[2] = {-1, -1};
    int stderr_fds[2] = {-1, -1};
    int msgin_fds [2] = {-1, -1};
    int msgout_fds[2] = {-1, -1};

#if WORKER_TIMINGS
    uint64_t _start = now_us();
#endif

    if ((w = calloc(1, sizeof(*w))) == NULL) {
        goto fail;
    }
    w->session = session;
    writeq_init(&w->stdin_writeq);
    writeq_init(&w->msgin_writeq);

    if (pipe(stdin_fds ) < 0 ||
        pipe(stdout_fds) < 0 ||
        pipe(stderr_fds) < 0 ||
        pipe(msgin_fds ) < 0 ||
        pipe(msgout_fds) < 0) {
        LOG_ERRNO("pipe()");
        goto fail;
    }
    maxfd_update(stdin_fds [0]);
    maxfd_update(stdin_fds [1]);
    maxfd_update(stdout_fds[0]);
    maxfd_update(stdout_fds[1]);
    maxfd_update(stderr_fds[0]);
    maxfd_update(stderr_fds[1]);
    maxfd_update(msgin_fds [0]);
    maxfd_update(msgin_fds [1]);
    maxfd_update(msgout_fds[0]);
    maxfd_update(msgout_fds[1]);


    pid = fork();
    if (pid < 0) {
        LOG_ERRNO("fork()");
        goto fail;
    }
    if (pid == 0) {
        /* child. */
        if (dup2(stdin_fds [0], 0) < 0 ||
            dup2(stdout_fds[1], 1) < 0 ||
            dup2(stderr_fds[1], 2) < 0 ||
            dup2(msgin_fds [0], 3) < 0 ||
            dup2(msgout_fds[1], 4) < 0) {
            exit(EXIT_FAILURE);
        }
        maxfd_closeall(5);
        pyenv_child_after_fork();
        exit(EXIT_SUCCESS);
    } else {
        /* parent. */
        close(stdin_fds [0]);
        close(stdout_fds[1]);
        close(stderr_fds[1]);
        close(msgin_fds [0]);
        close(msgout_fds[1]);

        set_fd_nonblocking(stdin_fds [1]);
        set_fd_nonblocking(stdout_fds[0]);
        set_fd_nonblocking(stderr_fds[0]);
        set_fd_nonblocking(msgin_fds [1]);
        set_fd_nonblocking(msgout_fds[0]);

        ev_child_init(&w->child_watcher, worker_exited_cb, pid, 0);
        ev_child_start(EV_A_ &w->child_watcher);

        ev_io_init(&w->stdin_w , worker_write_stdin_cb, stdin_fds [1],
                   EV_WRITE);
        ev_io_init(&w->stdout_w, worker_read_stdout_cb, stdout_fds[0],
                   EV_READ);
        ev_io_init(&w->stderr_w, worker_read_stderr_cb, stderr_fds[0],
                   EV_READ);
        ev_io_init(&w->msgin_w , worker_write_msgin_cb, msgin_fds [1],
                   EV_WRITE);
        ev_io_init(&w->msgout_w, worker_read_msgout_cb, msgout_fds[0],
                   EV_READ);
        ev_io_start(EV_A_ &w->stdout_w);
        ev_io_start(EV_A_ &w->stderr_w);
        ev_io_start(EV_A_ &w->msgout_w);

        LOGF(3, "=== %d: worker started, fds=[%d, %d, %d, %d, %d]\n",
             worker_pid(w), stdin_fds[1], stdout_fds[0], stderr_fds[0],
             msgin_fds[1], msgout_fds[0]);

        w->f_alive = true;
    }
#if WORKER_TIMINGS
    worker_start_time += now_us() - _start;
    worker_start_calls++;
#endif

    return w;

 fail:
    close(stdin_fds [0]);
    close(stdin_fds [1]);
    close(stdout_fds[0]);
    close(stdout_fds[1]);
    close(stderr_fds[0]);
    close(stderr_fds[1]);
    close(msgin_fds [0]);
    close(msgin_fds [1]);
    close(msgout_fds[0]);
    close(msgout_fds[1]);
    free(w);
    return NULL;
}
Beispiel #20
0
void feng_start_child_watcher(struct feng  *srv)
{
    cw.data = srv;
    ev_child_init (&cw, child_terminate_cb, 0, 0);
    ev_child_start (srv->loop, &cw);    
}