Add pthread_peekjoin_np(3).

The function allows to peek at the thread exit status and even see
return value, without joining (and thus finally destroying) the target
thread.

Reviewed by:	markj
Sponsored by:	The FreeBSD Foundation (kib)
MFC after:	2 weeks
Differential revision:	https://reviews.freebsd.org/D23676
This commit is contained in:
Konstantin Belousov 2020-02-15 23:25:39 +00:00
parent a7b61c0af1
commit 132fb3dc99
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=357985
5 changed files with 77 additions and 19 deletions

View file

@ -63,6 +63,7 @@ int pthread_mutex_setyieldloops_np(pthread_mutex_t *mutex, int count);
int pthread_mutex_isowned_np(pthread_mutex_t *mutex);
void pthread_resume_all_np(void);
int pthread_resume_np(pthread_t);
int pthread_peekjoin_np(pthread_t, void **);
void pthread_set_name_np(pthread_t, const char *);
int pthread_setaffinity_np(pthread_t, size_t, const cpuset_t *);
int pthread_single_np(void);

View file

@ -326,3 +326,7 @@ FBSD_1.4 {
FBSD_1.5 {
pthread_get_name_np;
};
FBSD_1.6 {
pthread_peekjoin_np;
};

View file

@ -36,13 +36,15 @@ __FBSDID("$FreeBSD$");
#include "thr_private.h"
int _pthread_peekjoin_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 *);
const struct timespec *abstime);
static int join_common(pthread_t, void **, const struct timespec *, bool peek);
__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);
static void backout_join(void *arg)
{
@ -57,7 +59,7 @@ static void backout_join(void *arg)
int
_thr_join(pthread_t pthread, void **thread_return)
{
return (join_common(pthread, thread_return, NULL));
return (join_common(pthread, thread_return, NULL, false));
}
int
@ -68,7 +70,13 @@ _pthread_timedjoin_np(pthread_t pthread, void **thread_return,
abstime->tv_nsec >= 1000000000)
return (EINVAL);
return (join_common(pthread, thread_return, abstime));
return (join_common(pthread, thread_return, abstime, false));
}
int
_pthread_peekjoin_np(pthread_t pthread, void **thread_return)
{
return (join_common(pthread, thread_return, NULL, true));
}
/*
@ -77,13 +85,13 @@ _pthread_timedjoin_np(pthread_t pthread, void **thread_return,
*/
static int
join_common(pthread_t pthread, void **thread_return,
const struct timespec *abstime)
const struct timespec *abstime, bool peek)
{
struct pthread *curthread = _get_curthread();
struct timespec ts, ts2, *tsp;
void *tmp;
long tid;
int ret = 0;
int ret;
if (pthread == NULL)
return (EINVAL);
@ -100,10 +108,21 @@ join_common(pthread_t pthread, void **thread_return,
/* Multiple joiners are not supported. */
ret = ENOTSUP;
}
if (ret) {
if (ret != 0) {
THR_THREAD_UNLOCK(curthread, pthread);
return (ret);
}
/* Only peek into status, do not gc the thread. */
if (peek) {
if (pthread->tid != TID_TERMINATED)
ret = EBUSY;
else if (thread_return != NULL)
*thread_return = pthread->ret;
THR_THREAD_UNLOCK(curthread, pthread);
return (ret);
}
/* Set the running thread to be the joiner: */
pthread->joiner = curthread;

View file

@ -500,7 +500,8 @@ PTHREAD_MLINKS+=pthread_spin_init.3 pthread_spin_destroy.3 \
PTHREAD_MLINKS+=pthread_switch_add_np.3 pthread_switch_delete_np.3
PTHREAD_MLINKS+=pthread_testcancel.3 pthread_setcancelstate.3 \
pthread_testcancel.3 pthread_setcanceltype.3
PTHREAD_MLINKS+=pthread_join.3 pthread_timedjoin_np.3
PTHREAD_MLINKS+=pthread_join.3 pthread_peekjoin_np.3 \
pthread_join.3 pthread_timedjoin_np.3
.endif
.include <bsd.prog.mk>

View file

@ -30,13 +30,14 @@
.\"
.\" $FreeBSD$
.\"
.Dd February 3, 2018
.Dd February 13, 2019
.Dt PTHREAD_JOIN 3
.Os
.Sh NAME
.Nm pthread_join ,
.Nm pthread_peekjoin_np ,
.Nm pthread_timedjoin_np
.Nd wait for thread termination
.Nd inspect thread termination state
.Sh LIBRARY
.Lb libpthread
.Sh SYNOPSIS
@ -45,7 +46,16 @@
.Fn pthread_join "pthread_t thread" "void **value_ptr"
.In pthread_np.h
.Ft int
.Fn pthread_timedjoin_np "pthread_t thread" "void **value_ptr" "const struct timespec *abstime"
.Fo pthread_peekjoin_np
.Fa "pthread_t thread"
.Fa "void **value_ptr"
.Fc
.Ft int
.Fo pthread_timedjoin_np
.Fa "pthread_t thread"
.Fa "void **value_ptr"
.Fa "const struct timespec *abstime"
.Fc
.Sh DESCRIPTION
The
.Fn pthread_join
@ -82,19 +92,30 @@ function except it will return
.Er ETIMEDOUT
if target thread does not exit before specified absolute time passes.
.Pp
The
.Fn pthread_peekjoin_np
only peeks into the exit status of the specified thread.
If the thread has not exited, the
.Er EBUSY
error is returned.
Otherwise, zero is returned and the thread exit value is optionally stored
into the location of
.Fa *value_ptr .
The target thread is left unjoined and can be used as an argument for
the
.Fn pthread_join
family of functions again.
.Pp
A thread that has exited but remains unjoined counts against
[_POSIX_THREAD_THREADS_MAX].
.Sh RETURN VALUES
If successful, the
.Fn pthread_join
and
.Fn pthread_timedjoin_np
functions will return zero.
Otherwise an error number will be returned to
indicate the error.
If successful, the described functions return zero.
Otherwise an error number is returned to indicate the error or
special condition.
.Sh ERRORS
The
.Fn pthread_join
.Fn pthread_join ,
.Fn pthread_peekjoin_np ,
and
.Fn pthread_timedjoin_np
functions will fail if:
@ -125,6 +146,14 @@ The specified absolute time passed while
.Fn pthread_timedjoin_np
waited for thread exit.
.El
.Pp
The
.Fn pthread_peekjoin_np
function will also fail if:
.Bl -tag -width Er
.It Bq Er EBUSY
The specified thread has not yet exited.
.El
.Sh SEE ALSO
.Xr wait 2 ,
.Xr pthread_create 3
@ -139,3 +168,7 @@ function is a
.Fx
extension which first appeared in
.Fx 6.1 .
Another extension, the
.Fn pthread_peekjoin_np
function, first appearead in
.Fx 13.0 .