Skip site navigation (1)Skip section navigation (2)
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>