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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to