tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: Critical section
Critical section must stop soft interrupt which may block & sleep
(using the preempted lwp). Thus critical sections must be at least
IPL_SOFTSERIAL.
On Wed, Nov 26, 2014 at 4:41 PM, Masao Uebayashi <uebayasi%gmail.com@localhost> wrote:
> 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