diff options
-rw-r--r-- | lib/libthr/pthread.map | 2 | ||||
-rw-r--r-- | lib/libthr/thread/thr_join.c | 58 |
2 files changed, 51 insertions, 9 deletions
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map index 3cb7a38..b76a88e 100644 --- a/lib/libthr/pthread.map +++ b/lib/libthr/pthread.map @@ -91,6 +91,7 @@ global: _pthread_getschedparam; _pthread_getspecific; _pthread_join; + _pthread_timedjoin_np; _pthread_key_create; _pthread_key_delete; _pthread_kill; @@ -246,6 +247,7 @@ global: pthread_getschedparam; pthread_getspecific; pthread_join; + pthread_timedjoin_np; pthread_key_create; pthread_key_delete; pthread_kill; 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); } |