On Mon, 25 Feb 2002, Matthew Dillon wrote:

>     Unless an unforseen problem arises, I am going to commit this tomorrow
>     and then start working on a cleanup patch.   I have decided to

Please wait for jhb's opinion on it.  He seems to be offline again.
I think he has plans and maybe even code for more code in critical_enter().
I think we don't agree with these plans, but they are just as valid
as ours, and our versions undo many of his old changes.

>     I've looked at cleaning up cpu_critical_enter() & exit but its use
>     pollutes a number of MI source files: kern/kern_ktr.c, kern/subr_trap.c,
>     and kern/subr_witness.c are all misusing the functions.  If these
>     functions can safely be changed to use critical_enter() and critical_exit()
>     I will rename the i386's cpu_critical*() functions into intr_disable()
>     and intr_restore() and then use the new names for internal i386 use.

It is already one layer higher than the MD versions for i386's at least.
The MD versions are disable_intr() (should be cli() to inhibit use in MI
code), enable_intr() (should be sti() ...), read_eflags() and write_eflags().
cpu_critical*() is supposed to be the version with an MI interface and
semantics, but one level lower than critical*().  In my version,
critical*() essentially doesn't exist and cpu_critical*() is only used
by fast interrupt handlers and hacks.  The MI code in kern mainly depends
on the MD function (with an MI interface and semantics) unpend().

>     Is there any reason why the above uses of cpu_critical*() cannot be
>     changed to use standard critical*()?  I believe we *always* have a
>     curthread structure to play with so it should just work.

I think this would mostly work on i386's.  It would more obviously work
if td_critness were a per-cpu global and not in the thread struce.  It
essentially is a per-cpu global, but we optimize it by putting it in
the thread struct.  But ktr, especially, is very low level and should
work in the middle of a thread switch.

According to jake, it would only work on sparc64's if critical*() does
something hardware-related.  Lazy masking of interrupts is partly in
hardware, so the hardware must be talked to to turn it on an off.  On
i386's, the masking is in software, so it can use td_critnest as a
flag.

The use of cpu_critical*() in subr_trap.c is a bit trickier/kludgier.
We need to return from the interrupt handler atomically with clearing
the lazy-masking flag.  The hardware interrupt enable flag must be
used for this on i386's.  The code for this is logically:

In ast:
        /* Prevent changes to flags while we are deciding if they are set. */
        critical_enter();

        while ((ke->ke_flags & (KEF_ASTPENDING | KEF_NEEDRESCHED)) != 0) {
                critical_exit();
                ...
                /* As above. */
                critical_enter();
        }

In doreti:
        /*
         * Must use MD code to prevent race window after critical_exit().
         * We switch from lazy sofware masking using td_critnest (or
         * whatever critical_enter() uses) to hardware masking using cli.
         */
        cli();
        critical_exit();
        ...
        iretd();

but this is optimized in -current by using cpu_critical*() instead of
critical_enter*() in ast() and not doing the cli() and critical_exit()
in doreti.  This depends on cpu_critical_enter() being precisely cli().

Bruce


To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to