about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/internal/pthread_impl.h2
-rw-r--r--src/thread/pthread_create.c60
2 files changed, 39 insertions, 23 deletions
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index fc2def63..69352ef2 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -47,8 +47,6 @@ struct pthread {
 	volatile int timer_id;
 	locale_t locale;
 	volatile int killlock[1];
-	volatile int startlock[1];
-	unsigned long sigmask[_NSIG/8/sizeof(long)];
 	char *dlerror_buf;
 	void *stdio_locks;
 
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index e07d29e3..5f07ab49 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -132,22 +132,36 @@ void __do_cleanup_pop(struct __ptcb *cb)
 	__pthread_self()->cancelbuf = cb->__next;
 }
 
+struct start_sched_args {
+	void *start_arg;
+	void *(*start_fn)(void *);
+	sigset_t mask;
+	pthread_attr_t *attr;
+	volatile int futex;
+};
+
+static void *start_sched(void *p)
+{
+	struct start_sched_args *ssa = p;
+	void *start_arg = ssa->start_arg;
+	void *(*start_fn)(void *) = ssa->start_fn;
+	pthread_t self = __pthread_self();
+
+	int ret = -__syscall(SYS_sched_setscheduler, self->tid,
+		ssa->attr->_a_policy, &ssa->attr->_a_prio);
+	if (!ret) __restore_sigs(&ssa->mask);
+	a_store(&ssa->futex, ret);
+	__wake(&ssa->futex, 1, 1);
+	if (ret) {
+		self->detach_state = DT_DYNAMIC;
+		return 0;
+	}
+	return start_fn(start_arg);
+}
+
 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] == 2) {
-			self->detach_state = DT_DYNAMIC;
-			pthread_exit(0);
-		}
-		__restore_sigs(self->sigmask);
-	}
 	if (self->unblock_cancel)
 		__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
 			SIGPT_SET, 0, _NSIG/8);
@@ -198,6 +212,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
 		| CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED;
 	int do_sched = 0;
 	pthread_attr_t attr = { 0 };
+	struct start_sched_args ssa;
 
 	if (!libc.can_do_threads) return ENOSYS;
 	self = __pthread_self();
@@ -282,8 +297,14 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
 		new->detach_state = DT_JOINABLE;
 	}
 	if (attr._a_sched) {
-		do_sched = new->startlock[0] = 1;
-		__block_app_sigs(new->sigmask);
+		do_sched = 1;
+		ssa.futex = -1;
+		ssa.start_fn = new->start;
+		ssa.start_arg = new->start_arg;
+		ssa.attr = &attr;
+		new->start = start_sched;
+		new->start_arg = &ssa;
+		__block_app_sigs(&ssa.mask);
 	}
 	new->robust_list.head = &new->robust_list.head;
 	new->unblock_cancel = self->cancel;
@@ -295,7 +316,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
 	__release_ptc();
 
 	if (do_sched) {
-		__restore_sigs(new->sigmask);
+		__restore_sigs(&ssa.mask);
 	}
 
 	if (ret < 0) {
@@ -305,11 +326,8 @@ 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 : 3);
-		__wake(new->startlock, 1, 1);
-		if (ret < 0) return -ret;
+		__futexwait(&ssa.futex, -1, 1);
+		if (ret) return ret;
 	}
 
 	*res = new;