static int _set_signals(void) { struct sigaction sa = { .sa_handler = signal_handler, .sa_flags = 0 }; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGCHLD); if (0 > sigprocmask(SIG_BLOCK, &sigset, NULL)) return LOGGER_PERROR("sigprocmask"), -1; sigfd = signalfd(-1, &sigset, SFD_NONBLOCK | SFD_CLOEXEC); if (0 > sigfd) return LOGGER_PERROR("signalfd"), -1; if (NULL == (sigfd_ctx = ribs_context_create(SIG_CHLD_STACK_SIZE, 0, _handle_sig_child))) return -1; return 0; } static int _init_subprocesses(const char *pidfilename, int num_forks) { if (0 >= num_forks) { num_forks = sysconf(_SC_NPROCESSORS_CONF); if (0 > num_forks) exit(EXIT_FAILURE); } LOGGER_INFO("num forks = %d", num_forks); num_instances = num_forks; daemon_instance = 0; children_pids = calloc(num_forks - 1, sizeof(pid_t)); int i; for (i = 1; i < num_forks; ++i) { LOGGER_INFO("starting sub-process %d", i); pid_t pid = fork(); if (0 > pid) return LOGGER_PERROR("fork"), -1; if (0 == pid) { daemon_instance = i; if (0 > prctl(PR_SET_PDEATHSIG, SIGTERM)) return LOGGER_PERROR("prctl"), -1; if (0 > _set_signals()) return LOGGER_ERROR("failed to set signals"), -1; LOGGER_INFO("sub-process %d started", i); return 0; } else children_pids[i-1] = pid; } if (pidfilename && 0 > _set_pidfile(pidfilename)) return LOGGER_ERROR("failed to set pidfile"), -1; if (0 > _set_signals()) return LOGGER_ERROR("failed to set signals"), -1; return 0; } static int ribs_server_init_daemon(const char *pidfilename, const char *logfilename, int num_forks) { if (0 > pipe2(child_is_up_pipe, O_CLOEXEC)) return LOGGER_ERROR("failed to create pipe"), -1; pid_t pid = fork(); if (pid < 0) return LOGGER_PERROR("ribs_server_init_daemon, fork"), -1; if (pid > 0) { close(child_is_up_pipe[1]); /* close the write side */ /* wait for child to come up */ uint8_t t; int res; LOGGER_INFO("waiting for the child process [%d] to start...", pid); if (0 >= (res = read(child_is_up_pipe[0], &t, sizeof(t)))) { if (0 > res) LOGGER_PERROR("pipe"); LOGGER_ERROR("child process failed to start"); return -1; } LOGGER_INFO("child process started successfully"); exit(EXIT_SUCCESS); } close(child_is_up_pipe[0]); /* close the read side */ umask(0); if (0 > setsid()) return LOGGER_PERROR("daemonize, setsid"), -1; int fdnull = open("/dev/null", O_RDWR); if (0 > fdnull) return LOGGER_PERROR("/dev/null"), -1; dup2(fdnull, STDIN_FILENO); if (logfilename) { if (0 > _logger_init(logfilename)) return -1; } else { dup2(fdnull, STDOUT_FILENO); dup2(fdnull, STDERR_FILENO); } close(fdnull); LOGGER_INFO("child process started"); return _init_subprocesses(pidfilename, num_forks); } int ribs_server_init(int daemonize, const char *pidfilename, const char *logfilename, int num_forks) { if (0 > hashtable_init(&ht_pid_to_ctx, 0)) return -1; if (daemonize) return ribs_server_init_daemon(pidfilename, logfilename, num_forks); /* if (logfilename && 0 > _logger_init(logfilename)) */ /* exit(EXIT_FAILURE); */ return _init_subprocesses(pidfilename, num_forks); } int ribs_server_signal_children(int sig) { if (0 >= num_instances || 0 != daemon_instance) return 0; int i, res = 0; for (i = 0; i < num_instances-1; ++i) { if (0 < children_pids[i] && 0 > kill(children_pids[i], sig)) { LOGGER_PERROR("kill [%d] %d", sig, children_pids[i]); res = -1; } } return res; } void ribs_server_start(void) { daemon_finalize(); if (0 <= sigfd && 0 > ribs_epoll_add(sigfd, EPOLLIN, sigfd_ctx)) return LOGGER_ERROR("ribs_epoll_add: sigfd"); epoll_worker_loop(); if (0 >= num_instances || 0 != daemon_instance) return; LOGGER_INFO("sending SIGTERM to sub-processes"); ribs_server_signal_children(SIGTERM); LOGGER_INFO("waiting for sub-processes to exit"); int i, status; for (i = 0; i < num_instances-1; ++i) { if (0 < children_pids[i] && 0 > waitpid(children_pids[i], &status, 0)) LOGGER_PERROR("waitpid %d", children_pids[i]); } LOGGER_INFO("sub-processes terminated"); }
static int _set_signals(void) { struct sigaction sa = { .sa_handler = signal_handler, .sa_flags = 0 }; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); if (0 == daemon_instance) sigaction(SIGCHLD, &sa, NULL); return 0; } static int _init_subprocesses(const char *pidfilename, int num_forks) { if (0 >= num_forks) { num_forks = sysconf(_SC_NPROCESSORS_CONF); if (0 > num_forks) exit(EXIT_FAILURE); } LOGGER_INFO("num forks = %d", num_forks); num_instances = num_forks; daemon_instance = 0; children_pids = calloc(num_forks - 1, sizeof(pid_t)); int i; for (i = 1; i < num_forks; ++i) { LOGGER_INFO("starting sub-process %d", i); pid_t pid = fork(); if (0 > pid) return LOGGER_PERROR("fork"), -1; if (0 == pid) { daemon_instance = i; if (0 > prctl(PR_SET_PDEATHSIG, SIGTERM)) return LOGGER_PERROR("prctl"), -1; if (0 > _set_signals()) return LOGGER_ERROR("failed to set signals"), -1; LOGGER_INFO("sub-process %d started", i); return 0; } else children_pids[i-1] = pid; } if (pidfilename && 0 > _set_pidfile(pidfilename)) return LOGGER_ERROR("failed to set pidfile"), -1; if (0 > _set_signals()) return LOGGER_ERROR("failed to set signals"), -1; return 0; } static int ribs_server_init_daemon(const char *pidfilename, const char *logfilename, int num_forks) { if (0 > pipe(child_is_up_pipe)) return LOGGER_ERROR("failed to create pipe"), -1; pid_t pid = fork(); if (pid < 0) return LOGGER_PERROR("ribs_server_init_daemon, fork"), -1; if (pid > 0) { close(child_is_up_pipe[1]); /* close the write side */ /* wait for child to come up */ uint8_t t; int res; LOGGER_INFO("waiting for the child process [%d] to start...", pid); if (0 >= (res = read(child_is_up_pipe[0], &t, sizeof(t)))) { if (0 > res) LOGGER_PERROR("pipe"); LOGGER_ERROR("child process failed to start"); return -1; } LOGGER_INFO("child process started successfully"); exit(EXIT_SUCCESS); } close(child_is_up_pipe[0]); /* close the read side */ umask(0); if (0 > setsid()) return LOGGER_PERROR("daemonize, setsid"), -1; int fdnull = open("/dev/null", O_RDWR); if (0 > fdnull) return LOGGER_PERROR("/dev/null"), -1; dup2(fdnull, STDIN_FILENO); if (logfilename) { if (0 > _logger_init(logfilename)) return -1; } else { dup2(fdnull, STDOUT_FILENO); dup2(fdnull, STDERR_FILENO); } close(fdnull); LOGGER_INFO("child process started"); return _init_subprocesses(pidfilename, num_forks); } int ribs_server_init(int daemonize, const char *pidfilename, const char *logfilename, int num_forks) { if (daemonize) return ribs_server_init_daemon(pidfilename, logfilename, num_forks); /* if (logfilename && 0 > _logger_init(logfilename)) */ /* exit(EXIT_FAILURE); */ return _init_subprocesses(pidfilename, num_forks); } int ribs_server_signal_children(int sig) { if (0 >= num_instances || 0 != daemon_instance) return 0; int i, res = 0; for (i = 0; i < num_instances-1; ++i) { if (0 > kill(children_pids[i], sig)) { LOGGER_PERROR("kill [%d] %d", sig, children_pids[i]); res = -1; } } return res; } void ribs_server_start(void) { daemon_finalize(); epoll_worker_loop(); if (0 >= num_instances || 0 != daemon_instance) return; struct sigaction sa = { .sa_handler = SIG_DFL, .sa_flags = 0 }; sigaction(SIGCHLD, &sa, NULL); LOGGER_INFO("sending SIGTERM to sub-processes"); ribs_server_signal_children(SIGTERM); LOGGER_INFO("waiting for sub-processes to exit"); int i, status; for (i = 0; i < num_instances-1; ++i) { if (0 > waitpid(children_pids[i], &status, 0)) LOGGER_PERROR("waitpid %d", children_pids[i]); } LOGGER_INFO("sub-processes terminated"); } int ribs_get_daemon_instance(void) { return daemon_instance; } int daemonize(void) { if (0 > pipe(child_is_up_pipe)) return LOGGER_ERROR("failed to create pipe"), -1; pid_t pid = fork(); if (pid < 0) { LOGGER_PERROR("daemonize, fork"); exit(EXIT_FAILURE); } if (pid > 0) { close(child_is_up_pipe[1]); /* close the write side */ /* wait for child to come up */ uint8_t t; int res; LOGGER_INFO("waiting for the child process [%d] to start...", pid); if (0 >= (res = read(child_is_up_pipe[0], &t, sizeof(t)))) { if (0 > res) LOGGER_PERROR("pipe"); LOGGER_ERROR("child process failed to start"); exit(EXIT_FAILURE); } LOGGER_INFO("child process started successfully"); exit(EXIT_SUCCESS); } close(child_is_up_pipe[0]); /* close the read side */ umask(0); if (0 > setsid()) { LOGGER_PERROR("daemonize, setsid"); exit(EXIT_FAILURE); } int fdnull = open("/dev/null", O_RDWR); dup2(fdnull, STDIN_FILENO); dup2(fdnull, STDOUT_FILENO); dup2(fdnull, STDERR_FILENO); close(fdnull); pid = getpid(); LOGGER_INFO("child process started (pid=%d)", pid); return 0; } void daemon_finalize(void) { if (daemon_instance > 0) return; if (0 > child_is_up_pipe[1]) return; uint8_t t = 0; if (0 > write(child_is_up_pipe[1], &t, sizeof(t))) { LOGGER_PERROR("pipe"); exit(EXIT_FAILURE); } close(child_is_up_pipe[1]); } int ribs_logger_init(const char *filename) { return _logger_init(filename); } int ribs_set_signals(void) { return _set_signals(); } int ribs_set_pidfile(const char *filename) { if (0 > _set_pidfile(filename)) return -1; return _set_signals(); }