Re: cli() and sti()

Richard B. Johnson (root@analogic.com)
Sun, 2 Mar 1997 19:06:41 -0500 (EST)


On Sun, 2 Mar 1997, Duan Zhenhai wrote:

> Hello,
> Can anybody tell me more information about cli()
> and sti()? Does both of them be used together?
> I read some code that like:
>
> save_flags(..);
> cli();
> .............
> restore_flags(..);
>
> and did not find they use sti.
>
> Thank you!

Some kernel code gets called with the interrupts turned OFF and some of
the same code gets called with the interrupts turned ON. You never want
to turn ON the interrupts in the section of code that was called with
the interrupts OFF. The section of code doesn't "Know" if the interrupts
were ON or OFF when it was called. The code does know, however that for
certain operations, the interrupts must be OFF because the state of the
object being tested might change as a result of an interrupt if the
interrupts were not disabled.

Therefore, the bits in the EFLAGS register that control interrupts and
other things, are first saved in a register using a macro save_flags().
The interrupt bit is then cleared using the cli() macro which emits
the single byte CLI instruction. After the critical section of code,
where you don't care if the interrupts are enabled, the restore_flags()
macro is executed instead of sti(). This will turn back ON the interrupts
if they were ON when the procedure was called, and they will be left OFF
if they were OFF when the procedure was called. The Intel ASM version of
what is happening is:

PUSHF ; Save EFLAGS onto stack
POP DWORD PTR [_old_flags] ; POP into _old_flags
CLI ; No interrupts
...... ; Critical section of code starts
...... ; Critical section of code ends
PUSH DWORD PTR [_old_flags] ; Get old EFLAGS onto stack
POPF ; Old EFLAGS into EFLAGS

Now, it would be NICE if the GCC compiler actually produced code like
this. Unfortunately, "_old_flags" is allocated on the stack so there
are many more instructions emitted under GCC than are actually required.
If fact, if you were writing such code in assembly, you would just
do:

PUSHF ; Save old flags
CLI ; No interrupts
...... ; Critical code
POPF ; Restore flags.

A pushf() macro could be easily written as could popf(). However, GCC
doesn't "like" user code to perform stack operations so it "levels" the
stack after such code, destroying what you want to do.

Cheers,
Dick Johnson
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Richard B. Johnson
Project Engineer
Analogic Corporation
Voice : (508) 977-3000 ext. 3754
Fax : (508) 532-6097
Modem : (508) 977-6870
Ftp : ftp@boneserver.analogic.com
Email : rjohnson@analogic.com, johnson@analogic.com
Penguin : Linux version 2.1.27 on an i586 machine (66.15 BogoMips).
Warning : It's hard to remain at the trailing edge of technology.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-