]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
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 ccd9eeef52b54c90efaacf50d20b612271b3121a..b6c6d6a80b7c752b9eeb718dc396fbd1bccd92c5 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 844a94f1b095cacf540358eda903cafa244b6dc2..ae15f4b76a31e83f77af7e6409151564deeb7f96 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 0f369f491704fb74522a32708d8b0526792a43f6..6ed50b4e4a7df8f806efabf957dab305e77a95db 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) {