Fix exit path From: Daniel Drake We currently have an exit race: exit_cmd() sends SIGTERM to the sighandler thread, then both sighandler and exit_cmd() call exit(). This adds another signal to the signal handler (SIGINT) which is equivalent to SIGTERM except it means "another thread wants me to go away" as opposed to "someone wants me to terminate everything". cmd_exit() now sends SIGINT and waits for the signal handler to finish up and go away before cleaning everything up. I also added a VT_RELDISP ioctl to the cleanup path just to be 100% sure that the kernel knows we have released the terminal. I'm investigating a race where the kernel asks us to release the terminal, but as we are shutting down we don't have time to process the signal properly. This isn't a complete fix but should be safe anyway. Index: splashutils-1.3/daemon.c =================================================================== --- splashutils-1.3.orig/daemon.c +++ splashutils-1.3/daemon.c @@ -209,6 +209,7 @@ void vt_silent_cleanup(void) vt.waitv = 0; tcsetattr(fd_tty_s, TCSANOW, &tios); + ioctl(fd_tty_s, VT_RELDISP, 1); ioctl(fd_tty_s, KDSETMODE, KD_TEXT); ioctl(fd_tty_s, VT_SETMODE, &vt); @@ -274,6 +275,13 @@ void switch_silent() cmd_repaint(NULL); } +static void do_cleanup(void) +{ + pthread_mutex_trylock(&mtx_tty); + vt_silent_cleanup(); + vt_cursor_enable(fd_tty_s); +} + /* * Signal handler. * @@ -290,6 +298,7 @@ void* thf_sighandler(void *unusued) sigaddset(&sigset, SIGUSR1); sigaddset(&sigset, SIGUSR2); sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGINT); while (1) { sigwait(&sigset, &sig); @@ -314,10 +323,12 @@ void* thf_sighandler(void *unusued) pthread_mutex_unlock(&mtx_paint); switch_silent(); + } else if (sig == SIGINT) { + /* internally generated terminate signal */ + do_cleanup(); + pthread_exit(NULL); } else if (sig == SIGTERM) { - pthread_mutex_trylock(&mtx_tty); - vt_silent_cleanup(); - vt_cursor_enable(fd_tty_s); + do_cleanup(); exit(0); } } @@ -692,13 +703,13 @@ void daemon_start() setsid(); signal(SIGABRT, SIG_IGN); - signal(SIGINT, SIG_IGN); /* These signals will be handled by the sighandler thread. */ sigemptyset(&sigset); sigaddset(&sigset, SIGUSR1); sigaddset(&sigset, SIGUSR2); sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGINT); sigprocmask(SIG_BLOCK, &sigset, NULL); pthread_mutex_lock(&mtx_paint); pthread_create(&th_sighandler, NULL, &thf_sighandler, NULL); Index: splashutils-1.3/daemon_cmd.c =================================================================== --- splashutils-1.3.orig/daemon_cmd.c +++ splashutils-1.3/daemon_cmd.c @@ -93,7 +93,8 @@ int cmd_exit(void **args) item *i, *j; pthread_cancel(th_switchmon); - pthread_kill(th_sighandler, SIGTERM); + pthread_kill(th_sighandler, SIGINT); + pthread_join(th_sighandler, NULL); free_objs();