summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-05 12:15:21 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-05 12:32:00 +0100
commite17da4c1150b1f8be9071c7403163ea6fb518c6e (patch)
tree578746027e656a7d86f0eb81aa4b42a3d0d2ba33 /lib
parent199c35e4c9cfd10d070392d58625e86b2f8f4c19 (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>
Diffstat (limited to 'lib')
-rw-r--r--lib/sqfs/data_writer/internal.h1
-rw-r--r--lib/sqfs/data_writer/pthread.c7
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) {