From a71e0f2a29333c7b1464b2ebd624b87eeb488da8 Mon Sep 17 00:00:00 2001 From: Cla Galliard Date: Mon, 13 May 2024 08:22:51 +0200 Subject: [PATCH] posix: pthread: implement non-standard try-join and timed-join 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 --- include/zephyr/posix/pthread.h | 2 ++ lib/posix/options/pthread.c | 61 +++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 4a5e7046f17..685a8d9a931 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -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); diff --git a/lib/posix/options/pthread.c b/lib/posix/options/pthread.c index 4ee2851dcdb..c54a061f9e7 100644 --- a/lib/posix/options/pthread.c +++ b/lib/posix/options/pthread.c @@ -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]), @@ -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; @@ -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); @@ -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. *