On Sun, 4 Sep 2011, Attilio Rao wrote:

Log:
??Interrupts are disabled/enabled when entering and exiting the KDB context.
??While this is generally good, it brings along a serie of problems,
??like clocks going off sync and in presence of SW_WATCHDOG, watchdogs
??firing without a good reason (missed hardclock wdog ticks update).

Please fix your mailer.  It corrupts spaces to binary data \xc2\xa0.

My version resets the timecounter 3 seconds after leaving ddb (not
immediately, to avoid setting it thousands or millions of times per
second for trace traps and possibly making it drift a few usec every
time (I get a drift of ~ 1 usec per second stopped)).  In fact, I don't
see how anyone can use ddb without this.  When running current, I
have to remember to stop ntpd before running ddb so that ntpd doesn't
corrupt its database (just the driftfile and logs).

Also please notice that intr enable/disable happens in the wrong way
as it is done via the MD (x86 specific likely) interface. This is
wrong for 2 reasons:

No, intr_disable() is MI.  It is also used by witness.  disable_intr()
is the corresponding x86 interface that you may be thinking of.  The MI
interface intr_disable() was introduced to avoid the MD'ness of
intr_disable().

1) There may be some codepaths leading to explicit preemption
2) It should  really use an MI interface

The right way to do this should be via spinlock_enter().

spinlock_enter() is MI, but has wrong semantics.  In my version of i386,
spinlocks don't disable any h/w interrupt, as is needed for fast interrupt
handlers to actually work.  I believe sparc64 is similar, except its
spinlock_enter() disables most h/w interrupts and this includes fast
interrupt handlers.  I don't understand sparc64, but it looks like its
spinlock_enter() disables all interrupts visible in C code, but not
all interrupts:

from cpufunc.h:
% static __inline register_t
% intr_disable(void)
% {
%       register_t s;
% % s = rdpr(pstate);
%       wrpr(pstate, s & ~PSTATE_IE, 0);
%       return (s);
% }

This seems to mask all interrupts, as required.

    (The interface here is slightly broken (non-MI).  It returns register_t.
    This assumes that the interrupt state can be represented in a single
    register.  The type critical_t exists to avoid the same bug in an
    old version of critical_enter().  Now this type is just bogus.
    critical_enter() no longer returns it.  Instead, spinlock_enter() uses
    a non-reentrant interface which stores what used to be the return value
    of critical_enter() in a per-thread MD data structure (md_saved_pil
    in the above).  Most or all arches use register_t for this.  This
    leaves critical_t as pure garbage -- the only remaining references to
    it are for its definition.)

From machep.c:
% void
% spinlock_enter(void)
% {
%       struct thread *td;
%       register_t pil;
% % td = curthread;
%       if (td->td_md.md_spinlock_count == 0) {
%               pil = rdpr(pil);
%               wrpr(pil, 0, PIL_TICK);
%               td->td_md.md_spinlock_count = 1;
%               td->td_md.md_saved_pil = pil;
%       } else
%               td->td_md.md_spinlock_count++;
%       critical_enter();
% }

I believe this disables all interrupts at and below a certain level.

From intr_machdep.h:
% #define       PIL_LOW         1       /* stray interrupts */
% #define       PIL_ITHREAD     2       /* interrupts that use ithreads */
% #define       PIL_RENDEZVOUS  3       /* smp rendezvous ipi */
% #define       PIL_AST         4       /* ast ipi */
% #define       PIL_STOP        5       /* stop cpu ipi */
% #define       PIL_PREEMPT     6       /* preempt idle thread cpu ipi */
% #define       PIL_HARDCLOCK   7       /* hardclock broadcast */
% #define       PIL_FILTER      12      /* filter interrupts */
% #define       PIL_BRIDGE      13      /* bridge interrupts */
% #define       PIL_TICK        14      /* tick interrupts */

And this level includes all interrupts that have a level, including
tick interrupts.

In my version of x86, spinlocks mask everything except the equivalent
of filter interrupts (= non-broken fast interrupts in my version). Non-broken fast-interrupt handlers have to be written very carefully
to be reentrant.  Since full reentrancy is too hard, they must run
with _all_ h/w interrupts disabled.  kdb needs all h/w interrupts
disabled for similar reasons.  It cannot even call things like
spinlock_enter() without knowing too much about their internals.
In fact, the non-reentrant state for spinlock_enter() and/or critical
_enter() was a reliable cause of panics for many years even when it
was accessed externally near kdb -- tracing through these functions
often paniced.

Below the filter level is a much higher level than sparc64.  I think
the interrupts not masked at PIL_TICK are mostly handled in asm, which
I am further from understanding.  Anyway, this is all at a low level
for sparc64.  Higher levels just need to use the correct interface to
disable all interrupts.  That is disable_intr(), not spinlock_enter().

Bruce
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to