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 <[email protected]>
This commit is contained in:
Augustin Cavalier
2024-07-16 19:59:39 +00:00
committed by waddlesplash
parent 69b420563b
commit 9a4c543934
2 changed files with 48 additions and 16 deletions
+2
View File
@@ -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_getname_np(pthread_t thread, char* buffer, size_t length);
extern int pthread_setname_np(pthread_t thread, const char* name); 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_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); extern int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpuset_t* mask);
+46 -16
View File
@@ -19,6 +19,7 @@
#include <libroot_private.h> #include <libroot_private.h>
#include <syscalls.h> #include <syscalls.h>
#include <thread_defs.h> #include <thread_defs.h>
#include <time_private.h>
#include <tls.h> #include <tls.h>
#include <user_thread.h> #include <user_thread.h>
@@ -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 // #pragma mark - public API
@@ -199,22 +226,7 @@ pthread_equal(pthread_t t1, pthread_t t2)
int int
pthread_join(pthread_t thread, void** _value) pthread_join(pthread_t thread, void** _value)
{ {
status_t dummy; return __pthread_join(thread, _value);
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);
} }
@@ -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 // #pragma mark - Haiku thread API bridge