Messages in this thread Patch in this message | | | Date | Tue, 27 Dec 2005 15:15:54 +0100 | From | Ingo Molnar <> | Subject | [patch 05/11] mutex subsystem, add include/asm-arm/mutex.h |
| |
add the ARM version of mutex.h, which is optimized in assembly for ARMv6, and uses the xchg implementation on pre-ARMv6.
From: Nicolas Pitre <nico@cam.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
----
include/asm-arm/mutex.h | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 144 insertions(+)
Index: linux/include/asm-arm/mutex.h =================================================================== --- /dev/null +++ linux/include/asm-arm/mutex.h @@ -0,0 +1,144 @@ +/* + * include/asm-arm/mutex.h + * + * ARM optimized mutex locking primitives + * + * Please look into asm-generic/mutex-xchg.h for a formal definition. + */ +#ifndef _ASM_MUTEX_H +#define _ASM_MUTEX_H + +#if __LINUX_ARM_ARCH__ < 6 +/* On pre-ARMv6 hardware the swp based implementation is the most efficient. */ +# include <asm-generic/mutex-xchg.h> +#else + +/* + * Attempting to lock a mutex on ARMv6+ can be done with a bastardized + * atomic decrement (it is not a reliable atomic decrement but it satisfies + * the defined semantics for our purpose, while being smaller and faster + * than a real atomic decrement or atomic swap. The idea is to attempt + * decrementing the lock value only once. If once decremented it isn't zero, + * or if its store-back fails due to a dispute on the exclusive store, we + * simply bail out immediately through the slow path where the lock will be + * reattempted until it succeeds. + */ +#define __mutex_fastpath_lock(count, fail_fn) \ +do { \ + /* type-check the function too: */ \ + void fastcall (*__tmp)(atomic_t *) = fail_fn; \ + int __ex_flag, __res; \ + \ + (void)__tmp; \ + typecheck(atomic_t *, count); \ + \ + __asm__ ( \ + "ldrex %0, [%2] \n" \ + "sub %0, %0, #1 \n" \ + "strex %1, %0, [%2] \n" \ + \ + : "=&r" (__res), "=&r" (__ex_flag) \ + : "r" (&(count)->counter) \ + : "cc","memory" ); \ + \ + if (unlikely(__res || __ex_flag)) \ + fail_fn(count); \ +} while (0) + +#define __mutex_fastpath_lock_retval(count, fail_fn) \ +({ \ + /* type-check the function too: */ \ + int fastcall (*__tmp)(atomic_t *) = fail_fn; \ + int __ex_flag, __res; \ + \ + (void)__tmp; \ + typecheck(atomic_t *, count); \ + \ + __asm__ ( \ + "ldrex %0, [%2] \n" \ + "sub %0, %0, #1 \n" \ + "strex %1, %0, [%2] \n" \ + \ + : "=&r" (__res), "=&r" (__ex_flag) \ + : "r" (&(count)->counter) \ + : "cc","memory" ); \ + \ + __res |= __ex_flag; \ + if (unlikely(__res != 0)) \ + __res = fail_fn(count); \ + __res; \ +}) + +/* + * Same trick is used for the unlock fast path. However the original value, + * rather than the result, is used to test for success in order to have + * better generated assembly. + */ +#define __mutex_fastpath_unlock(count, fail_fn) \ +do { \ + /* type-check the function too: */ \ + void fastcall (*__tmp)(atomic_t *) = fail_fn; \ + int __ex_flag, __res, __orig; \ + \ + (void)__tmp; \ + typecheck(atomic_t *, count); \ + \ + __asm__ ( \ + "ldrex %0, [%3] \n" \ + "add %1, %0, #1 \n" \ + "strex %2, %1, [%3] \n" \ + \ + : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag) \ + : "r" (&(count)->counter) \ + : "cc","memory" ); \ + \ + if (unlikely(__orig || __ex_flag)) \ + fail_fn(count); \ +} while (0) + +/* + * If the unlock was done on a contended lock, or if the unlock simply fails + * then the mutex remains locked. + */ +#define __mutex_slowpath_needs_to_unlock() 1 + +/* + * For __mutex_fastpath_trylock we use another construct which could be + * described as an "incomplete atomic decrement" or a "single value cmpxchg" + * since it has two modes of failure: + * + * 1) if the exclusive store fails we fail, and + * + * 2) if the decremented value is not zero we don't even attempt the store. + * + * This provides the needed trylock semantics like cmpxchg would, but it is + * lighter and less generic than a true cmpxchg implementation. + */ +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fn_name)(atomic_t *)) +{ + int __ex_flag, __res; + + __asm__ ( + + "ldrex %0, [%2] \n" + "subs %0, %0, #1 \n" + "strexeq %1, %0, [%2] \n" + + : "=&r" (__res), "=&r" (__ex_flag) + : "r" (&count->counter) + : "cc", "memory" ); + + /* + * We must not return a synthetic 'failure' if the conditional + * did not succeed - drop back into the generic slowpath if + * this happens (should be rare): + */ + if (unlikely(__ex_flag)) + return fn_name(count); + + return __res == 0; +} + +#endif +#endif - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |