* * * * *

                                  Exclusion

For those of you who are interested in rolling your own [1] operating system,
and if you insist on writing it all in Assembly on your typical IBM
PCompatible (and the most popular type is your 32-bit multitasking operating
system) please, please, do yourself a favor—avoid using CLI (CLear Interrupt
flag) and STI (SeT Interrupt flag) as locking primitives. It fails miserably
on SMP (Symetric MultiProcessing)-based machines (which I predict will become
a commoditized item, much like older 486 and early Pentium machines are now,
in the next five years).

Better to use the following:

-----[ Assembly ]-----
lock_for_here   db      0

       ; code code code

               mov     al,1
spin            xchg    al,[lock_for_here]
               cmp     al,0
               jne     .spin

       ; critical code here ...

               mov     byte ptr [lock_for_here],0

-----[ END OF LINE ]-----

This actually has several advantages over using CLI and STI:

 1. XCHG (eXCHanGE) locks the bus so that the exchange is atomic with
    respect to other CPUs on the bus.
 2. XCHG is not a protected mode instruction, unlike CLI and STI—therefore
    the sequence can even be used in non-priviledged code. While this may
    seem silly when you're writing a kernel, not every CPU (Central
    Processing Unit) has a duo user/superuser model. The 80x86 line does
    support four different priviledged modes.
 3. Interrupts can still be serviced.
 4. It doesn't hurt that much on a single-CPU system if it's programmed
    properly. Sure, the worst case is a deadlocked system, but you're
    careful to avoid deadlocks, right?

Better yet, wrap them up into functions. That case, if you do need to change
how to lock critical sections (say if CLI/STI does prove faster for a single
CPU system) you can easily change it in one location.

And it makes it just that much easier to port.

[1] http://www.webring.org/cgi-bin/webring?ring=os&list

Email author at [email protected]