From 6214ede12d2e6859d24faacb590244a2d07d3807 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Fri, 20 Nov 2015 10:12:57 +0800 Subject: [PATCH] kern/lwp: Check lwp_lock before remove lwp from process lwp tree This makes sure that lwp tree iteration with blocking operation will not be broken. While I'm here, add assertion lwp_lock == 0 in lwp_dispose() --- sys/kern/kern_exit.c | 9 +++++++++ sys/kern/kern_fork.c | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 2bdecfdb0c..eb35dc4bc0 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -838,6 +838,7 @@ lwp_dispose(struct lwp *lp) struct thread *td = lp->lwp_thread; KKASSERT(lwkt_preempted_proc() != lp); + KKASSERT(lp->lwp_lock == 0); KKASSERT(td->td_refs == 0); KKASSERT((td->td_flags & (TDF_RUNNING | TDF_RUNQ | @@ -986,6 +987,14 @@ loop: * be zero. */ while ((lp = RB_ROOT(&p->p_lwp_tree)) != NULL) { + /* + * Make sure no one is using this lwp, before + * it is removed from the tree. If we didn't + * wait it here, lwp tree iteration with + * blocking operation would be broken. + */ + while (lp->lwp_lock > 0) + tsleep(lp, 0, "zomblwp", 1); lwp_rb_tree_RB_REMOVE(&p->p_lwp_tree, lp); reaplwp(lp); } diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 2717f6cd0d..f6ead9f088 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -221,6 +221,13 @@ sys_lwp_create(struct lwp_create_args *uap) return (0); fail: + /* + * Make sure no one is using this lwp, before it is removed from + * the tree. If we didn't wait it here, lwp tree iteration with + * blocking operation would be broken. + */ + while (lp->lwp_lock > 0) + tsleep(lp, 0, "lwpfail", 1); lwp_rb_tree_RB_REMOVE(&p->p_lwp_tree, lp); --p->p_nthreads; /* lwp_dispose expects an exited lwp, and a held proc */ -- 2.41.0