tree-wide: in all threads we fork off in library code, block all signals
authorLennart Poettering <lennart@poettering.net>
Fri, 29 Dec 2017 20:21:54 +0000 (21:21 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 4 Jan 2018 12:27:27 +0000 (13:27 +0100)
This ensures that in all threads we fork off in the background in our
code we mask out all signals, so that our thread won't end up getting
signals delivered the main process should be getting.

We always set the signal mask before forking off the thread, so that the
thread has the right mask set from its earliest existance on.

src/basic/async.c
src/journal/journal-file.c
src/libsystemd/sd-resolve/sd-resolve.c

index ccd9eee..b6c6d6a 100644 (file)
 #include "util.h"
 
 int asynchronous_job(void* (*func)(void *p), void *arg) {
+        sigset_t ss, saved_ss;
         pthread_attr_t a;
         pthread_t t;
-        int r;
+        int r, k;
 
-        /* It kinda sucks that we have to resort to threads to
-         * implement an asynchronous sync(), but well, such is
-         * life.
-         *
-         * Note that issuing this command right before exiting a
-         * process will cause the process to wait for the sync() to
-         * complete. This function hence is nicely asynchronous really
-         * only in long running processes. */
+        /* It kinda sucks that we have to resort to threads to implement an asynchronous close(), but well, such is
+         * life. */
 
         r = pthread_attr_init(&a);
         if (r > 0)
                 return -r;
 
         r = pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
-        if (r > 0)
+        if (r > 0) {
+                r = -r;
                 goto finish;
+        }
+
+        if (sigfillset(&ss) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        /* Block all signals before forking off the thread, so that the new thread is started with all signals
+         * blocked. This way the existence of the new thread won't affect signal handling in other threads. */
+
+        r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
+        if (r > 0) {
+                r = -r;
+                goto finish;
+        }
 
         r = pthread_create(&t, &a, func, arg);
 
+        k = pthread_sigmask(SIG_SETMASK, &saved_ss, NULL);
+
+        if (r > 0)
+                r = -r;
+        else if (k > 0)
+                r = -k;
+        else
+                r = 0;
+
 finish:
         pthread_attr_destroy(&a);
-        return -r;
+        return r;
 }
 
 int asynchronous_sync(pid_t *ret_pid) {
index 844a94f..ae15f4b 100644 (file)
@@ -247,11 +247,25 @@ int journal_file_set_offline(JournalFile *f, bool wait) {
         if (wait) /* Without using a thread if waiting. */
                 journal_file_set_offline_internal(f);
         else {
+                sigset_t ss, saved_ss;
+                int k;
+
+                if (sigfillset(&ss) < 0)
+                        return -errno;
+
+                r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
+                if (r > 0)
+                        return -r;
+
                 r = pthread_create(&f->offline_thread, NULL, journal_file_set_offline_thread, f);
+
+                k = pthread_sigmask(SIG_SETMASK, &saved_ss, NULL);
                 if (r > 0) {
                         f->offline_state = OFFLINE_JOINED;
                         return -r;
                 }
+                if (k > 0)
+                        return -k;
         }
 
         return 0;
index 0f369f4..6ed50b4 100644 (file)
@@ -398,11 +398,6 @@ static int handle_request(int out_fd, const Packet *packet, size_t length) {
 
 static void* thread_worker(void *p) {
         sd_resolve *resolve = p;
-        sigset_t fullset;
-
-        /* No signals in this thread please */
-        assert_se(sigfillset(&fullset) == 0);
-        assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0);
 
         /* Assign a pretty name to this thread */
         (void) pthread_setname_np(pthread_self(), "sd-resolve");
@@ -437,8 +432,18 @@ static void* thread_worker(void *p) {
 }
 
 static int start_threads(sd_resolve *resolve, unsigned extra) {
+        sigset_t ss, saved_ss;
         unsigned n;
-        int r;
+        int r, k;
+
+        if (sigfillset(&ss) < 0)
+                return -errno;
+
+        /* No signals in forked off threads please. We set the mask before forking, so that the threads never exist
+         * with a different mask than a fully blocked one */
+        r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
+        if (r > 0)
+                return -r;
 
         n = resolve->n_outstanding + extra;
         n = CLAMP(n, WORKERS_MIN, WORKERS_MAX);
@@ -446,13 +451,22 @@ static int start_threads(sd_resolve *resolve, unsigned extra) {
         while (resolve->n_valid_workers < n) {
 
                 r = pthread_create(&resolve->workers[resolve->n_valid_workers], NULL, thread_worker, resolve);
-                if (r != 0)
-                        return -r;
+                if (r > 0) {
+                        r = -r;
+                        goto finish;
+                }
 
                 resolve->n_valid_workers++;
         }
 
-        return 0;
+        r = 0;
+
+finish:
+        k = pthread_sigmask(SIG_SETMASK, &saved_ss, NULL);
+        if (k > 0 && r >= 0)
+                r = -k;
+
+        return r;
 }
 
 static bool resolve_pid_changed(sd_resolve *r) {