Пример #1
0
void li_event_child_init(liEventLoop *loop, liEventChild *child, liEventCallback callback, int pid) {
	memset(child, 0, sizeof(*child));
	child->base.type = LI_EVT_CHILD;
	child->base.keep_loop_alive = 1;
	child->base.callback = callback;
	ev_init(&child->libevmess.w, NULL);
	ev_child_set(&child->libevmess.child, pid, 0);
	ev_set_cb(&child->libevmess.child, event_child_cb);

	if (NULL != loop) li_event_attach(loop, child);
	li_event_start(child);
}
Пример #2
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;
	}
}
Пример #3
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);
}
Пример #4
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);
}
Пример #5
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);
}