diff options
author | davidxu <davidxu@FreeBSD.org> | 2005-10-04 06:15:25 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2005-10-04 06:15:25 +0000 |
commit | 6459dc5d9d0ec1b437d561a2038a1e4f053df2af (patch) | |
tree | 467a22e42b028df8d861fa91c891834e7deb9e4c /lib/libthr/thread/thr_join.c | |
parent | e3843610ee40a003342b7024d661837ba52cc19d (diff) | |
download | FreeBSD-src-6459dc5d9d0ec1b437d561a2038a1e4f053df2af.zip FreeBSD-src-6459dc5d9d0ec1b437d561a2038a1e4f053df2af.tar.gz |
Add function pthread_timedjoin_np, the function is similar with pthread_join
except the function will return ETIMEDOUT if target thread does not exit
before specified absolute time passes.
Diffstat (limited to 'lib/libthr/thread/thr_join.c')
-rw-r--r-- | lib/libthr/thread/thr_join.c | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c index c44b261..81c210d 100644 --- a/lib/libthr/thread/thr_join.c +++ b/lib/libthr/thread/thr_join.c @@ -37,7 +37,10 @@ #include "thr_private.h" +static int join_common(pthread_t, void **, const struct timespec *); + __weak_reference(_pthread_join, pthread_join); +__weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np); static void backout_join(void *arg) { @@ -52,7 +55,26 @@ static void backout_join(void *arg) int _pthread_join(pthread_t pthread, void **thread_return) { + return (join_common(pthread, thread_return, NULL)); +} + +int +_pthread_timedjoin_np(pthread_t pthread, void **thread_return, + const struct timespec *abstime) +{ + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000) + return (EINVAL); + + return (join_common(pthread, thread_return, abstime)); +} + +static int +join_common(pthread_t pthread, void **thread_return, + const struct timespec *abstime) +{ struct pthread *curthread = _get_curthread(); + struct timespec ts, ts2, *tsp; void *tmp; long state; int oldcancel; @@ -86,20 +108,38 @@ _pthread_join(pthread_t pthread, void **thread_return) oldcancel = _thr_cancel_enter(curthread); while ((state = pthread->state) != PS_DEAD) { - _thr_umtx_wait(&pthread->state, state, NULL); + if (abstime != NULL) { + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + if (ts2.tv_sec < 0) { + ret = ETIMEDOUT; + break; + } + tsp = &ts2; + } else + tsp = NULL; + ret = _thr_umtx_wait(&pthread->state, state, tsp); + if (ret == ETIMEDOUT) + break; } _thr_cancel_leave(curthread, oldcancel); THR_CLEANUP_POP(curthread, 0); - tmp = pthread->ret; - THREAD_LIST_LOCK(curthread); - pthread->tlflags |= TLFLAGS_DETACHED; - THR_GCLIST_ADD(pthread); - THREAD_LIST_UNLOCK(curthread); - - if (thread_return != NULL) - *thread_return = tmp; + if (ret == ETIMEDOUT) { + THREAD_LIST_LOCK(curthread); + pthread->joiner = NULL; + THREAD_LIST_UNLOCK(curthread); + } else { + tmp = pthread->ret; + THREAD_LIST_LOCK(curthread); + pthread->tlflags |= TLFLAGS_DETACHED; + pthread->joiner = NULL; + THR_GCLIST_ADD(pthread); + THREAD_LIST_UNLOCK(curthread); + if (thread_return != NULL) + *thread_return = tmp; + } return (ret); } |