summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_exit.c4
-rw-r--r--sys/kern/kern_sig.c44
-rw-r--r--sys/sys/proc.h4
3 files changed, 41 insertions, 11 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 113561cc64d..7d0ea4a0fe6 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.133 2014/01/24 04:26:51 guenther Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.134 2014/02/09 11:17:19 kettenis Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -550,6 +550,8 @@ loop:
(pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
pr->ps_single->p_stat == SSTOP &&
(pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
+ single_thread_wait(pr);
+
atomic_setbits_int(&pr->ps_flags, PS_WAITED);
retval[0] = p->p_pid;
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 9e16570c21c..4f0a6af6e89 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sig.c,v 1.157 2014/01/21 01:48:44 tedu Exp $ */
+/* $OpenBSD: kern_sig.c,v 1.158 2014/02/09 11:17:19 kettenis Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
@@ -1071,6 +1071,9 @@ out:
*
* while (signum = CURSIG(curproc))
* postsig(signum);
+ *
+ * Assumes that if the P_SINTR flag is set, we're holding both the
+ * kernel and scheduler locks.
*/
int
issignal(struct proc *p)
@@ -1105,9 +1108,11 @@ issignal(struct proc *p)
*/
p->p_xstat = signum;
- KERNEL_LOCK();
- single_thread_set(p, SINGLE_SUSPEND, 0);
- KERNEL_UNLOCK();
+ if (dolock)
+ KERNEL_LOCK();
+ single_thread_set(p, SINGLE_PTRACE, 0);
+ if (dolock)
+ KERNEL_UNLOCK();
if (dolock)
SCHED_LOCK(s);
@@ -1115,9 +1120,11 @@ issignal(struct proc *p)
if (dolock)
SCHED_UNLOCK(s);
- KERNEL_LOCK();
+ if (dolock)
+ KERNEL_LOCK();
single_thread_clear(p, 0);
- KERNEL_UNLOCK();
+ if (dolock)
+ KERNEL_UNLOCK();
/*
* If we are no longer being traced, or the parent
@@ -1829,6 +1836,8 @@ single_thread_check(struct proc *p, int deep)
* where the other threads should stop:
* - SINGLE_SUSPEND: stop wherever they are, will later either be told to exit
* (by setting to SINGLE_EXIT) or be released (via single_thread_clear())
+ * - SINGLE_PTRACE: stop wherever they are, will wait for them to stop
+ * later (via single_thread_wait()) and released as with SINGLE_SUSPEND
* - SINGLE_UNWIND: just unwind to kernel boundary, will be told to exit
* or released as with SINGLE_SUSPEND
* - SINGLE_EXIT: unwind to kernel boundary and exit
@@ -1840,11 +1849,16 @@ single_thread_set(struct proc *p, enum single_thread_mode mode, int deep)
struct proc *q;
int error;
+#ifdef MULTIPROCESSOR
+ KASSERT(__mp_lock_held(&kernel_lock));
+#endif
+
if ((error = single_thread_check(p, deep)))
return error;
switch (mode) {
case SINGLE_SUSPEND:
+ case SINGLE_PTRACE:
break;
case SINGLE_UNWIND:
atomic_setbits_int(&pr->ps_flags, PS_SINGLEUNWIND);
@@ -1887,7 +1901,8 @@ single_thread_set(struct proc *p, enum single_thread_mode mode, int deep)
/* if it's not interruptible, then just have to wait */
if (q->p_flag & P_SINTR) {
/* merely need to suspend? just stop it */
- if (mode == SINGLE_SUSPEND) {
+ if (mode == SINGLE_SUSPEND ||
+ mode == SINGLE_PTRACE) {
q->p_stat = SSTOP;
break;
}
@@ -1913,10 +1928,18 @@ single_thread_set(struct proc *p, enum single_thread_mode mode, int deep)
SCHED_UNLOCK(s);
}
+ if (mode != SINGLE_PTRACE)
+ single_thread_wait(pr);
+
+ return 0;
+}
+
+void
+single_thread_wait(struct process *pr)
+{
/* wait until they're all suspended */
while (pr->ps_singlecount > 0)
tsleep(&pr->ps_singlecount, PUSER, "suspend", 0);
- return 0;
}
void
@@ -1926,7 +1949,10 @@ single_thread_clear(struct proc *p, int flag)
struct proc *q;
KASSERT(pr->ps_single == p);
-
+#ifdef MULTIPROCESSOR
+ KASSERT(__mp_lock_held(&kernel_lock));
+#endif
+
pr->ps_single = NULL;
atomic_clearbits_int(&pr->ps_flags, PS_SINGLEUNWIND | PS_SINGLEEXIT);
TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) {
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 55e1f90c335..32063bcd002 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.175 2014/02/04 00:33:43 tedu Exp $ */
+/* $OpenBSD: proc.h,v 1.176 2014/02/09 11:17:19 kettenis Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -518,10 +518,12 @@ int groupmember(gid_t, struct ucred *);
enum single_thread_mode {
SINGLE_SUSPEND, /* other threads to stop wherever they are */
+ SINGLE_PTRACE, /* other threads to stop but don't wait */
SINGLE_UNWIND, /* other threads to unwind and stop */
SINGLE_EXIT /* other threads to unwind and then exit */
};
int single_thread_set(struct proc *, enum single_thread_mode, int);
+void single_thread_wait(struct process *);
void single_thread_clear(struct proc *, int);
int single_thread_check(struct proc *, int);