Date: Fri, 31 Dec 2004 14:58:08 GMT From: David Xu <davidxu@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 67980 for review Message-ID: <200412311458.iBVEw8kh009290@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=67980 Change 67980 by davidxu@davidxu_tiger on 2004/12/31 14:57:08 rework join related code. Affected files ... .. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_join.c#3 edit Differences ... ==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_join.c#3 (text+ko) ==== @@ -37,121 +37,131 @@ __weak_reference(_pthread_join, pthread_join); +static void backout_join(void *arg) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *pthread = (struct pthread *)arg; + + THREAD_LIST_LOCK(curthread); + if (_thr_find_thread(curthread, pthread, /*include dead*/1) == 0) { + if (pthread->joiner == curthread) + pthread->joiner = NULL; + } + THREAD_LIST_UNLOCK(curthread); +} + int _pthread_join(pthread_t pthread, void **thread_return) { struct pthread *curthread = _get_curthread(); void *tmp; + int oldcancel; int ret = 0; - _thr_cancel_enter(curthread); - - /* Check if the caller has specified an invalid thread: */ - if (pthread == NULL || pthread->magic != THR_MAGIC) { - /* Invalid thread: */ - _thr_cancel_leave(curthread, 1); + if (pthread == NULL) { return (EINVAL); } - /* Check if the caller has specified itself: */ if (pthread == curthread) { - /* Avoid a deadlock condition: */ - _thr_cancel_leave(curthread, 1); return (EDEADLK); } - /* - * Find the thread in the list of active threads or in the - * list of dead threads: - */ - if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) { - /* Return an error: */ - _thr_cancel_leave(curthread, 1); + THREAD_LIST_LOCK(curthread); + if ((ret = _thr_find_thread(curthread, pthread, /*include dead*/1)) != 0) { + THREAD_LIST_UNLOCK(curthread); return (ESRCH); } + /* Check if this thread has been detached. */ + if ((pthread->tlflags & TLFLAGS_DETACHED) != 0) { + THREAD_LIST_UNLOCK(curthread); + return (ESRCH); + } + THR_THREAD_LOCK(curthread, pthread); - /* Check if this thread has been detached: */ - if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { + /* Lock the target thread while checking its state. */ + if (pthread->state == PS_DEAD) { + /* Return the thread's return value. */ + tmp = pthread->ret; + THR_THREAD_UNLOCK(curthread, pthread); - /* Remove the reference and return an error: */ - _thr_ref_delete(curthread, pthread); - ret = ESRCH; - } else { - /* Lock the target thread while checking its state. */ - if (pthread->state == PS_DEAD) { - /* Return the thread's return value: */ - tmp = pthread->ret; + + /* Detach the thread. */ + pthread->tlflags |= TLFLAGS_DETACHED; + + /* + * Remove the thread from the list of active + * threads and add it to the GC list. + */ + THR_LIST_REMOVE(pthread); + THR_GCLIST_ADD(pthread); + + /* Unlock the thread list. */ + THREAD_LIST_UNLOCK(curthread); - /* Detach the thread. */ - pthread->attr.flags |= PTHREAD_DETACHED; + if (thread_return != NULL) + *thread_return = tmp; + return (0); + } + THR_THREAD_UNLOCK(curthread, pthread); - /* Unlock the thread. */ - THR_THREAD_UNLOCK(curthread, pthread); + if (pthread->joiner != NULL) { + THREAD_LIST_UNLOCK(curthread); - /* - * Remove the thread from the list of active - * threads and add it to the GC list. - */ - THR_LOCK_ACQUIRE(curthread, &_thread_list_lock); - THR_LIST_REMOVE(pthread); - THR_GCLIST_ADD(pthread); - THR_LOCK_RELEASE(curthread, &_thread_list_lock); + /* Multiple joiners are not supported. */ + return (ENOTSUP); + } - /* Remove the reference. */ - _thr_ref_delete(curthread, pthread); - if (thread_return != NULL) - *thread_return = tmp; - } - else if (pthread->joiner != NULL) { - /* Unlock the thread and remove the reference. */ - THR_THREAD_UNLOCK(curthread, pthread); - _thr_ref_delete(curthread, pthread); + /* Set the running thread to be the joiner: */ + pthread->joiner = curthread; - /* Multiple joiners are not supported. */ - ret = ENOTSUP; - } - else { - /* Set the running thread to be the joiner: */ - pthread->joiner = curthread; + /* Keep track of which thread we're joining to: */ + curthread->join_status.error = 0; + curthread->join_status.thread = pthread; - /* Keep track of which thread we're joining to: */ - curthread->join_status.thread = pthread; + THREAD_LIST_UNLOCK(curthread); - /* Unlock the thread and remove the reference. */ - THR_THREAD_UNLOCK(curthread, pthread); - _thr_ref_delete(curthread, pthread); + THR_CLEANUP_PUSH(curthread, backout_join, pthread); - THR_LOCK_SWITCH(curthread); - while (curthread->join_status.thread == pthread) { - THR_SET_STATE(curthread, PS_JOIN); - /* Schedule the next thread: */ - _thr_sched_switch_unlocked(curthread); - THR_LOCK_SWITCH(curthread); - } - THR_UNLOCK_SWITCH(curthread); + long cycle; + THR_LOCK(curthread); + while (curthread->join_status.thread == pthread) { + cycle = curthread->cycle; + THR_UNLOCK(curthread); + oldcancel = _thr_cancel_enter(curthread); + umtx_wait((struct umtx *)&curthread->cycle, cycle); + _thr_cancel_leave(curthread, oldcancel); + THR_LOCK(curthread); + } + THR_UNLOCK(curthread); + THR_CLEANUP_POP(curthread, 0); - if ((curthread->cancelflags & THR_CANCELLING) && - !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) { - if (_thr_ref_add(curthread, pthread, 1) == 0) { - THR_THREAD_LOCK(curthread, pthread); - pthread->joiner = NULL; - THR_THREAD_UNLOCK(curthread, pthread); - _thr_ref_delete(curthread, pthread); - } - pthread_exit(PTHREAD_CANCELED); + if (curthread->join_status.error == 0) { + THREAD_LIST_LOCK(curthread); + if (_thr_find_thread(curthread, pthread, /*include dead*/1) == 0) { + if (pthread->joiner == curthread) { + pthread->tlflags |= TLFLAGS_DETACHED; + /* + * Remove the thread from the list of active + * threads and add it to the GC list. + */ + THR_LIST_REMOVE(pthread); + THR_GCLIST_ADD(pthread); } - - /* - * The thread return value and error are set by the - * thread we're joining to when it exits or detaches: - */ - ret = curthread->join_status.error; - if ((ret == 0) && (thread_return != NULL)) - *thread_return = curthread->join_status.ret; + THREAD_LIST_UNLOCK(curthread); + } else { + THREAD_LIST_UNLOCK(curthread); + /* Return an error: */ + return (ESRCH); } } - _thr_cancel_leave(curthread, 1); + /* + * The thread return value and error are set by the + * thread we're joining to when it exits or detaches: + */ + ret = curthread->join_status.error; + if ((ret == 0) && (thread_return != NULL)) + *thread_return = curthread->join_status.ret; /* Return the completion status: */ return (ret);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200412311458.iBVEw8kh009290>