tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Critical section
The problem of kpreempt_*() API is that its meaning is overriden by kernel
internal (scheduler, sync primitives, ...). This change separates the internal
use (scheduler disables preeemption) and others (kernel subsystem code executes
critical section). Detect sleep from within critical section in mi_switch().
The only problem I've seen is, cprng_fast.c calling percpu_getref() in
KASSERT(); it's kind of re-entrance.
Index: sys/crypto/cprng_fast/cprng_fast.c
===================================================================
RCS file: /cvsroot/src/sys/crypto/cprng_fast/cprng_fast.c,v
retrieving revision 1.11
diff -p -u -r1.11 cprng_fast.c
--- sys/crypto/cprng_fast/cprng_fast.c 11 Aug 2014 22:36:49 -0000 1.11
+++ sys/crypto/cprng_fast/cprng_fast.c 26 Nov 2014 07:35:51 -0000
@@ -258,8 +258,10 @@ static inline void
cprng_fast_put(struct cprng_fast *cprng, int s)
{
+#if 0
KASSERT((cprng == percpu_getref(cprng_fast_percpu)) &&
(percpu_putref(cprng_fast_percpu), true));
+#endif
splx(s);
percpu_putref(cprng_fast_percpu);
}
Index: sys/kern/kern_synch.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_synch.c,v
retrieving revision 1.308
diff -p -u -r1.308 kern_synch.c
--- sys/kern/kern_synch.c 28 Feb 2014 10:16:51 -0000 1.308
+++ sys/kern/kern_synch.c 26 Nov 2014 07:35:51 -0000
@@ -441,6 +441,54 @@ kpreempt_enable(void)
}
/*
+ * Critical section.
+ *
+ * - Kernel subsystems can declare critical sections.
+ * - Kernel core (scheduler and synchronization implementation) use
+ * KPREEMPT_DISABLE()/KPREEMPT_ENABLE().
+ * - Not re-entrant.
+ * - If re-entered, panic is triggered.
+ * - Can't sleep.
+ * - If calling threads sleep (enter scheduler), panic is triggered.
+ * - Kernel preemption is disabled.
+ * - Callers ensure appropriate IPL.
+ * - If there's no strong reason, IPL_SOFT* is recommended, because
+ * setting H/W interrupt level is expensive itself.
+ */
+
+#define CRIT_BIT 0x10000 /* set in l_nopreempt */
+
+void
+crit_enter(void)
+{
+ lwp_t * const l = curlwp;
+
+ KASSERTMSG((l->l_nopreempt & CRIT_BIT) == 0, "l_nopreempt=%x",
+ l->l_nopreempt);
+ l->l_nopreempt |= CRIT_BIT;
+}
+
+void
+crit_exit(void)
+{
+ lwp_t * const l = curlwp;
+
+ KASSERTMSG((l->l_nopreempt & CRIT_BIT) != 0, "l_nopreempt=%x",
+ l->l_nopreempt);
+ l->l_nopreempt &= ~CRIT_BIT;
+ if (__predict_false(l->l_dopreempt))
+ kpreempt(0);
+}
+
+bool
+crit_entered(void)
+{
+ const lwp_t * const l = curlwp;
+
+ return (l->l_nopreempt & CRIT_BIT) != 0;
+}
+
+/*
* Compute the amount of time during which the current lwp was running.
*
* - update l_rtime unless it's an idle lwp.
@@ -514,6 +562,7 @@ mi_switch(lwp_t *l)
bool returning;
KASSERT(lwp_locked(l, NULL));
+ KASSERT(!crit_entered());
KASSERT(kpreempt_disabled());
LOCKDEBUG_BARRIER(l->l_mutex, 1);
Index: sys/kern/subr_percpu.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_percpu.c,v
retrieving revision 1.16
diff -p -u -r1.16 subr_percpu.c
--- sys/kern/subr_percpu.c 27 Jan 2012 19:48:40 -0000 1.16
+++ sys/kern/subr_percpu.c 26 Nov 2014 07:35:51 -0000
@@ -291,7 +291,7 @@ void *
percpu_getref(percpu_t *pc)
{
- KPREEMPT_DISABLE(curlwp);
+ crit_enter();
return percpu_getptr_remote(pc, curcpu());
}
@@ -306,7 +306,7 @@ void
percpu_putref(percpu_t *pc)
{
- KPREEMPT_ENABLE(curlwp);
+ crit_exit();
}
/*
Index: sys/kern/subr_pserialize.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_pserialize.c,v
retrieving revision 1.7
diff -p -u -r1.7 subr_pserialize.c
--- sys/kern/subr_pserialize.c 7 Feb 2013 23:37:58 -0000 1.7
+++ sys/kern/subr_pserialize.c 26 Nov 2014 07:35:51 -0000
@@ -187,6 +187,7 @@ pserialize_read_enter(void)
{
KASSERT(!cpu_intr_p());
+ crit_enter();
return splsoftserial();
}
@@ -195,6 +196,7 @@ pserialize_read_exit(int s)
{
splx(s);
+ crit_exit();
}
/*
Index: sys/sys/systm.h
===================================================================
RCS file: /cvsroot/src/sys/sys/systm.h,v
retrieving revision 1.266
diff -p -u -r1.266 systm.h
--- sys/sys/systm.h 3 Aug 2014 12:49:32 -0000 1.266
+++ sys/sys/systm.h 26 Nov 2014 07:35:51 -0000
@@ -522,6 +522,9 @@ do { \
void kpreempt_disable(void);
void kpreempt_enable(void);
bool kpreempt_disabled(void);
+void crit_enter(void);
+void crit_exit(void);
+bool crit_entered(void);
#endif
void assert_sleepable(void);
Home |
Main Index |
Thread Index |
Old Index