Skip to content

Commit 22bf59f

Browse files
author
Christopher Friedt
committed
posix: pthread: initial and final state must be TERMINATED
Previously, we considered `PTHREAD_EXITED` as a valid state for reclaiming a thread. That was not the case. `PTHREAD_EXITED` requires that `pthread_join()` is called while the thread is in `PTHREAD_EXITED` state. With that the calling thread may retrieve the return value of the joining thread. Additionally, correct incorrectly aliased pointer argument to `k_thread_abort()`. Signed-off-by: Christopher Friedt <[email protected]>
1 parent cd264e5 commit 22bf59f

File tree

2 files changed

+58
-37
lines changed

2 files changed

+58
-37
lines changed

lib/posix/posix_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ enum pthread_state {
3131
PTHREAD_DETACHED = PTHREAD_CREATE_DETACHED,
3232
/* The thread is running and joinable. */
3333
PTHREAD_JOINABLE = PTHREAD_CREATE_JOINABLE,
34+
/* A joinable thread exited and its return code is available. */
35+
PTHREAD_EXITED,
3436
/* The thread structure is unallocated and available for reuse. */
3537
PTHREAD_TERMINATED,
36-
/* A joinable thread exited and its return code is available. */
37-
PTHREAD_EXITED
3838
};
3939

4040
struct posix_thread {

lib/posix/pthread.c

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,31 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
143143
pthread_exit(NULL);
144144
}
145145

146+
static bool pthread_attr_is_valid(const struct pthread_attr *attr)
147+
{
148+
/*
149+
* FIXME: Pthread attribute must be non-null and it provides stack
150+
* pointer and stack size. So even though POSIX 1003.1 spec accepts
151+
* attrib as NULL but zephyr needs it initialized with valid stack.
152+
*/
153+
if (attr == NULL || attr->initialized == 0U || attr->stack == NULL ||
154+
attr->stacksize == 0) {
155+
return false;
156+
}
157+
158+
/* require a valid scheduler policy */
159+
if (!valid_posix_policy(attr->schedpolicy)) {
160+
return false;
161+
}
162+
163+
/* require a valid detachstate */
164+
if (!(attr->detachstate == PTHREAD_JOINABLE || attr->detachstate == PTHREAD_DETACHED)) {
165+
return false;
166+
}
167+
168+
return true;
169+
}
170+
146171
/**
147172
* @brief Create a new thread.
148173
*
@@ -154,7 +179,6 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
154179
int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr,
155180
void *(*threadroutine)(void *), void *arg)
156181
{
157-
int rv;
158182
int32_t prio;
159183
k_spinlock_key_t key;
160184
uint32_t pthread_num;
@@ -163,22 +187,21 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr,
163187
struct posix_thread *thread;
164188
const struct pthread_attr *attr = (const struct pthread_attr *)_attr;
165189

166-
/*
167-
* FIXME: Pthread attribute must be non-null and it provides stack
168-
* pointer and stack size. So even though POSIX 1003.1 spec accepts
169-
* attrib as NULL but zephyr needs it initialized with valid stack.
170-
*/
171-
if ((attr == NULL) || (attr->initialized == 0U)
172-
|| (attr->stack == NULL) || (attr->stacksize == 0)) {
190+
if (!pthread_attr_is_valid(attr)) {
173191
return EINVAL;
174192
}
175193

176194
key = k_spin_lock(&pthread_pool_lock);
177-
for (pthread_num = 0;
178-
pthread_num < CONFIG_MAX_PTHREAD_COUNT; pthread_num++) {
195+
for (pthread_num = 0; pthread_num < CONFIG_MAX_PTHREAD_COUNT; pthread_num++) {
179196
thread = &posix_thread_pool[pthread_num];
180197
if (thread->state == PTHREAD_TERMINATED) {
181-
thread->state = PTHREAD_JOINABLE;
198+
if (pthread_mutex_init(&thread->state_lock, NULL) == 0) {
199+
thread->state = attr->detachstate;
200+
sys_slist_init(&thread->key_list);
201+
} else {
202+
/* cannot allocate resources so break early and return EAGAIN */
203+
pthread_num = CONFIG_MAX_PTHREAD_COUNT;
204+
}
182205
break;
183206
}
184207
}
@@ -188,27 +211,14 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr,
188211
return EAGAIN;
189212
}
190213

191-
rv = pthread_mutex_init(&thread->state_lock, NULL);
192-
if (rv != 0) {
193-
key = k_spin_lock(&pthread_pool_lock);
194-
thread->state = PTHREAD_EXITED;
195-
k_spin_unlock(&pthread_pool_lock, key);
196-
return rv;
197-
}
198-
199214
prio = posix_to_zephyr_priority(attr->priority, attr->schedpolicy);
200215

201216
cancel_key = k_spin_lock(&thread->cancel_lock);
202217
thread->cancel_state = (1 << _PTHREAD_CANCEL_POS) & attr->flags;
203218
thread->cancel_pending = 0;
204219
k_spin_unlock(&thread->cancel_lock, cancel_key);
205220

206-
pthread_mutex_lock(&thread->state_lock);
207-
thread->state = attr->detachstate;
208-
pthread_mutex_unlock(&thread->state_lock);
209-
210221
pthread_cond_init(&thread->state_cond, &cond_attr);
211-
sys_slist_init(&thread->key_list);
212222

213223
*newthread = pthread_num;
214224
k_thread_create(&thread->thread, attr->stack, attr->stacksize,
@@ -217,7 +227,6 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr,
217227
return 0;
218228
}
219229

220-
221230
/**
222231
* @brief Set cancelability State.
223232
*
@@ -377,6 +386,7 @@ int pthread_once(pthread_once_t *once, void (*init_func)(void))
377386
*/
378387
void pthread_exit(void *retval)
379388
{
389+
bool destroy = false;
380390
k_spinlock_key_t cancel_key;
381391
struct posix_thread *self = to_posix_thread(pthread_self());
382392
pthread_key_obj *key_obj;
@@ -397,6 +407,7 @@ void pthread_exit(void *retval)
397407
self->retval = retval;
398408
pthread_cond_broadcast(&self->state_cond);
399409
} else {
410+
destroy = true;
400411
self->state = PTHREAD_TERMINATED;
401412
}
402413

@@ -411,11 +422,15 @@ void pthread_exit(void *retval)
411422
}
412423

413424
pthread_mutex_unlock(&self->state_lock);
414-
pthread_mutex_destroy(&self->state_lock);
425+
426+
if (destroy) {
427+
/* A detached thread must have its resources destroyed by pthread_exit() */
428+
pthread_mutex_destroy(&self->state_lock);
429+
}
415430

416431
pthread_cond_destroy(&self->state_cond);
417432

418-
k_thread_abort((k_tid_t)self);
433+
k_thread_abort(&self->thread);
419434
}
420435

421436
/**
@@ -425,6 +440,7 @@ void pthread_exit(void *retval)
425440
*/
426441
int pthread_join(pthread_t thread, void **status)
427442
{
443+
bool destroy = false;
428444
struct posix_thread *pthread = to_posix_thread(thread);
429445
int ret = 0;
430446

@@ -443,17 +459,19 @@ int pthread_join(pthread_t thread, void **status)
443459
}
444460

445461
if (pthread->state == PTHREAD_EXITED) {
462+
destroy = true;
463+
pthread->state = PTHREAD_TERMINATED;
446464
if (status != NULL) {
447465
*status = pthread->retval;
448466
}
449-
} else if (pthread->state == PTHREAD_DETACHED) {
450-
ret = EINVAL;
451467
} else {
452468
ret = ESRCH;
453469
}
454470

455471
pthread_mutex_unlock(&pthread->state_lock);
456-
if (pthread->state == PTHREAD_EXITED) {
472+
473+
if (destroy) {
474+
/* A joined thread must have its resources destroyed by pthread_join() */
457475
pthread_mutex_destroy(&pthread->state_lock);
458476
}
459477

@@ -467,6 +485,7 @@ int pthread_join(pthread_t thread, void **status)
467485
*/
468486
int pthread_detach(pthread_t thread)
469487
{
488+
bool join = false;
470489
struct posix_thread *pthread = to_posix_thread(thread);
471490
int ret = 0;
472491

@@ -485,10 +504,7 @@ int pthread_detach(pthread_t thread)
485504
pthread_cond_broadcast(&pthread->state_cond);
486505
break;
487506
case PTHREAD_EXITED:
488-
pthread->state = PTHREAD_TERMINATED;
489-
/* THREAD has already exited.
490-
* Pthread remained to provide exit status.
491-
*/
507+
join = true;
492508
break;
493509
case PTHREAD_TERMINATED:
494510
ret = ESRCH;
@@ -499,6 +515,11 @@ int pthread_detach(pthread_t thread)
499515
}
500516

501517
pthread_mutex_unlock(&pthread->state_lock);
518+
519+
if (join) {
520+
pthread_join(thread, NULL);
521+
}
522+
502523
return ret;
503524
}
504525

@@ -718,7 +739,7 @@ static int posix_thread_pool_init(void)
718739

719740

720741
for (i = 0; i < CONFIG_MAX_PTHREAD_COUNT; ++i) {
721-
posix_thread_pool[i].state = PTHREAD_EXITED;
742+
posix_thread_pool[i].state = PTHREAD_TERMINATED;
722743
}
723744

724745
return 0;

0 commit comments

Comments
 (0)