mutex subsystem, add include/asm-i386/mutex.h
PATCH 3/11 mutex subsystem, add include/asm-i386/mutex.h
add the i386 version of mutex.h, optimized in assembly.
Signed-off-by Arjan van de Ven <[email protected]>
Signed-off-by Ingo Molnar <[email protected]>
----
include/asm-i386/mutex.h | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 140 insertions(+)
include/asm-i386/mutex.h new file +140 -0
@@ -0,0 +1,140 @@ +/* +* Assembly implementation of the mutex fastpath, based on atomic +* decrement/increment. +* +* started by Ingo Molnar: +* +* Copyright (C) 2004, 2005 Red Hat, Inc., Ingo Molnar <[email protected]> +*/ +#ifndef _ASM_MUTEX_H +#define _ASM_MUTEX_H + +/** +* __mutex_fastpath_lock - try to take the lock by moving the count +* from 1 to a 0 value +* @count: pointer of type atomic_t +* @fn: function to call if the original value was not 1 +* +* Change the count from 1 to a value lower than 1, and call <fn> if it +* wasn't 1 originally. This function MUST leave the value lower than 1 +* even when the "1" assertion wasn't true. +*/ +#define __mutex_fastpath_lock(count, fn_name) \ +do { \ + /* type-check the function too: */ \ + void fastcall (*__tmp)(atomic_t *) = fn_name; \ + unsigned int dummy; \ + \ + (void)__tmp; \ + typecheck(atomic_t *, count); \ + \ + __asm__ __volatile__( \ + LOCK " decl (%%eax) \n" \ + " js 2f \n" \ + "1: \n" \ + \ + LOCK_SECTION_START("") \ + "2: call "#fn_name" \n" \ + " jmp 1b \n" \ + LOCK_SECTION_END \ + \ + :"=a" (dummy) \ + : "a" (count) \ + : "memory", "ecx", "edx"); \ +} while (0) + + +/** +* __mutex_fastpath_lock_retval - try to take the lock by moving the count +* from 1 to a 0 value +* @count: pointer of type atomic_t +* @fn: function to call if the original value was not 1 +* +* Change the count from 1 to a value lower than 1, and call <fn> if it +* wasn't 1 originally. This function returns 0 if the fastpath succeeds, +* or anything the slow path function returns +*/ +static inline int +__mutex_fastpath_lock_retval (atomic_t *count, + int fastcall (*fn_name)(atomic_t *)) +{ +if (unlikely (atomic_dec_return (count) <0 )) +return fn_name (count); +else +return 0 ; +} + +/** +* __mutex_fastpath_unlock - try to promote the mutex from 0 to 1 +* @count: pointer of type atomic_t +* @fn: function to call if the original value was not 0 +* +* try to promote the mutex from 0 to 1. if it wasn't 0, call <fn>. +* In the failure case, this function is allowed to either set the value +* to 1, or to set it to a value lower than 1. +* +* If the implementation sets it to a value of lower than 1, the +* __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs +* to return 0 otherwise. +*/ +#define __mutex_fastpath_unlock(count, fn_name) \ +do { \ + /* type-check the function too: */ \ + void fastcall (*__tmp)(atomic_t *) = fn_name; \ + unsigned int dummy; \ + \ + (void)__tmp; \ + typecheck(atomic_t *, count); \ + \ + __asm__ __volatile__( \ + LOCK " incl (%%eax) \n" \ + " jle 2f \n" \ + "1: \n" \ + \ + LOCK_SECTION_START("") \ + "2: call "#fn_name" \n" \ + " jmp 1b \n" \ + LOCK_SECTION_END \ + \ + :"=a" (dummy) \ + : "a" (count) \ + : "memory", "ecx", "edx"); \ +} while (0) + +#define __mutex_slowpath_needs_to_unlock () 1 + +/** +* __mutex_fastpath_trylock - try to acquire the mutex, without waiting +* +* @count: pointer of type atomic_t +* @fn: fallback function +* +* Change the count from 1 to a value lower than 1, and return 0 (failure) +* if it wasn't 1 originally, or return 1 (success) otherwise. This function +* MUST leave the value lower than 1 even when the "1" assertion wasn't true. +* Additionally, if the value was < 0 originally, this function must not leave +* it to 0 on failure. +*/ +static inline int +__mutex_fastpath_trylock (atomic_t *count,int (*fn)(atomic_t *)) +{ +/* +* We have two variants here. The cmpxchg based one is the best one +* because it never induce a false contention state. It is included +* here because architectures using the inc/dec algorithms over the +* xchg ones are much more likely to support cmpxchg natively. +* +* If not we fall back to the spinlock based variant - that is +* just as efficient (and simpler) as a 'destructive' probing of +* the mutex state would be. +*/ +#ifdef __HAVE_ARCH_CMPXCHG +if (likely (atomic_cmpxchg (count,1 ,0 )) ==1 ) +return 1 ; +return 0 ; +#else +return fn (count); +#endif +} + +#endif