Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libthr/thread/thr_join.c
Show All 30 Lines | |||||
#include "namespace.h" | #include "namespace.h" | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include "un-namespace.h" | #include "un-namespace.h" | ||||
#include "thr_private.h" | #include "thr_private.h" | ||||
int _pthread_peekjoin_np(pthread_t pthread, void **thread_return); | |||||
int _pthread_timedjoin_np(pthread_t pthread, void **thread_return, | int _pthread_timedjoin_np(pthread_t pthread, void **thread_return, | ||||
const struct timespec *abstime); | const struct timespec *abstime); | ||||
static int join_common(pthread_t, void **, const struct timespec *); | 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(_thr_join, _pthread_join); | __weak_reference(_thr_join, _pthread_join); | ||||
__weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np); | __weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np); | ||||
__weak_reference(_pthread_peekjoin_np, pthread_peekjoin_np); | |||||
static void backout_join(void *arg) | static void backout_join(void *arg) | ||||
{ | { | ||||
struct pthread *pthread = (struct pthread *)arg; | struct pthread *pthread = (struct pthread *)arg; | ||||
struct pthread *curthread = _get_curthread(); | struct pthread *curthread = _get_curthread(); | ||||
THR_THREAD_LOCK(curthread, pthread); | THR_THREAD_LOCK(curthread, pthread); | ||||
pthread->joiner = NULL; | pthread->joiner = NULL; | ||||
THR_THREAD_UNLOCK(curthread, pthread); | THR_THREAD_UNLOCK(curthread, pthread); | ||||
} | } | ||||
int | int | ||||
_thr_join(pthread_t pthread, void **thread_return) | _thr_join(pthread_t pthread, void **thread_return) | ||||
{ | { | ||||
return (join_common(pthread, thread_return, NULL)); | return (join_common(pthread, thread_return, NULL, false)); | ||||
} | } | ||||
int | int | ||||
_pthread_timedjoin_np(pthread_t pthread, void **thread_return, | _pthread_timedjoin_np(pthread_t pthread, void **thread_return, | ||||
const struct timespec *abstime) | const struct timespec *abstime) | ||||
{ | { | ||||
if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || | if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || | ||||
abstime->tv_nsec >= 1000000000) | abstime->tv_nsec >= 1000000000) | ||||
return (EINVAL); | 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)); | |||||
} | |||||
/* | /* | ||||
* Cancellation behavior: | * Cancellation behavior: | ||||
* if the thread is canceled, joinee is not recycled. | * if the thread is canceled, joinee is not recycled. | ||||
*/ | */ | ||||
static int | static int | ||||
join_common(pthread_t pthread, void **thread_return, | join_common(pthread_t pthread, void **thread_return, | ||||
const struct timespec *abstime) | const struct timespec *abstime, bool peek) | ||||
{ | { | ||||
struct pthread *curthread = _get_curthread(); | struct pthread *curthread = _get_curthread(); | ||||
struct timespec ts, ts2, *tsp; | struct timespec ts, ts2, *tsp; | ||||
void *tmp; | void *tmp; | ||||
long tid; | long tid; | ||||
int ret = 0; | int ret; | ||||
if (pthread == NULL) | if (pthread == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (pthread == curthread) | if (pthread == curthread) | ||||
return (EDEADLK); | return (EDEADLK); | ||||
if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) | if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) | ||||
return (ESRCH); | return (ESRCH); | ||||
if ((pthread->flags & THR_FLAGS_DETACHED) != 0) { | if ((pthread->flags & THR_FLAGS_DETACHED) != 0) { | ||||
ret = EINVAL; | ret = EINVAL; | ||||
} else if (pthread->joiner != NULL) { | } else if (pthread->joiner != NULL) { | ||||
/* Multiple joiners are not supported. */ | /* Multiple joiners are not supported. */ | ||||
ret = ENOTSUP; | ret = ENOTSUP; | ||||
} | } | ||||
if (ret) { | if (ret != 0) { | ||||
THR_THREAD_UNLOCK(curthread, pthread); | THR_THREAD_UNLOCK(curthread, pthread); | ||||
return (ret); | 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: */ | /* Set the running thread to be the joiner: */ | ||||
pthread->joiner = curthread; | pthread->joiner = curthread; | ||||
THR_THREAD_UNLOCK(curthread, pthread); | THR_THREAD_UNLOCK(curthread, pthread); | ||||
THR_CLEANUP_PUSH(curthread, backout_join, pthread); | THR_CLEANUP_PUSH(curthread, backout_join, pthread); | ||||
_thr_cancel_enter(curthread); | _thr_cancel_enter(curthread); | ||||
Show All 38 Lines |