]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Use sigaction() instead of signal()
authorMichael Marley <michael@michaelmarley.com>
Wed, 31 Jan 2024 02:51:53 +0000 (21:51 -0500)
committerFlole998 <Flole998@users.noreply.github.com>
Thu, 1 Feb 2024 00:39:39 +0000 (01:39 +0100)
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.

src/main.c
src/tvh_thread.c
src/tvh_thread.h

index f02b4f8cc403546242bf4e065cf6f55c9dde8a5c..3268ded52fe68e1a12735e05b1ac4cfff18f204f 100644 (file)
@@ -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(&gtimer_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);
 
index 4149ad2bfe17a8ac6471fcbc1312921f0318b39e..6a019d7a02f3446deefe07cdb581e8192929d40b 100644 (file)
@@ -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)
 {
index c7baa4812eae3b3a3c08c952cc9f7fc1141710e9..3305ba299724d42f5f20ec2f1f489c9fcfc6c165 100644 (file)
@@ -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