diff --git a/src/basic/async.c b/src/basic/async.c index ccd9eeef52..b6c6d6a80b 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -32,32 +32,52 @@ #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) { diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 844a94f1b0..ae15f4b76a 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -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; diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 0f369f4917..6ed50b4e4a 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -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) {