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 <clamattia@gmail.com>
This commit is contained in:
Cla Galliard 2024-05-13 08:22:51 +02:00 committed by Benjamin Cabé
commit a71e0f2a29
2 changed files with 55 additions and 8 deletions

View file

@ -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);

View file

@ -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.
*