Page MenuHomeFreeBSD

D54766.id170008.diff
No OneTemporary

D54766.id170008.diff

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

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)

Event Timeline