summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_fork.c6
-rw-r--r--sys/kern/kern_sig.c34
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;