Messages in this thread | | | Date | Tue, 30 Nov 1999 21:05:24 -0500 (EST) | From | "Richard B. Johnson" <> | Subject | Re: Shared memory not SMP safe to user-mode code. |
| |
On Wed, 1 Dec 1999, Jamie Lokier wrote:
> Richard B. Johnson wrote a spinlock: > > pars->spin += key; > > if(pars->spin != key) > > { > > pars->spin -= key; > > Wrong. This is not safe on UP /or/ SMP because "+=" and "-=" are not > atomic operations in C. `volatile' does not help either. > [SNIPPED]
It is not necessary for the operations to be atomic! It is only essential that they can be undone. Both the child and the parent have private copies of their key value. The resulting arithmetic on the shared variable will be wrong if any of the read/modify/write operations are interrupted by another task, however, the resulting "mess" will be completely undone when both of the tasks subtract their key values (in any order). This is the important point of locking with a private key value, taught when I was a kid in CS-101.
Note that to resolve deadlocks, both tasks as forced to sleep for a different amount of time so they don't "attack" the variable again at the same instant. This will not work with a long-long where addition and subtraction occur as separate steps over two variables. Only one variable can be modified. Also, the only reason why it won't work with such aggregate types is that the propagation from one variable to another via the carry-flag requires the same order of subtraction as addition. With a single register or memory operand, we don't care about the order of operations.
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.
Again, we don't need atomic operations for this.
The task that, for an instant, sees its key equal to the shared variable owns the lock. It is as simple as that.
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.
Cheers, Dick Johnson
Penguin : Linux version 2.3.13 on an i686 machine (400.59 BogoMips). Warning : It's hard to remain at the trailing edge of technology.
- 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/
| |