summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/os/condvar.c24
-rw-r--r--usr/src/uts/common/os/sig.c22
-rw-r--r--usr/src/uts/common/sys/klwp.h30
-rw-r--r--usr/src/uts/common/vm/vm_as.c24
-rw-r--r--usr/src/uts/intel/fs/proc/prmachdep.c14
-rw-r--r--usr/src/uts/sparc/fs/proc/prmachdep.c12
6 files changed, 86 insertions, 40 deletions
diff --git a/usr/src/uts/common/os/condvar.c b/usr/src/uts/common/os/condvar.c
index 8e8c189d57..21b91391f6 100644
--- a/usr/src/uts/common/os/condvar.c
+++ b/usr/src/uts/common/os/condvar.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -555,45 +555,49 @@ cv_wait_stop(kcondvar_t *cvp, kmutex_t *mp, int wakeup_time)
(void) untimeout(id);
/*
- * Check for reasons to stop, if lwp_nostop is not true.
+ * Check for reasons to stop, and stop if lwp_nostop is zero.
* See issig_forreal() for explanations of the various stops.
+ * Like issig_forreal(), we allow a PR_SUSPENDED/SUSPEND_NORMAL
+ * to occur even if lwp_nostop is set.
*/
mutex_enter(&p->p_lock);
- while (lwp->lwp_nostop == 0 && !(p->p_flag & SEXITLWPS)) {
+ while (!(p->p_flag & SEXITLWPS)) {
/*
* Hold the lwp here for watchpoint manipulation.
*/
- if (t->t_proc_flag & TP_PAUSE) {
+ if ((t->t_proc_flag & TP_PAUSE) && !lwp->lwp_nostop) {
stop(PR_SUSPENDED, SUSPEND_PAUSE);
continue;
}
/*
* System checkpoint.
*/
- if (t->t_proc_flag & TP_CHKPT) {
+ if ((t->t_proc_flag & TP_CHKPT) && !lwp->lwp_nostop) {
stop(PR_CHECKPOINT, 0);
continue;
}
/*
* Honor fork1(), watchpoint activity (remapping a page),
- * and lwp_suspend() requests.
+ * and lwp_suspend() regardless of whether lwp_nostop is
+ * set but not if lwp_nostop_r is set (to avoid a recursive
+ * call to prstop()).
*/
- if ((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
- (t->t_proc_flag & TP_HOLDLWP)) {
+ if (((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
+ (t->t_proc_flag & TP_HOLDLWP)) && !lwp->lwp_nostop_r) {
stop(PR_SUSPENDED, SUSPEND_NORMAL);
continue;
}
/*
* Honor /proc requested stop.
*/
- if (t->t_proc_flag & TP_PRSTOP) {
+ if ((t->t_proc_flag & TP_PRSTOP) && !lwp->lwp_nostop) {
stop(PR_REQUESTED, 0);
}
/*
* If some lwp in the process has already stopped
* showing PR_JOBCONTROL, stop in sympathy with it.
*/
- if (p->p_stopsig && t != p->p_agenttp) {
+ if (p->p_stopsig && !lwp->lwp_nostop && (t != p->p_agenttp)) {
stop(PR_JOBCONTROL, p->p_stopsig);
continue;
}
diff --git a/usr/src/uts/common/os/sig.c b/usr/src/uts/common/os/sig.c
index 4a2efd89cb..3425046072 100644
--- a/usr/src/uts/common/os/sig.c
+++ b/usr/src/uts/common/os/sig.c
@@ -436,10 +436,10 @@ issig_justlooking(void)
if ((lwp->lwp_asleep && MUSTRETURN(p, t)) ||
(p->p_flag & (SEXITLWPS|SKILLED)) ||
- (lwp->lwp_nostop == 0 &&
- (p->p_stopsig | (p->p_flag & (SHOLDFORK1|SHOLDWATCH)) |
- (t->t_proc_flag &
- (TP_PRSTOP|TP_HOLDLWP|TP_CHKPT|TP_PAUSE)))) ||
+ (!lwp->lwp_nostop_r && ((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) |
+ (t->t_proc_flag & TP_HOLDLWP))) ||
+ (!lwp->lwp_nostop && (p->p_stopsig | (t->t_proc_flag &
+ (TP_PRSTOP|TP_CHKPT|TP_PAUSE)))) ||
lwp->lwp_cursig)
return (1);
@@ -577,9 +577,15 @@ issig_forreal(void)
* or is executing lwp_suspend() on this lwp.
* Again, go back to top of loop to check if an exit
* or hold event has occurred while stopped.
+ * We explicitly allow this form of stopping of one
+ * lwp in a process by another lwp in the same process,
+ * even if lwp->lwp_nostop is set, because otherwise a
+ * process can become deadlocked on a fork1().
+ * Allow this only if lwp_nostop_r is not set,
+ * to avoid a recursive call to prstop().
*/
if (((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
- (t->t_proc_flag & TP_HOLDLWP)) && !lwp->lwp_nostop) {
+ (t->t_proc_flag & TP_HOLDLWP)) && !lwp->lwp_nostop_r) {
stop(PR_SUSPENDED, SUSPEND_NORMAL);
continue;
}
@@ -845,9 +851,11 @@ stop(int why, int what)
/*
* Make sure we don't deadlock on a recursive call to prstop().
- * prstop() sets the lwp_nostop flag.
+ * prstop() sets the lwp_nostop_r flag and increments lwp_nostop.
*/
- if (lwp->lwp_nostop)
+ if (lwp->lwp_nostop_r ||
+ (lwp->lwp_nostop &&
+ (why != PR_SUSPENDED || what != SUSPEND_NORMAL)))
return;
/*
diff --git a/usr/src/uts/common/sys/klwp.h b/usr/src/uts/common/sys/klwp.h
index 53204efe04..ade26b4f82 100644
--- a/usr/src/uts/common/sys/klwp.h
+++ b/usr/src/uts/common/sys/klwp.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -161,12 +161,34 @@ typedef struct _klwp {
struct itimerval lwp_timer[3];
/*
- * used to stop/alert lwps
+ * There are a number of places where you do not wish an lwp to
+ * be stopped due to some interaction with other lwps in the process.
+ * In these cases the lwp_nostop value is incremented. At places where
+ * the lwp would normally be stopped the stop is allowed if lwp_nostop
+ * is zero. There are a very few cases where even if lwp_nostop is set
+ * we need to allow the lwp to stop. In those cases the lwp is
+ * stopped if lwp_nostop_r is not set regardless of the state of
+ * lwp_nostop. These conditions are:
+ *
+ * 1. In issig_forreal() when another lwp is undergoing fork1()
+ * or watchpoint activity (p_flag contains either SHOLDFORK1 or
+ * SHOLDWATCH or t_proc_flag contains TP_HOLDLWP)
+ *
+ * 2. In stop() when the why argument is not PR_SUSPENDED or the what
+ * argument is not SUSPEND_NORMAL.
+ *
+ * 3. In cv_wait_stop() when another lwp is undergoing fork1() or
+ * watchpoint activity (p_flag contains either SHOLDFORK1 or
+ * SHOLDWATCH or t_proc_flag contains TP_HOLDLWP)
+ *
+ * lwp_nostop_r is set in prstop(). ie we honour the presence of
+ * SHOLDFORK1 or SHOLDWATCH or TP_HOLDLWP in the case of
+ * stop(PR_SUSPENDED, SUSPEND_NORMAL)
*/
char lwp_unused;
char lwp_state; /* Running in User/Kernel mode (no lock req) */
- ushort_t lwp_nostop; /* Don't stop this lwp (no lock required) */
- kcondvar_t lwp_cv;
+ ushort_t lwp_nostop; /* Don't stop this lwp except SUSPEND_NORMAL */
+ ushort_t lwp_nostop_r; /* Don't stop this lwp (avoid recursion) */
/*
* Last failed privilege.
diff --git a/usr/src/uts/common/vm/vm_as.c b/usr/src/uts/common/vm/vm_as.c
index f54ae54359..b03d712069 100644
--- a/usr/src/uts/common/vm/vm_as.c
+++ b/usr/src/uts/common/vm/vm_as.c
@@ -878,8 +878,10 @@ retry:
* for a pagefault. This is to avoid deadlock while debugging
* a process via /proc over NFS (in particular).
*/
- if (lwp != NULL)
+ if (lwp != NULL) {
lwp->lwp_nostop++;
+ lwp->lwp_nostop_r++;
+ }
/*
* same length must be used when we softlock and softunlock.
@@ -957,8 +959,10 @@ retry:
seg = as_segat(as, raddr);
if (seg == NULL) {
AS_LOCK_EXIT(as, &as->a_lock);
- if ((lwp != NULL) && (!is_xhat))
+ if ((lwp != NULL) && (!is_xhat)) {
lwp->lwp_nostop--;
+ lwp->lwp_nostop_r--;
+ }
return (FC_NOMAP);
}
@@ -1038,8 +1042,10 @@ retry:
}
if (as_lock_held)
AS_LOCK_EXIT(as, &as->a_lock);
- if ((lwp != NULL) && (!is_xhat))
+ if ((lwp != NULL) && (!is_xhat)) {
lwp->lwp_nostop--;
+ lwp->lwp_nostop_r--;
+ }
/*
* If the lower levels returned EDEADLK for a fault,
* It means that we should retry the fault. Let's wait
@@ -1077,8 +1083,10 @@ retry:
* for a pagefault. This is to avoid deadlock while debugging
* a process via /proc over NFS (in particular).
*/
- if (lwp != NULL)
+ if (lwp != NULL) {
lwp->lwp_nostop++;
+ lwp->lwp_nostop_r++;
+ }
raddr = (caddr_t)((uintptr_t)addr & (uintptr_t)PAGEMASK);
rsize = (((size_t)(addr + size) + PAGEOFFSET) & PAGEMASK) -
@@ -1088,8 +1096,10 @@ retry:
seg = as_segat(as, raddr);
if (seg == NULL) {
AS_LOCK_EXIT(as, &as->a_lock);
- if (lwp != NULL)
+ if (lwp != NULL) {
lwp->lwp_nostop--;
+ lwp->lwp_nostop_r--;
+ }
return (FC_NOMAP);
}
@@ -1106,8 +1116,10 @@ retry:
break;
}
AS_LOCK_EXIT(as, &as->a_lock);
- if (lwp != NULL)
+ if (lwp != NULL) {
lwp->lwp_nostop--;
+ lwp->lwp_nostop_r--;
+ }
/*
* If the lower levels returned EDEADLK for a fault,
* It means that we should retry the fault. Let's wait
diff --git a/usr/src/uts/intel/fs/proc/prmachdep.c b/usr/src/uts/intel/fs/proc/prmachdep.c
index 70b8725784..e0788476c4 100644
--- a/usr/src/uts/intel/fs/proc/prmachdep.c
+++ b/usr/src/uts/intel/fs/proc/prmachdep.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -425,11 +425,11 @@ prstop(int why, int what)
struct regs *r = lwptoregs(lwp);
/*
- * Make sure we don't deadlock on a recursive call
- * to prstop(). stop() tests the lwp_nostop flag.
+ * Make sure we don't deadlock on a recursive call to prstop().
+ * stop() tests the lwp_nostop_r and lwp_nostop flags.
*/
- ASSERT(lwp->lwp_nostop == 0);
- lwp->lwp_nostop = 1;
+ lwp->lwp_nostop_r++;
+ lwp->lwp_nostop++;
if (copyin_nowatch((caddr_t)r->r_pc, &lwp->lwp_pcb.pcb_instr,
sizeof (lwp->lwp_pcb.pcb_instr)) == 0)
@@ -440,8 +440,8 @@ prstop(int why, int what)
}
(void) save_syscall_args();
- ASSERT(lwp->lwp_nostop == 1);
- lwp->lwp_nostop = 0;
+ lwp->lwp_nostop--;
+ lwp->lwp_nostop_r--;
}
/*
diff --git a/usr/src/uts/sparc/fs/proc/prmachdep.c b/usr/src/uts/sparc/fs/proc/prmachdep.c
index c78150cda5..b025b55a98 100644
--- a/usr/src/uts/sparc/fs/proc/prmachdep.c
+++ b/usr/src/uts/sparc/fs/proc/prmachdep.c
@@ -880,11 +880,11 @@ prstop(int why, int what)
extern void fp_prsave(kfpu_t *);
/*
- * Make sure we don't deadlock on a recursive call
- * to prstop(). stop() tests the lwp_nostop flag.
+ * Make sure we don't deadlock on a recursive call to prstop().
+ * stop() tests the lwp_nostop_r and lwp_nostop flags.
*/
- ASSERT(lwp->lwp_nostop == 0);
- lwp->lwp_nostop = 1;
+ lwp->lwp_nostop_r++;
+ lwp->lwp_nostop++;
(void) flush_user_windows_to_stack(NULL);
if (lwp->lwp_pcb.pcb_step != STEP_NONE)
(void) prundostep();
@@ -967,8 +967,8 @@ prstop(int why, int what)
}
(void) save_syscall_args();
- ASSERT(lwp->lwp_nostop == 1);
- lwp->lwp_nostop = 0;
+ lwp->lwp_nostop--;
+ lwp->lwp_nostop_r--;
}
/*