summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2017-09-06 20:37:19 -0400
committerRich Felker <dalias@aerifal.cx>2017-09-06 20:37:19 -0400
commit9e01be6e49b9ae433072207f420ef33c8189eb78 (patch)
treef8cf6089257a0b4252b391b8abbc9ab042458fd5
parent822dddfbf1884553341114663aff56ed87d57663 (diff)
downloadmusl-9e01be6e49b9ae433072207f420ef33c8189eb78.tar.gz
fix signal masking race in pthread_create with priority attributes
if the parent thread was able to set the new thread's priority before it reached the check for 'startlock', the new thread failed to restore its signal mask and thus ran with all signals blocked. concept for patch by Sergei, who reported the issue; unnecessary changes were removed and comments added since the whole 'startlock' thing is non-idiomatic and confusing. eventually it should be replaced with use of idiomatic synchronization primitives.
-rw-r--r--src/thread/pthread_create.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index 49f2f729..6cbf85b3 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -131,9 +131,14 @@ void __do_cleanup_pop(struct __ptcb *cb)
static int start(void *p)
{
pthread_t self = p;
+ /* States for startlock:
+ * 0 = no need for start sync
+ * 1 = waiting for parent to do work
+ * 2 = failure in parent, child must abort
+ * 3 = success in parent, child must restore sigmask */
if (self->startlock[0]) {
__wait(self->startlock, 0, 1, 1);
- if (self->startlock[0]) {
+ if (self->startlock[0] == 2) {
self->detached = 2;
pthread_exit(0);
}
@@ -295,7 +300,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
if (do_sched) {
ret = __syscall(SYS_sched_setscheduler, new->tid,
attr._a_policy, &attr._a_prio);
- a_store(new->startlock, ret<0 ? 2 : 0);
+ a_store(new->startlock, ret<0 ? 2 : 3);
__wake(new->startlock, 1, 1);
if (ret < 0) return -ret;
}