Skip to content

Commit

Permalink
posix: pthread: implement non-standard try-join and timed-join
Browse files Browse the repository at this point in the history
These functions can be used to join pthreads in a non-standard way.
The function pthread_tryjoin will not block and simply test whether the
thread has exited already. The function pthread_timed_join will only block
until the specified time. The functions are wrappers for calling the
k_thread_join with timeout K_NO_WAIT and with a specific timeout as opposed
to calling it with K_FOREVER.

Signed-off-by: Cla Galliard <[email protected]>
  • Loading branch information
ClaCodes authored and kartben committed Dec 15, 2024
1 parent 7bfd5c0 commit a71e0f2
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 8 deletions.
2 changes: 2 additions & 0 deletions include/zephyr/posix/pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
int pthread_once(pthread_once_t *once, void (*initFunc)(void));
#endif
FUNC_NORETURN void pthread_exit(void *retval);
int pthread_timedjoin_np(pthread_t thread, void **status, const struct timespec *abstime);
int pthread_tryjoin_np(pthread_t thread, void **status);
int pthread_join(pthread_t thread, void **status);
int pthread_cancel(pthread_t pthread);
int pthread_detach(pthread_t thread);
Expand Down
61 changes: 53 additions & 8 deletions lib/posix/options/pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ BUILD_ASSERT((PTHREAD_CANCEL_ENABLE == 0 || PTHREAD_CANCEL_DISABLE == 0) &&
BUILD_ASSERT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS + CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS <=
32);

int64_t timespec_to_timeoutms(const struct timespec *abstime);
static void posix_thread_recycle(void);
static sys_dlist_t posix_thread_q[] = {
SYS_DLIST_STATIC_INIT(&posix_thread_q[POSIX_THREAD_READY_Q]),
Expand Down Expand Up @@ -1061,12 +1062,7 @@ void pthread_exit(void *retval)
CODE_UNREACHABLE;
}

/**
* @brief Wait for a thread termination.
*
* See IEEE 1003.1
*/
int pthread_join(pthread_t pthread, void **status)
static int pthread_timedjoin_internal(pthread_t pthread, void **status, k_timeout_t timeout)
{
int ret = ESRCH;
struct posix_thread *t = NULL;
Expand Down Expand Up @@ -1115,8 +1111,19 @@ int pthread_join(pthread_t pthread, void **status)
break;
}

ret = k_thread_join(&t->thread, K_FOREVER);
/* other possibilities? */
ret = k_thread_join(&t->thread, timeout);
if (ret != 0) {
/* when joining failed, ensure that the thread can be joined later */
SYS_SEM_LOCK(&pthread_pool_lock) {
t->attr.detachstate = PTHREAD_CREATE_JOINABLE;
}
}
if (ret == -EBUSY) {
return EBUSY;
} else if (ret == -EAGAIN) {
return ETIMEDOUT;
}
/* Can only be ok or -EDEADLK, which should never occur for pthreads */
__ASSERT_NO_MSG(ret == 0);

LOG_DBG("Joined pthread %p", &t->thread);
Expand All @@ -1131,6 +1138,44 @@ int pthread_join(pthread_t pthread, void **status)
return 0;
}

/**
* @brief Await a thread termination with timeout.
*
* Non-portable GNU extension of IEEE 1003.1
*/
int pthread_timedjoin_np(pthread_t pthread, void **status, const struct timespec *abstime)
{
if (abstime == NULL) {
return EINVAL;
}

if (abstime->tv_sec < 0 || abstime->tv_nsec < 0 || abstime->tv_nsec >= NSEC_PER_SEC) {
return EINVAL;
}

return pthread_timedjoin_internal(pthread, status, K_MSEC(timespec_to_timeoutms(abstime)));
}

/**
* @brief Check a thread for termination.
*
* Non-portable GNU extension of IEEE 1003.1
*/
int pthread_tryjoin_np(pthread_t pthread, void **status)
{
return pthread_timedjoin_internal(pthread, status, K_NO_WAIT);
}

/**
* @brief Await a thread termination.
*
* See IEEE 1003.1
*/
int pthread_join(pthread_t pthread, void **status)
{
return pthread_timedjoin_internal(pthread, status, K_FOREVER);
}

/**
* @brief Detach a thread.
*
Expand Down

0 comments on commit a71e0f2

Please sign in to comment.