From: Michael Marley Date: Wed, 31 Jan 2024 02:51:53 +0000 (-0500) Subject: Use sigaction() instead of signal() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=717056be02e1d1754bc86948c8523964c5ea0f1c;p=thirdparty%2Ftvheadend.git Use sigaction() instead of signal() The behavior of signal() is not consistent or defined when using it to set signal handlers (see "Portability" in https://man7.org/linux/man-pages/man2/signal.2.html). Previously we got away with this, but starting with GCC 14, using signal() apparently causes certain syscalls to be restarted after the signal is caught. One of these is the read() currently on line 63 of fsmonitor.c. The result is that read() doesn't return when the fsmonitor thread receives a signal, resulting in the thread never shutting down, resulting in TVHeadend hanging on any attempt to terminate it. Instead, use sigaction(), which has defined behavior when setting signal handlers. Since invoking sigaction() requires several lines, a helper was added to tvh_thread.c to avoid code duplication. --- diff --git a/src/main.c b/src/main.c index f02b4f8cc..3268ded52 100644 --- a/src/main.c +++ b/src/main.c @@ -217,7 +217,7 @@ handle_sigill(int x) /* to determine the CPU capabilities with possible */ /* unknown instructions */ tvhwarn(LS_CPU, "Illegal instruction handler (might be OK)"); - signal(SIGILL, handle_sigill); + tvh_signal(SIGILL, handle_sigill); } void @@ -228,7 +228,7 @@ doexit(int x) tvh_cond_signal(>imer_cond, 0); tvh_cond_signal(&mtimer_cond, 0); atomic_set(&tvheadend_running, 0); - signal(x, doexit); + tvh_signal(x, doexit); } static int @@ -1111,8 +1111,8 @@ main(int argc, char **argv) tvhlog_set_trace(log_trace); tvhinfo(LS_MAIN, "Log started"); - signal(SIGPIPE, handle_sigpipe); // will be redundant later - signal(SIGILL, handle_sigill); // see handler.. + tvh_signal(SIGPIPE, handle_sigpipe); // will be redundant later + tvh_signal(SIGILL, handle_sigill); // see handler.. /* Set privileges */ if((opt_fork && getuid() == 0) || opt_group || opt_user) { @@ -1345,8 +1345,8 @@ main(int argc, char **argv) sigaddset(&set, SIGTERM); sigaddset(&set, SIGINT); - signal(SIGTERM, doexit); - signal(SIGINT, doexit); + tvh_signal(SIGTERM, doexit); + tvh_signal(SIGINT, doexit); pthread_sigmask(SIG_UNBLOCK, &set, NULL); diff --git a/src/tvh_thread.c b/src/tvh_thread.c index 4149ad2bf..6a019d7a0 100644 --- a/src/tvh_thread.c +++ b/src/tvh_thread.c @@ -82,8 +82,8 @@ thread_wrapper(void *p) sigaddset(&set, SIGQUIT); pthread_sigmask(SIG_UNBLOCK, &set, NULL); - signal(SIGTERM, doexit); - signal(SIGQUIT, doquit); + tvh_signal(SIGTERM, doexit); + tvh_signal(SIGQUIT, doquit); /* Run */ tvhtrace(LS_THREAD, "created thread %ld [%s / %p(%p)]", @@ -430,6 +430,14 @@ int tvh_cond_timedwait_ts(tvh_cond_t *cond, tvh_mutex_t *mutex, struct timespec return r; } +int tvh_signal(int signal, void (*handler) (int)) +{ + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = handler; + return sigaction(signal, &action, NULL); +} + void tvh_mutex_not_held(const char *file, int line) { diff --git a/src/tvh_thread.h b/src/tvh_thread.h index c7baa4812..3305ba299 100644 --- a/src/tvh_thread.h +++ b/src/tvh_thread.h @@ -156,6 +156,8 @@ int tvh_cond_wait(tvh_cond_t *cond, tvh_mutex_t *mutex); int tvh_cond_timedwait(tvh_cond_t *cond, tvh_mutex_t *mutex, int64_t clock); int tvh_cond_timedwait_ts(tvh_cond_t *cond, tvh_mutex_t *mutex, struct timespec *ts); +int tvh_signal(int signal, void (*handler) (int)); + #ifndef TVH_THREAD_C #define pthread_cond __do_not_use_pthread_cond #define pthread_cond_t __do_not_use_pthread_cond_t