提交 8a544ee3 编写于 作者: R Rich Felker

synchronously clean up pthread_create failure due to scheduling errors

previously, when pthread_create failed due to inability to set
explicit scheduling according to the requested attributes, the nascent
thread was detached and made responsible for its own cleanup via the
standard pthread_exit code path. this left it consuming resources
potentially well after pthread_create returned, in a way that the
application could not see or mitigate, and unnecessarily exposed its
existence to the rest of the implementation via the global thread
list.

instead, attempt explicit scheduling early and reuse the failure path
for __clone failure if it fails. the nascent thread's exit futex is
not needed for unlocking the thread list, since the thread calling
pthread_create holds the thread list lock the whole time, so it can be
repurposed to ensure the thread has finished exiting. no pthread_exit
is needed, and freeing the stack, if needed, can happen just as it
would if __clone failed.
上级 022f27d5
...@@ -184,8 +184,8 @@ static int start(void *p) ...@@ -184,8 +184,8 @@ static int start(void *p)
if (a_cas(&args->control, 1, 2)==1) if (a_cas(&args->control, 1, 2)==1)
__wait(&args->control, 0, 2, 1); __wait(&args->control, 0, 2, 1);
if (args->control) { if (args->control) {
__pthread_self()->detach_state = DT_DETACHED; __syscall(SYS_set_tid_address, &args->control);
__pthread_exit(0); return 0;
} }
} }
__syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->sig_mask, 0, _NSIG/8); __syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->sig_mask, 0, _NSIG/8);
...@@ -339,8 +339,21 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att ...@@ -339,8 +339,21 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
libc.threads_minus_1++; libc.threads_minus_1++;
ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock); ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock);
/* If clone succeeded, new thread must be linked on the thread /* All clone failures translate to EAGAIN. If explicit scheduling
* list before unlocking it, even if scheduling may still fail. */ * was requested, attempt it before unlocking the thread list so
* that the failed thread is never exposed and so that we can
* clean up all transient resource usage before returning. */
if (ret < 0) {
ret = -EAGAIN;
} else if (attr._a_sched) {
ret = __syscall(SYS_sched_setscheduler,
new->tid, attr._a_policy, &attr._a_prio);
if (a_swap(&args->control, ret ? 3 : 0)==2)
__wake(&args->control, 1, 1);
if (ret)
__wait(&args->control, 0, 3, 0);
}
if (ret >= 0) { if (ret >= 0) {
new->next = self->next; new->next = self->next;
new->prev = self; new->prev = self;
...@@ -355,15 +368,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att ...@@ -355,15 +368,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
if (ret < 0) { if (ret < 0) {
if (map) __munmap(map, size); if (map) __munmap(map, size);
return EAGAIN; return -ret;
}
if (attr._a_sched) {
int ret = -__syscall(SYS_sched_setscheduler, new->tid,
attr._a_policy, &attr._a_prio);
if (a_swap(&args->control, ret ? 3 : 0)==2)
__wake(&args->control, 1, 1);
if (ret) return ret;
} }
*res = new; *res = new;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册