Skip to content

Commit 02df615

Browse files
andyrosscfriedt
authored andcommitted
lib/pthread: Fix create/join race in thread lifecycle
The pthread_join() implementation was done using a condition variable and not k_thread_join(), and that's actually fatal. It's not possible in Zephyr to guarantee a thread has exited in a race-free way without calling either k_thread_abort() or k_thread_join(). This opened a hole where an app could call pthread_join(), which would go to sleep waiting on the condition variable, which would be signaled from the exit path of the thread, and then return to call pthread_create() (and thus k_thread_create()) on the same pthread_t object (and thus the same struct k_thread) BEFORE THE EARLIER THREAD HAD ACTUALLY EXITED. This makes the scheduler blow up, at least on SMP (I wasn't personally able to make it happen on uniprocessor configs, though the race is present always). Rework to call k_thread_join(). There's no other correct way to do this. Fixes zephyrproject-rtos#56163 Signed-off-by: Andy Ross <[email protected]>
1 parent 084132e commit 02df615

File tree

2 files changed

+7
-16
lines changed

2 files changed

+7
-16
lines changed

lib/posix/posix_internal.h

-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ struct posix_thread {
5454
/* Pthread State */
5555
enum pthread_state state;
5656
pthread_mutex_t state_lock;
57-
pthread_cond_t state_cond;
5857
};
5958

6059
typedef struct pthread_key_obj {

lib/posix/pthread.c

+7-15
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr,
183183
k_spinlock_key_t key;
184184
uint32_t pthread_num;
185185
k_spinlock_key_t cancel_key;
186-
pthread_condattr_t cond_attr;
187186
struct posix_thread *thread;
188187
const struct pthread_attr *attr = (const struct pthread_attr *)_attr;
189188

@@ -218,8 +217,6 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr,
218217
thread->cancel_pending = 0;
219218
k_spin_unlock(&thread->cancel_lock, cancel_key);
220219

221-
pthread_cond_init(&thread->state_cond, &cond_attr);
222-
223220
*newthread = pthread_num;
224221
k_thread_create(&thread->thread, attr->stack, attr->stacksize,
225222
(k_thread_entry_t)zephyr_thread_wrapper, (void *)arg, NULL, threadroutine,
@@ -283,7 +280,6 @@ int pthread_cancel(pthread_t pthread)
283280
} else {
284281
thread->retval = PTHREAD_CANCELED;
285282
thread->state = PTHREAD_EXITED;
286-
pthread_cond_broadcast(&thread->state_cond);
287283
}
288284
pthread_mutex_unlock(&thread->state_lock);
289285

@@ -405,7 +401,6 @@ void pthread_exit(void *retval)
405401
if (self->state == PTHREAD_JOINABLE) {
406402
self->state = PTHREAD_EXITED;
407403
self->retval = retval;
408-
pthread_cond_broadcast(&self->state_cond);
409404
} else {
410405
destroy = true;
411406
self->state = PTHREAD_TERMINATED;
@@ -428,8 +423,6 @@ void pthread_exit(void *retval)
428423
pthread_mutex_destroy(&self->state_lock);
429424
}
430425

431-
pthread_cond_destroy(&self->state_cond);
432-
433426
k_thread_abort(&self->thread);
434427
}
435428

@@ -452,12 +445,14 @@ int pthread_join(pthread_t thread, void **status)
452445
return ESRCH;
453446
}
454447

455-
pthread_mutex_lock(&pthread->state_lock);
456-
457-
if (pthread->state == PTHREAD_JOINABLE) {
458-
pthread_cond_wait(&pthread->state_cond, &pthread->state_lock);
448+
if (pthread->state == PTHREAD_DETACHED) {
449+
return EINVAL;
459450
}
460451

452+
k_thread_join(&pthread->thread, K_FOREVER);
453+
454+
pthread_mutex_lock(&pthread->state_lock);
455+
461456
if (pthread->state == PTHREAD_EXITED) {
462457
destroy = true;
463458
pthread->state = PTHREAD_TERMINATED;
@@ -498,10 +493,7 @@ int pthread_detach(pthread_t thread)
498493
switch (pthread->state) {
499494
case PTHREAD_JOINABLE:
500495
pthread->state = PTHREAD_DETACHED;
501-
/* Broadcast the condition.
502-
* This will make threads waiting to join this thread continue.
503-
*/
504-
pthread_cond_broadcast(&pthread->state_cond);
496+
z_thread_wake_joiners(&pthread->thread);
505497
break;
506498
case PTHREAD_EXITED:
507499
join = true;

0 commit comments

Comments
 (0)