base: add memory barrier before releasing lock

When releasing a lock we must take care that all state is written back to
memory and is not cached in registers. The volatile flag of the lock variable
only means to the compiler that this value must be written immediately.
Other values changed before may be kept by the compiler in registers, which we
don't want here.

Additionally the compiler is free to reorder the code in order to optimize.
That means the code we intend to be executed inside the critical section can
get be reordered and can be executed after we reset the lock variable in the
unlock implementation. The volatile statement of the lock variable doesn't
prevent reordering of instructions which are independent.

By adding a explicit memory barrier, we force the compiler to generate code
that writes back all the register content to memory/cache (and avoid a
bunch of hard to find bugs ...)
This commit is contained in:
Alexander Boettcher 2012-12-05 11:09:41 +01:00 committed by Norman Feske
parent 0d7c6efa84
commit ca37f26a01
1 changed files with 4 additions and 0 deletions

View File

@ -29,6 +29,8 @@
enum State { SPINLOCK_LOCKED, SPINLOCK_UNLOCKED };
static inline void memory_barrier() { asm volatile ("" : : : "memory"); }
static inline void spinlock_lock(volatile int *lock_variable)
{
while (!Genode::cmpxchg(lock_variable, SPINLOCK_UNLOCKED, SPINLOCK_LOCKED)) {
@ -43,6 +45,8 @@ static inline void spinlock_lock(volatile int *lock_variable)
static inline void spinlock_unlock(volatile int *lock_variable)
{
/* make sure all got written by compiler before releasing lock */
memory_barrier();
*lock_variable = SPINLOCK_UNLOCKED;
}