Subtracting the private key values will not undo the mess. Back to the
diagram. += and -= are not atomic in C.
[ On SMP, even if the compiler happens to choose (unlocked)
read-modify-write instructions, the processor divides them into those
three phases using an internal register anyway. So reg below still
makes sense ].
So:
Process 0 Process 1
--------- ---------
reg = pars->spin
reg += KEY0
<task switch>
reg = pars->spin to
reg += KEY1
pars->spin = reg
<task switch>
pars->spin = reg
At this point, pars->spin == KEY0.
<task switch>
if (pars->spin != KEY1) {
pars->spin -= KEY1;
At this point, pars->spin == KEY0 - KEY1.
<task switch>
if (pars->spin != KEY0) {
pars->spin -= KEY0;
At this point, pars->spin == -KEY1 and both processes think they have
restored the spin state. Oh dear. No-one ever gets the lock after this
point.
> This is the important point of locking with a private key value,
> taught when I was a kid in CS-101.
Indeed, Ingo's lockless spinlock works using private keys way but not
using non-atomic += and -=.
> Now, another thing. If any task "thinks" only for an instant, that
> their copy of the key is exactly the same as the shared variable, then
> it is guaranteed that the other task will never, even for an instant
> "think" that the shared variable is the same. This is enforced by
> the CPU which guarantees that, regardless of what it "speculates",
> code will never be executed out-of-order.
This loses me. Can you rephrase?
> That said, the code executes perfectly, but only if you use the
> version that has the flush() macro. The flush() macro loads a segment
> register (cs) in the "far" return. This flushes the offending cache.
IMO, only by luck. far jumps are not defined to be serialising, and do not
flush anything except the prefetch queue (back when there was one). The
only reason it works here is because of timing.
-- Jamie
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/