Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] 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.

Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Nicolas Pitre and committed by
Ingo Molnar
823d0f4f b8aa0361

+128
+128
include/asm-arm/mutex.h
··· 1 + /* 2 + * include/asm-arm/mutex.h 3 + * 4 + * ARM optimized mutex locking primitives 5 + * 6 + * Please look into asm-generic/mutex-xchg.h for a formal definition. 7 + */ 8 + #ifndef _ASM_MUTEX_H 9 + #define _ASM_MUTEX_H 10 + 11 + #if __LINUX_ARM_ARCH__ < 6 12 + /* On pre-ARMv6 hardware the swp based implementation is the most efficient. */ 13 + # include <asm-generic/mutex-xchg.h> 14 + #else 15 + 16 + /* 17 + * Attempting to lock a mutex on ARMv6+ can be done with a bastardized 18 + * atomic decrement (it is not a reliable atomic decrement but it satisfies 19 + * the defined semantics for our purpose, while being smaller and faster 20 + * than a real atomic decrement or atomic swap. The idea is to attempt 21 + * decrementing the lock value only once. If once decremented it isn't zero, 22 + * or if its store-back fails due to a dispute on the exclusive store, we 23 + * simply bail out immediately through the slow path where the lock will be 24 + * reattempted until it succeeds. 25 + */ 26 + #define __mutex_fastpath_lock(count, fail_fn) \ 27 + do { \ 28 + int __ex_flag, __res; \ 29 + \ 30 + typecheck(atomic_t *, count); \ 31 + typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ 32 + \ 33 + __asm__ ( \ 34 + "ldrex %0, [%2] \n" \ 35 + "sub %0, %0, #1 \n" \ 36 + "strex %1, %0, [%2] \n" \ 37 + \ 38 + : "=&r" (__res), "=&r" (__ex_flag) \ 39 + : "r" (&(count)->counter) \ 40 + : "cc","memory" ); \ 41 + \ 42 + if (unlikely(__res || __ex_flag)) \ 43 + fail_fn(count); \ 44 + } while (0) 45 + 46 + #define __mutex_fastpath_lock_retval(count, fail_fn) \ 47 + ({ \ 48 + int __ex_flag, __res; \ 49 + \ 50 + typecheck(atomic_t *, count); \ 51 + typecheck_fn(fastcall int (*)(atomic_t *), fail_fn); \ 52 + \ 53 + __asm__ ( \ 54 + "ldrex %0, [%2] \n" \ 55 + "sub %0, %0, #1 \n" \ 56 + "strex %1, %0, [%2] \n" \ 57 + \ 58 + : "=&r" (__res), "=&r" (__ex_flag) \ 59 + : "r" (&(count)->counter) \ 60 + : "cc","memory" ); \ 61 + \ 62 + __res |= __ex_flag; \ 63 + if (unlikely(__res != 0)) \ 64 + __res = fail_fn(count); \ 65 + __res; \ 66 + }) 67 + 68 + /* 69 + * Same trick is used for the unlock fast path. However the original value, 70 + * rather than the result, is used to test for success in order to have 71 + * better generated assembly. 72 + */ 73 + #define __mutex_fastpath_unlock(count, fail_fn) \ 74 + do { \ 75 + int __ex_flag, __res, __orig; \ 76 + \ 77 + typecheck(atomic_t *, count); \ 78 + typecheck_fn(fastcall void (*)(atomic_t *), fail_fn); \ 79 + \ 80 + __asm__ ( \ 81 + "ldrex %0, [%3] \n" \ 82 + "add %1, %0, #1 \n" \ 83 + "strex %2, %1, [%3] \n" \ 84 + \ 85 + : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag) \ 86 + : "r" (&(count)->counter) \ 87 + : "cc","memory" ); \ 88 + \ 89 + if (unlikely(__orig || __ex_flag)) \ 90 + fail_fn(count); \ 91 + } while (0) 92 + 93 + /* 94 + * If the unlock was done on a contended lock, or if the unlock simply fails 95 + * then the mutex remains locked. 96 + */ 97 + #define __mutex_slowpath_needs_to_unlock() 1 98 + 99 + /* 100 + * For __mutex_fastpath_trylock we use another construct which could be 101 + * described as a "single value cmpxchg". 102 + * 103 + * This provides the needed trylock semantics like cmpxchg would, but it is 104 + * lighter and less generic than a true cmpxchg implementation. 105 + */ 106 + static inline int 107 + __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) 108 + { 109 + int __ex_flag, __res, __orig; 110 + 111 + __asm__ ( 112 + 113 + "1: ldrex %0, [%3] \n" 114 + "subs %1, %0, #1 \n" 115 + "strexeq %2, %1, [%3] \n" 116 + "movlt %0, #0 \n" 117 + "cmpeq %2, #0 \n" 118 + "bgt 1b \n" 119 + 120 + : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag) 121 + : "r" (&count->counter) 122 + : "cc", "memory" ); 123 + 124 + return __orig; 125 + } 126 + 127 + #endif 128 + #endif