Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142345997
D54766.id170008.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D54766.id170008.diff
View Options
diff --git a/include/pthread_np.h b/include/pthread_np.h
--- a/include/pthread_np.h
+++ b/include/pthread_np.h
@@ -65,6 +65,7 @@
void pthread_suspend_all_np(void);
int pthread_suspend_np(pthread_t);
int pthread_timedjoin_np(pthread_t, void **, const struct timespec *);
+int pthread_tryjoin_np(pthread_t, void **);
__END_DECLS
#endif
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -342,3 +342,7 @@
pthread_signals_unblock_np;
pthread_sigqueue;
};
+
+FBSD_1.9 {
+ pthread_tryjoin_np;
+};
diff --git a/lib/libthr/tests/Makefile b/lib/libthr/tests/Makefile
--- a/lib/libthr/tests/Makefile
+++ b/lib/libthr/tests/Makefile
@@ -36,6 +36,7 @@
ATF_TESTS_C+= atfork_test
ATF_TESTS_C+= umtx_op_test
ATF_TESTS_C+= pthread_sigqueue_test
+ATF_TESTS_C+= pthread_tryjoin_test
LIBADD+= pthread
LIBADD.fpu_test+= m
diff --git a/lib/libthr/tests/pthread_tryjoin_test.c b/lib/libthr/tests/pthread_tryjoin_test.c
new file mode 100644
--- /dev/null
+++ b/lib/libthr/tests/pthread_tryjoin_test.c
@@ -0,0 +1,62 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2025 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+
+#include <atf-c.h>
+#include <err.h>
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdatomic.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static atomic_int finish;
+
+static void *
+thr_fun(void *arg)
+{
+ while (atomic_load_explicit(&finish, memory_order_relaxed) != 1)
+ sleep(1);
+ atomic_store_explicit(&finish, 2, memory_order_relaxed);
+ return (arg);
+}
+
+ATF_TC(pthread_tryjoin);
+ATF_TC_HEAD(pthread_tryjoin, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks pthread_tryjoin(3)");
+}
+
+ATF_TC_BODY(pthread_tryjoin, tc)
+{
+ pthread_t thr;
+ void *retval;
+ int error, x;
+
+ error = pthread_create(&thr, NULL, thr_fun, &x);
+ ATF_REQUIRE_EQ(error, 0);
+
+ error = pthread_tryjoin_np(thr, &retval);
+ ATF_REQUIRE_EQ(error, EBUSY);
+
+ atomic_store_explicit(&finish, 1, memory_order_relaxed);
+ while (atomic_load_explicit(&finish, memory_order_relaxed) != 2)
+ sleep(1);
+
+ error = pthread_tryjoin_np(thr, &retval);
+ ATF_REQUIRE_EQ(error, 0);
+ ATF_REQUIRE_EQ(retval, &x);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, pthread_tryjoin);
+ return (atf_no_error());
+}
diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c
--- a/lib/libthr/thread/thr_join.c
+++ b/lib/libthr/thread/thr_join.c
@@ -34,29 +34,39 @@
#include "thr_private.h"
int _pthread_peekjoin_np(pthread_t pthread, void **thread_return);
+int _pthread_tryjoin_np(pthread_t pthread, void **thread_return);
int _pthread_timedjoin_np(pthread_t pthread, void **thread_return,
const struct timespec *abstime);
-static int join_common(pthread_t, void **, const struct timespec *, bool peek);
+static int join_common(pthread_t, void **, const struct timespec *, bool peek,
+ bool try);
__weak_reference(_thr_join, pthread_join);
__weak_reference(_thr_join, _pthread_join);
__weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np);
__weak_reference(_pthread_peekjoin_np, pthread_peekjoin_np);
+__weak_reference(_pthread_tryjoin_np, pthread_tryjoin_np);
-static void backout_join(void *arg)
+static void
+backout_join(struct pthread *pthread, struct pthread *curthread)
{
- struct pthread *pthread = (struct pthread *)arg;
- struct pthread *curthread = _get_curthread();
-
THR_THREAD_LOCK(curthread, pthread);
pthread->joiner = NULL;
THR_THREAD_UNLOCK(curthread, pthread);
}
+static void
+backout_join_pop(void *arg)
+{
+ struct pthread *pthread = (struct pthread *)arg;
+ struct pthread *curthread = _get_curthread();
+
+ backout_join(pthread, curthread);
+}
+
int
_thr_join(pthread_t pthread, void **thread_return)
{
- return (join_common(pthread, thread_return, NULL, false));
+ return (join_common(pthread, thread_return, NULL, false, false));
}
int
@@ -67,13 +77,36 @@
abstime->tv_nsec >= 1000000000)
return (EINVAL);
- return (join_common(pthread, thread_return, abstime, false));
+ return (join_common(pthread, thread_return, abstime, false, false));
}
int
_pthread_peekjoin_np(pthread_t pthread, void **thread_return)
{
- return (join_common(pthread, thread_return, NULL, true));
+ return (join_common(pthread, thread_return, NULL, true, false));
+}
+
+int
+_pthread_tryjoin_np(pthread_t pthread, void **thread_return)
+{
+ return (join_common(pthread, thread_return, NULL, false, true));
+}
+
+static void
+join_common_joined(struct pthread *pthread, struct pthread *curthread,
+ void **thread_return, bool thr_locked)
+{
+ void *tmp;
+
+ tmp = pthread->ret;
+ if (!thr_locked)
+ THR_THREAD_LOCK(curthread, pthread);
+ pthread->flags |= THR_FLAGS_DETACHED;
+ pthread->joiner = NULL;
+ _thr_try_gc(curthread, pthread); /* thread lock released */
+
+ if (thread_return != NULL)
+ *thread_return = tmp;
}
/*
@@ -82,11 +115,10 @@
*/
static int
join_common(pthread_t pthread, void **thread_return,
- const struct timespec *abstime, bool peek)
+ const struct timespec *abstime, bool peek, bool try)
{
struct pthread *curthread = _get_curthread();
struct timespec ts, ts2, *tsp;
- void *tmp;
long tid;
int ret;
@@ -120,12 +152,22 @@
return (ret);
}
+ /* Only try to join. */
+ if (try) {
+ if (pthread->tid != TID_TERMINATED) {
+ THR_THREAD_UNLOCK(curthread, pthread);
+ return (EBUSY);
+ }
+ join_common_joined(pthread, curthread, thread_return, true);
+ return (0);
+ }
+
/* Set the running thread to be the joiner: */
pthread->joiner = curthread;
THR_THREAD_UNLOCK(curthread, pthread);
- THR_CLEANUP_PUSH(curthread, backout_join, pthread);
+ THR_CLEANUP_PUSH(curthread, backout_join_pop, pthread);
_thr_cancel_enter(curthread);
tid = pthread->tid;
@@ -149,20 +191,11 @@
_thr_cancel_leave(curthread, 0);
THR_CLEANUP_POP(curthread, 0);
- if (ret == ETIMEDOUT) {
- THR_THREAD_LOCK(curthread, pthread);
- pthread->joiner = NULL;
- THR_THREAD_UNLOCK(curthread, pthread);
+ if (ret == ETIMEDOUT || ret == EBUSY) {
+ backout_join(pthread, curthread);
} else {
ret = 0;
- tmp = pthread->ret;
- THR_THREAD_LOCK(curthread, pthread);
- pthread->flags |= THR_FLAGS_DETACHED;
- pthread->joiner = NULL;
- _thr_try_gc(curthread, pthread); /* thread lock released */
-
- if (thread_return != NULL)
- *thread_return = tmp;
+ join_common_joined(pthread, curthread, thread_return, false);
}
return (ret);
}
diff --git a/share/man/man3/Makefile b/share/man/man3/Makefile
--- a/share/man/man3/Makefile
+++ b/share/man/man3/Makefile
@@ -540,6 +540,7 @@
PTHREAD_MLINKS+=pthread_testcancel.3 pthread_setcancelstate.3 \
pthread_testcancel.3 pthread_setcanceltype.3
PTHREAD_MLINKS+=pthread_join.3 pthread_peekjoin_np.3 \
- pthread_join.3 pthread_timedjoin_np.3
+ pthread_join.3 pthread_timedjoin_np.3 \
+ pthread_join.3 pthread_tryjoin_np.3
.include <bsd.prog.mk>
diff --git a/share/man/man3/pthread_join.3 b/share/man/man3/pthread_join.3
--- a/share/man/man3/pthread_join.3
+++ b/share/man/man3/pthread_join.3
@@ -35,6 +35,7 @@
.Nm pthread_join ,
.Nm pthread_peekjoin_np ,
.Nm pthread_timedjoin_np
+.Nm pthread_tryjoin_np
.Nd inspect thread termination state
.Sh LIBRARY
.Lb libpthread
@@ -54,6 +55,8 @@
.Fa "void **value_ptr"
.Fa "const struct timespec *abstime"
.Fc
+.Ft int
+.Fn pthread_tryjoin_np "pthread_t thread" "void **value_ptr"
.Sh DESCRIPTION
The
.Fn pthread_join
@@ -104,6 +107,13 @@
.Fn pthread_join
family of functions again.
.Pp
+The
+.Fn pthread_tryjoin_np
+joins the thread if it is already terminated, same as
+.Fn pthread_join.
+If the thread did not yet terminated, the function returns
+.Er EBUSY .
+.Pp
A thread that has exited but remains unjoined counts against
[_POSIX_THREAD_THREADS_MAX].
.Sh RETURN VALUES
@@ -147,7 +157,9 @@
.Pp
The
.Fn pthread_peekjoin_np
-function will also fail if:
+and
+.Fn pthread_tryjoin_np
+functions will also fail if:
.Bl -tag -width Er
.It Bq Er EBUSY
The specified thread has not yet exited.
@@ -168,7 +180,15 @@
.Fx
extension which first appeared in
.Fx 6.1 .
-Another extension, the
+The
.Fn pthread_peekjoin_np
-function, first appearead in
+function is a
+.Fx
+extension which first appearead in
.Fx 13.0 .
+The
+.Fn pthread_tryjoin_np
+function is a
+.Fx
+extension which first appearead in
+.Fx 16.0 .
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 19, 8:49 PM (2 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27753371
Default Alt Text
D54766.id170008.diff (8 KB)
Attached To
Mode
D54766: Add pthread_tryjoin_np(3) as provided by glibc
Attached
Detach File
Event Timeline
Log In to Comment