Fix mtx_legal2block. The only time that it is bad to block on a mutex is

if we hold a spin mutex, since we can trivially get into deadlocks if we
start switching out of processes that hold spinlocks.  Checking to see if
interrupts were disabled was a sort of cheap way of doing this since most
of the time interrupts were only disabled when holding a spin lock.  At
least on the i386.  To fix this properly, use a per-process counter
p_spinlocks that counts the number of spin locks currently held, and
instead of checking to see if interrupts are disabled in the witness code,
check to see if we hold any spin locks.  Since child processes always
start up with the sched lock magically held in fork_exit(), we initialize
p_spinlocks to 1 for child processes.  Note that proc0 doesn't go through
fork_exit(), so it starts with no spin locks held.

Consulting from:	cp
This commit is contained in:
John Baldwin 2001-03-09 07:24:17 +00:00
parent c9a970a79f
commit 5db078a9be
10 changed files with 29 additions and 13 deletions

View File

@ -36,8 +36,6 @@
#ifdef _KERNEL
#define mtx_legal2block() \
((alpha_pal_rdps() & ALPHA_PSL_IPL_MASK) == ALPHA_PSL_IPL_0)
#define mtx_intr_enable(mutex) (mutex)->mtx_saveintr = ALPHA_PSL_IPL_0
/*

View File

@ -40,7 +40,6 @@
/* Global locks */
extern struct mtx clock_lock;
#define mtx_legal2block() (read_eflags() & PSL_I)
#define mtx_intr_enable(mutex) (mutex)->mtx_saveintr |= PSL_I
/*

View File

@ -40,7 +40,6 @@
/* Global locks */
extern struct mtx clock_lock;
#define mtx_legal2block() (read_eflags() & PSL_I)
#define mtx_intr_enable(mutex) (mutex)->mtx_saveintr |= PSL_I
/*

View File

@ -38,7 +38,6 @@
#ifdef _KERNEL
#define mtx_legal2block() (ia64_get_psr() & IA64_PSR_I)
#define mtx_intr_enable(mutex) (mutex)->mtx_saveintr |= IA64_PSR_I
#endif /* _KERNEL */

View File

@ -406,6 +406,10 @@ fork1(p1, flags, procp)
if (p1->p_sflag & PS_PROFIL)
startprofclock(p2);
mtx_unlock_spin(&sched_lock);
/*
* We start off holding one spinlock after fork: sched_lock.
*/
p2->p_spinlocks = 1;
PROC_UNLOCK(p2);
MALLOC(p2->p_cred, struct pcred *, sizeof(struct pcred),
M_SUBPROC, M_WAITOK);

View File

@ -1094,6 +1094,8 @@ witness_enter(struct mtx *m, int flags, const char *file, int line)
}
PCPU_SET(witness_spin_check, i | w->w_level);
mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
p->p_spinlocks++;
MPASS(p->p_spinlocks > 0);
w->w_file = file;
w->w_line = line;
m->mtx_line = line;
@ -1116,7 +1118,7 @@ witness_enter(struct mtx *m, int flags, const char *file, int line)
if (cold)
goto out;
if (!mtx_legal2block())
if (p->p_spinlocks != 0)
panic("blockable mtx_lock() of %s when not legal @ %s:%d",
m->mtx_description, file, line);
/*
@ -1263,10 +1265,12 @@ void
witness_exit(struct mtx *m, int flags, const char *file, int line)
{
struct witness *w;
struct proc *p;
if (witness_cold || m->mtx_witness == NULL || panicstr)
return;
w = m->mtx_witness;
p = curproc;
if (flags & MTX_SPIN) {
if ((m->mtx_flags & MTX_SPIN) == 0)
@ -1283,6 +1287,8 @@ witness_exit(struct mtx *m, int flags, const char *file, int line)
PCPU_SET(witness_spin_check,
PCPU_GET(witness_spin_check) & ~w->w_level);
mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
MPASS(p->p_spinlocks > 0);
p->p_spinlocks--;
return;
}
if ((m->mtx_flags & MTX_SPIN) != 0)
@ -1297,7 +1303,7 @@ witness_exit(struct mtx *m, int flags, const char *file, int line)
return;
}
if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
if ((flags & MTX_NOSWITCH) == 0 && p->p_spinlocks != 0 && !cold)
panic("switchable mtx_unlock() of %s when not legal @ %s:%d",
m->mtx_description, file, line);
LIST_REMOVE(m, mtx_held);

View File

@ -1094,6 +1094,8 @@ witness_enter(struct mtx *m, int flags, const char *file, int line)
}
PCPU_SET(witness_spin_check, i | w->w_level);
mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
p->p_spinlocks++;
MPASS(p->p_spinlocks > 0);
w->w_file = file;
w->w_line = line;
m->mtx_line = line;
@ -1116,7 +1118,7 @@ witness_enter(struct mtx *m, int flags, const char *file, int line)
if (cold)
goto out;
if (!mtx_legal2block())
if (p->p_spinlocks != 0)
panic("blockable mtx_lock() of %s when not legal @ %s:%d",
m->mtx_description, file, line);
/*
@ -1263,10 +1265,12 @@ void
witness_exit(struct mtx *m, int flags, const char *file, int line)
{
struct witness *w;
struct proc *p;
if (witness_cold || m->mtx_witness == NULL || panicstr)
return;
w = m->mtx_witness;
p = curproc;
if (flags & MTX_SPIN) {
if ((m->mtx_flags & MTX_SPIN) == 0)
@ -1283,6 +1287,8 @@ witness_exit(struct mtx *m, int flags, const char *file, int line)
PCPU_SET(witness_spin_check,
PCPU_GET(witness_spin_check) & ~w->w_level);
mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
MPASS(p->p_spinlocks > 0);
p->p_spinlocks--;
return;
}
if ((m->mtx_flags & MTX_SPIN) != 0)
@ -1297,7 +1303,7 @@ witness_exit(struct mtx *m, int flags, const char *file, int line)
return;
}
if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
if ((flags & MTX_NOSWITCH) == 0 && p->p_spinlocks != 0 && !cold)
panic("switchable mtx_unlock() of %s when not legal @ %s:%d",
m->mtx_description, file, line);
LIST_REMOVE(m, mtx_held);

View File

@ -1094,6 +1094,8 @@ witness_enter(struct mtx *m, int flags, const char *file, int line)
}
PCPU_SET(witness_spin_check, i | w->w_level);
mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
p->p_spinlocks++;
MPASS(p->p_spinlocks > 0);
w->w_file = file;
w->w_line = line;
m->mtx_line = line;
@ -1116,7 +1118,7 @@ witness_enter(struct mtx *m, int flags, const char *file, int line)
if (cold)
goto out;
if (!mtx_legal2block())
if (p->p_spinlocks != 0)
panic("blockable mtx_lock() of %s when not legal @ %s:%d",
m->mtx_description, file, line);
/*
@ -1263,10 +1265,12 @@ void
witness_exit(struct mtx *m, int flags, const char *file, int line)
{
struct witness *w;
struct proc *p;
if (witness_cold || m->mtx_witness == NULL || panicstr)
return;
w = m->mtx_witness;
p = curproc;
if (flags & MTX_SPIN) {
if ((m->mtx_flags & MTX_SPIN) == 0)
@ -1283,6 +1287,8 @@ witness_exit(struct mtx *m, int flags, const char *file, int line)
PCPU_SET(witness_spin_check,
PCPU_GET(witness_spin_check) & ~w->w_level);
mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
MPASS(p->p_spinlocks > 0);
p->p_spinlocks--;
return;
}
if ((m->mtx_flags & MTX_SPIN) != 0)
@ -1297,7 +1303,7 @@ witness_exit(struct mtx *m, int flags, const char *file, int line)
return;
}
if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
if ((flags & MTX_NOSWITCH) == 0 && p->p_spinlocks != 0 && !cold)
panic("switchable mtx_unlock() of %s when not legal @ %s:%d",
m->mtx_description, file, line);
LIST_REMOVE(m, mtx_held);

View File

@ -36,8 +36,6 @@
#ifdef _KERNEL
#define mtx_legal2block() \
((alpha_pal_rdps() & ALPHA_PSL_IPL_MASK) == ALPHA_PSL_IPL_0)
#define mtx_intr_enable(mutex) (mutex)->mtx_saveintr = ALPHA_PSL_IPL_0
/*

View File

@ -213,6 +213,7 @@ struct proc {
struct vnode *p_textvp; /* (b) Vnode of executable. */
struct mtx p_mtx; /* (k) Lock for this struct. */
u_int p_spinlocks; /* (k) Count of held spin locks. */
char p_lock; /* (c) Process lock (prevent swap) count. */
u_char p_oncpu; /* (j) Which cpu we are on. */
u_char p_lastcpu; /* (j) Last cpu we were on. */