git: afa70a8496e9 - main - libthr: add pthread_tryjoin_np()

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 19 Jan 2026 16:57:16 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=afa70a8496e90fa751418be8d1b55e3d559a281a

commit afa70a8496e90fa751418be8d1b55e3d559a281a
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-01-18 12:26:46 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-01-19 16:49:57 +0000

    libthr: add pthread_tryjoin_np()
    
    Similar to the same glibc function.
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D54766
---
 include/pthread_np.h         |  1 +
 lib/libthr/pthread.map       |  4 ++++
 lib/libthr/thread/thr_join.c | 55 +++++++++++++++++++++++++++++++++-----------
 3 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/include/pthread_np.h b/include/pthread_np.h
index a9e738540db4..04c64a748b72 100644
--- a/include/pthread_np.h
+++ b/include/pthread_np.h
@@ -65,6 +65,7 @@ int pthread_single_np(void);
 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
index 3a5353a32dc3..ad0c28de98c1 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -342,3 +342,7 @@ FBSD_1.8 {
 	 pthread_signals_unblock_np;
 	 pthread_sigqueue;
 };
+
+FBSD_1.9 {
+	 pthread_tryjoin_np;
+};
diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c
index 56b316ec0f51..33eb18638169 100644
--- a/lib/libthr/thread/thr_join.c
+++ b/lib/libthr/thread/thr_join.c
@@ -34,14 +34,17 @@
 #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(struct pthread *pthread, struct pthread *curthread)
@@ -63,7 +66,7 @@ backout_join_pop(void *arg)
 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
@@ -74,13 +77,34 @@ _pthread_timedjoin_np(pthread_t pthread, void **thread_return,
 	    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)
+{
+	void *tmp;
+
+	tmp = pthread->ret;
+	pthread->flags |= THR_FLAGS_DETACHED;
+	pthread->joiner = NULL;
+	_thr_try_gc(curthread, pthread); /* thread lock released */
+
+	if (thread_return != NULL)
+		*thread_return = tmp;
 }
 
 /*
@@ -89,11 +113,10 @@ _pthread_peekjoin_np(pthread_t pthread, void **thread_return)
  */
 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;
 
@@ -127,12 +150,22 @@ join_common(pthread_t pthread, void **thread_return,
 		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);
+		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;
@@ -160,14 +193,8 @@ join_common(pthread_t pthread, void **thread_return,
 		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);
 	}
 	return (ret);
 }