Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Sep 2014 08:18:08 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r271000 - head/sys/kern
Message-ID:  <201409030818.s838I8uY084843@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Wed Sep  3 08:18:07 2014
New Revision: 271000
URL: http://svnweb.freebsd.org/changeset/base/271000

Log:
  Right now, thread_single(SINGLE_EXIT) returns after the p_numthreads
  reaches 1. The p_numthreads counter is decremented in thread_exit() by
  a call to thread_unlink(). This means that the exiting threads may
  still execute on other CPUs when thread_single(SINGLE_EXIT) returns.
  As result, vmspace could be destroyed while paging structures are
  still used on other CPUs by exiting threads.
  
  Delay the return from thread_single(SINGLE_EXIT) until all threads are
  really destroyed by thread_stash() after the last switch out. The
  p_exitthreads counter already provides the required mechanism, move
  the wait from the thread_wait() (which is called from wait(2) code)
  into thread_single().
  
  Reported by:	many (as "panic: pmap active <addr>")
  Reviewed by:	alc, jhb
  Tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week

Modified:
  head/sys/kern/kern_thread.c

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c	Wed Sep  3 08:14:07 2014	(r270999)
+++ head/sys/kern/kern_thread.c	Wed Sep  3 08:18:07 2014	(r271000)
@@ -432,6 +432,7 @@ thread_exit(void)
 	 */
 	if (p->p_flag & P_HADTHREADS) {
 		if (p->p_numthreads > 1) {
+			atomic_add_int(&td->td_proc->p_exitthreads, 1);
 			thread_unlink(td);
 			td2 = FIRST_THREAD_IN_PROC(p);
 			sched_exit_thread(td2, td);
@@ -452,7 +453,6 @@ thread_exit(void)
 				}
 			}
 
-			atomic_add_int(&td->td_proc->p_exitthreads, 1);
 			PCPU_SET(deadthread, td);
 		} else {
 			/*
@@ -507,14 +507,12 @@ thread_wait(struct proc *p)
 	struct thread *td;
 
 	mtx_assert(&Giant, MA_NOTOWNED);
-	KASSERT((p->p_numthreads == 1), ("Multiple threads in wait1()"));
+	KASSERT((p->p_numthreads == 1), ("multiple threads in thread_wait()"));
+	KASSERT((p->p_exitthreads == 0), ("p_exitthreads leaking"));
 	td = FIRST_THREAD_IN_PROC(p);
 	/* Lock the last thread so we spin until it exits cpu_throw(). */
 	thread_lock(td);
 	thread_unlock(td);
-	/* Wait for any remaining threads to exit cpu_throw(). */
-	while (p->p_exitthreads)
-		sched_relinquish(curthread);
 	lock_profile_thread_exit(td);
 	cpuset_rel(td->td_cpuset);
 	td->td_cpuset = NULL;
@@ -722,6 +720,17 @@ stopme:
 		p->p_singlethread = NULL;
 		p->p_flag &= ~(P_STOPPED_SINGLE | P_SINGLE_EXIT);
 		thread_unthread(td);
+
+		/*
+		 * Wait for any remaining threads to exit cpu_throw().
+		 */
+		while (p->p_exitthreads != 0) {
+			PROC_SUNLOCK(p);
+			PROC_UNLOCK(p);
+			sched_relinquish(td);
+			PROC_LOCK(p);
+			PROC_SLOCK(p);
+		}
 	}
 	PROC_SUNLOCK(p);
 	return (0);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409030818.s838I8uY084843>