diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-05 12:15:21 +0100 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-05 12:32:00 +0100 |
commit | e17da4c1150b1f8be9071c7403163ea6fb518c6e (patch) | |
tree | 578746027e656a7d86f0eb81aa4b42a3d0d2ba33 | |
parent | 199c35e4c9cfd10d070392d58625e86b2f8f4c19 (diff) |
Fix pthread data writer interfering with signal handling
If a signal is sent to a process, the POSIX spec says that ANY thread
could be picked ARBITRARILY to handle the signal. In our case this could
be one of the internal worker threads.
The problem here is that an unsuspecting user of the library might
suddenly have their signal handler run in parallel to their main thread
and run into weird concurrency issues, because they didn't expect that
to happen.
In fact, the libsquashfs API tries to be transparent about whether or
not it uses a thread pool internally and does everything other than
number crunching (e.g. I/O that may happen through user supplied
callbacks) in the same thread as the one that submitts the blocks.
Unfortunately, pthread doesn't have a way to set a signal mask for the
new thread and setting it inside the thread is racy (i.e. a signal might
be delivered before the worker thread sets the mask).
The only portable and non-racy way to do this, is to disable all signals
in the calling thread that sets up the data writer, create the threads
(which will inherit the mask) and then resetore the previous signal mask,
hoping for the best.
The downside to this is that signals may be lost in that short time.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r-- | lib/sqfs/data_writer/internal.h | 1 | ||||
-rw-r--r-- | lib/sqfs/data_writer/pthread.c | 7 |
2 files changed, 8 insertions, 0 deletions
diff --git a/lib/sqfs/data_writer/internal.h b/lib/sqfs/data_writer/internal.h index d6e26cd..7af6ab4 100644 --- a/lib/sqfs/data_writer/internal.h +++ b/lib/sqfs/data_writer/internal.h @@ -24,6 +24,7 @@ #ifdef WITH_PTHREAD #include <pthread.h> +#include <signal.h> #endif diff --git a/lib/sqfs/data_writer/pthread.c b/lib/sqfs/data_writer/pthread.c index 3cdf8fb..915ea2a 100644 --- a/lib/sqfs/data_writer/pthread.c +++ b/lib/sqfs/data_writer/pthread.c @@ -45,6 +45,7 @@ sqfs_data_writer_t *sqfs_data_writer_create(size_t max_block_size, sqfs_file_t *file) { sqfs_data_writer_t *proc; + sigset_t set, oldset; unsigned int i; int ret; @@ -79,6 +80,9 @@ sqfs_data_writer_t *sqfs_data_writer_create(size_t max_block_size, goto fail_init; } + sigfillset(&set); + pthread_sigmask(SIG_SETMASK, &set, &oldset); + for (i = 0; i < num_workers; ++i) { ret = pthread_create(&proc->workers[i]->thread, NULL, worker_proc, proc->workers[i]); @@ -87,6 +91,8 @@ sqfs_data_writer_t *sqfs_data_writer_create(size_t max_block_size, goto fail_thread; } + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + return proc; fail_thread: pthread_mutex_lock(&proc->mtx); @@ -99,6 +105,7 @@ fail_thread: pthread_join(proc->workers[i]->thread, NULL); } } + pthread_sigmask(SIG_SETMASK, &oldset, NULL); fail_init: for (i = 0; i < num_workers; ++i) { if (proc->workers[i] != NULL) { |