- PARA_NOTICE_LOG("setting up signal handlers\n");
- if (para_install_sighandler(SIGINT) < 0)
- goto err;
- if (para_install_sighandler(SIGTERM) < 0)
- goto err;
- if (para_install_sighandler(SIGHUP) < 0)
- goto err;
- if (para_install_sighandler(SIGCHLD) < 0)
- goto err;
- if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
- goto err;
- if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)
- goto err;
- add_close_on_fork_list(signal_pipe);
- return;
-err:
- PARA_EMERG_LOG("could not install signal handlers\n");
- exit(EXIT_FAILURE);
+static int signal_post_select(struct sched *s, __a_unused void *context)
+{
+ int signum = para_next_signal(&s->rfds);
+
+ switch (signum) {
+ case 0:
+ return 0;
+ case SIGHUP:
+ handle_sighup();
+ break;
+ case SIGCHLD:
+ for (;;) {
+ pid_t pid;
+ int ret = para_reap_child(&pid);
+ if (ret <= 0)
+ break;
+ if (pid != mmd->afs_pid)
+ continue;
+ PARA_EMERG_LOG("fatal: afs died\n");
+ kill(0, SIGTERM);
+ goto cleanup;
+ }
+ break;
+ /* die on sigint/sigterm. Kill all children too. */
+ case SIGINT:
+ case SIGTERM:
+ PARA_EMERG_LOG("terminating on signal %d\n", signum);
+ kill(0, SIGTERM);
+ /*
+ * We must wait for afs because afs catches SIGINT/SIGTERM.
+ * Before reacting to the signal, afs might want to use the
+ * shared memory area and the mmd mutex. If we destroy this
+ * mutex too early and afs tries to lock the shared memory
+ * area, the call to mutex_lock() will fail and terminate the
+ * afs process. This leads to dirty osl tables.
+ *
+ * There's no such problem with the other children of the
+ * server process (the command handlers) as these reset their
+ * SIGINT/SIGTERM handlers to the default action, i.e. these
+ * processes get killed immediately by the above kill().
+ */
+ PARA_INFO_LOG("waiting for afs (pid %d) to die\n",
+ (int)mmd->afs_pid);
+ waitpid(mmd->afs_pid, NULL, 0);
+cleanup:
+ free(mmd->afd.afhi.chunk_table);
+ close_listed_fds();
+ mutex_destroy(mmd_mutex);
+ shm_detach(mmd);
+ exit(EXIT_FAILURE);
+ }
+ return 0;
+}
+
+static void init_signal_task(void)
+{
+ signal_task = signal_init_or_die();
+ para_install_sighandler(SIGINT);
+ para_install_sighandler(SIGTERM);
+ para_install_sighandler(SIGHUP);
+ para_install_sighandler(SIGCHLD);
+ para_sigaction(SIGPIPE, SIG_IGN);
+ add_close_on_fork_list(signal_task->fd);
+ signal_task->task = task_register(&(struct task_info) {
+ .name = "signal",
+ .pre_select = signal_pre_select,
+ .post_select = signal_post_select,
+ .context = signal_task,
+
+ }, &sched);
+}
+
+static void command_pre_select(struct sched *s, void *context)
+{
+ struct server_command_task *sct = context;
+ para_fd_set(sct->listen_fd, &s->rfds, &s->max_fileno);