diff options
-rw-r--r-- | sys/kern/kern_fork.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 34 |
2 files changed, 27 insertions, 13 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 6d5f56091f2..169c7a05a64 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_fork.c,v 1.228 2020/12/02 22:35:32 mpi Exp $ */ +/* $OpenBSD: kern_fork.c,v 1.229 2020/12/04 15:16:45 mpi Exp $ */ /* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */ /* @@ -516,7 +516,7 @@ thread_fork(struct proc *curp, void *stack, void *tcb, pid_t *tidptr, struct proc *p; pid_t tid; vaddr_t uaddr; - int error; + int s, error; if (stack == NULL) return EINVAL; @@ -563,10 +563,12 @@ thread_fork(struct proc *curp, void *stack, void *tcb, pid_t *tidptr, * if somebody else wants to take us to single threaded mode, * count ourselves in. */ + SCHED_LOCK(s); if (pr->ps_single) { atomic_inc_int(&pr->ps_singlecount); atomic_setbits_int(&p->p_flag, P_SUSPSINGLE); } + SCHED_UNLOCK(s); /* * Return tid to parent thread and copy it out to userspace diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index e8453e4de71..7ebea92cee1 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.266 2020/12/02 22:35:32 mpi Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.267 2020/12/04 15:16:45 mpi Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1941,14 +1941,14 @@ userret(struct proc *p) } int -single_thread_check(struct proc *p, int deep) +single_thread_check_locked(struct proc *p, int deep, int s) { struct process *pr = p->p_p; + SCHED_ASSERT_LOCKED(); + if (pr->ps_single != NULL && pr->ps_single != p) { do { - int s; - /* if we're in deep, we need to unwind to the edge */ if (deep) { if (pr->ps_flags & PS_SINGLEUNWIND) @@ -1957,14 +1957,12 @@ single_thread_check(struct proc *p, int deep) return (EINTR); } - SCHED_LOCK(s); - if (pr->ps_single == NULL) { - SCHED_UNLOCK(s); + if (pr->ps_single == NULL) continue; - } if (atomic_dec_int_nv(&pr->ps_singlecount) == 0) wakeup(&pr->ps_singlecount); + if (pr->ps_flags & PS_SINGLEEXIT) { SCHED_UNLOCK(s); KERNEL_LOCK(); @@ -1975,13 +1973,24 @@ single_thread_check(struct proc *p, int deep) /* not exiting and don't need to unwind, so suspend */ p->p_stat = SSTOP; mi_switch(); - SCHED_UNLOCK(s); } while (pr->ps_single != NULL); } return (0); } +int +single_thread_check(struct proc *p, int deep) +{ + int s, error; + + SCHED_LOCK(s); + error = single_thread_check_locked(p, deep, s); + SCHED_UNLOCK(s); + + return error; +} + /* * Stop other threads in the process. The mode controls how and * where the other threads should stop: @@ -2003,8 +2012,12 @@ single_thread_set(struct proc *p, enum single_thread_mode mode, int deep) KERNEL_ASSERT_LOCKED(); KASSERT(curproc == p); - if ((error = single_thread_check(p, deep))) + SCHED_LOCK(s); + error = single_thread_check_locked(p, deep, s); + if (error) { + SCHED_UNLOCK(s); return error; + } switch (mode) { case SINGLE_SUSPEND: @@ -2022,7 +2035,6 @@ single_thread_set(struct proc *p, enum single_thread_mode mode, int deep) panic("single_thread_mode = %d", mode); #endif } - SCHED_LOCK(s); pr->ps_singlecount = 0; membar_producer(); pr->ps_single = p; |