From 9a4c54393497beed640e98f5a7a5fe747741c3db Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 15 Jul 2024 22:16:01 -0400 Subject: [PATCH] pthread: Implement pthread_timedjoin_np. This also corrects an oversight in pthread_join() that not all potential error codes of wait_for_thread were accounted for (in particular EDEADLK wasn't.) This is a non-standard extension, but is present on both Linux and FreeBSD, at least. Change-Id: Ie96e7a261e863ab491bee30349360df7ff3d0e80 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5099 Reviewed-by: waddlesplash --- headers/compatibility/gnu/pthread.h | 2 + src/system/libroot/posix/pthread/pthread.cpp | 62 +++++++++++++++----- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/headers/compatibility/gnu/pthread.h b/headers/compatibility/gnu/pthread.h index c1f4db958d..7c74a717a7 100644 --- a/headers/compatibility/gnu/pthread.h +++ b/headers/compatibility/gnu/pthread.h @@ -25,6 +25,8 @@ extern int pthread_getattr_np(pthread_t thread, pthread_attr_t* attr); extern int pthread_getname_np(pthread_t thread, char* buffer, size_t length); extern int pthread_setname_np(pthread_t thread, const char* name); +extern int pthread_timedjoin_np(pthread_t thread, void** _value, const struct timespec* abstime); + extern int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpuset_t* mask); extern int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpuset_t* mask); diff --git a/src/system/libroot/posix/pthread/pthread.cpp b/src/system/libroot/posix/pthread/pthread.cpp index b97483f69b..990421623a 100644 --- a/src/system/libroot/posix/pthread/pthread.cpp +++ b/src/system/libroot/posix/pthread/pthread.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -141,6 +142,32 @@ __pthread_set_default_priority(int32 priority) } +static int +__pthread_join(pthread_t thread, void** _value, int flags = 0, bigtime_t timeout = 0) +{ + status_t status; + do { + status_t dummy; + status = wait_for_thread_etc(thread->id, flags, timeout, &dummy); + } while (status == B_INTERRUPTED); + + if (status == B_BAD_THREAD_ID) + RETURN_AND_TEST_CANCEL(ESRCH); + if (status == B_WOULD_BLOCK || status == B_TIMED_OUT) + RETURN_AND_TEST_CANCEL(ETIMEDOUT); + if (status < B_OK) + RETURN_AND_TEST_CANCEL(status); + + if (_value != NULL) + *_value = thread->exit_value; + + if ((atomic_or(&thread->flags, THREAD_DETACHED) & THREAD_DEAD) != 0) + free(thread); + + RETURN_AND_TEST_CANCEL(B_OK); +} + + // #pragma mark - public API @@ -199,22 +226,7 @@ pthread_equal(pthread_t t1, pthread_t t2) int pthread_join(pthread_t thread, void** _value) { - status_t dummy; - status_t error; - do { - error = wait_for_thread(thread->id, &dummy); - } while (error == B_INTERRUPTED); - - if (error == B_BAD_THREAD_ID) - RETURN_AND_TEST_CANCEL(ESRCH); - - if (_value != NULL) - *_value = thread->exit_value; - - if ((atomic_or(&thread->flags, THREAD_DETACHED) & THREAD_DEAD) != 0) - free(thread); - - RETURN_AND_TEST_CANCEL(error); + return __pthread_join(thread, _value); } @@ -346,6 +358,24 @@ pthread_setname_np(pthread_t thread, const char* name) } +extern "C" int +pthread_timedjoin_np(pthread_t thread, void** _value, const struct timespec* abstime) +{ + int flags = 0; + bigtime_t timeout = 0; + if (abstime != NULL) { + if (!timespec_to_bigtime(*abstime, timeout)) + RETURN_AND_TEST_CANCEL(EINVAL); + flags |= B_ABSOLUTE_REAL_TIME_TIMEOUT; + } else { + timeout = 0; + flags |= B_RELATIVE_TIMEOUT; + } + + return __pthread_join(thread, _value, flags, timeout); +} + + // #pragma mark - Haiku thread API bridge