lkml.org 
[lkml]   [2018]   [Jun]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 7/9] asm-generic/bitops/lock.h: Rewrite using atomic_fetch_*
    Date
    The lock bitops can be implemented more efficiently using the atomic_fetch_*
    ops, which provide finer-grained control over the memory ordering semantics
    than the bitops.

    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Ingo Molnar <mingo@kernel.org>
    Signed-off-by: Will Deacon <will.deacon@arm.com>
    ---
    include/asm-generic/bitops/lock.h | 68 ++++++++++++++++++++++++++++++++-------
    1 file changed, 56 insertions(+), 12 deletions(-)

    diff --git a/include/asm-generic/bitops/lock.h b/include/asm-generic/bitops/lock.h
    index 67ab280ad134..3ae021368f48 100644
    --- a/include/asm-generic/bitops/lock.h
    +++ b/include/asm-generic/bitops/lock.h
    @@ -2,6 +2,10 @@
    #ifndef _ASM_GENERIC_BITOPS_LOCK_H_
    #define _ASM_GENERIC_BITOPS_LOCK_H_

    +#include <linux/atomic.h>
    +#include <linux/compiler.h>
    +#include <asm/barrier.h>
    +
    /**
    * test_and_set_bit_lock - Set a bit and return its old value, for lock
    * @nr: Bit to set
    @@ -11,7 +15,20 @@
    * the returned value is 0.
    * It can be used to implement bit locks.
    */
    -#define test_and_set_bit_lock(nr, addr) test_and_set_bit(nr, addr)
    +static inline int test_and_set_bit_lock(unsigned int nr,
    + volatile unsigned long *p)
    +{
    + long old;
    + unsigned long mask = BIT_MASK(nr);
    +
    + p += BIT_WORD(nr);
    + if (READ_ONCE(*p) & mask)
    + return 1;
    +
    + old = atomic_long_fetch_or_acquire(mask, (atomic_long_t *)p);
    + return !!(old & mask);
    +}
    +

    /**
    * clear_bit_unlock - Clear a bit in memory, for unlock
    @@ -20,11 +37,11 @@
    *
    * This operation is atomic and provides release barrier semantics.
    */
    -#define clear_bit_unlock(nr, addr) \
    -do { \
    - smp_mb__before_atomic(); \
    - clear_bit(nr, addr); \
    -} while (0)
    +static inline void clear_bit_unlock(unsigned int nr, volatile unsigned long *p)
    +{
    + p += BIT_WORD(nr);
    + atomic_long_fetch_andnot_release(BIT_MASK(nr), (atomic_long_t *)p);
    +}

    /**
    * __clear_bit_unlock - Clear a bit in memory, for unlock
    @@ -37,11 +54,38 @@ do { \
    *
    * See for example x86's implementation.
    */
    -#define __clear_bit_unlock(nr, addr) \
    -do { \
    - smp_mb__before_atomic(); \
    - clear_bit(nr, addr); \
    -} while (0)
    +static inline void __clear_bit_unlock(unsigned int nr,
    + volatile unsigned long *p)
    +{
    + unsigned long old;

    -#endif /* _ASM_GENERIC_BITOPS_LOCK_H_ */
    + p += BIT_WORD(nr);
    + old = READ_ONCE(*p);
    + old &= ~BIT_MASK(nr);
    + atomic_long_set_release((atomic_long_t *)p, old);
    +}
    +
    +/**
    + * clear_bit_unlock_is_negative_byte - Clear a bit in memory and test if bottom
    + * byte is negative, for unlock.
    + * @nr: the bit to clear
    + * @addr: the address to start counting from
    + *
    + * This is a bit of a one-trick-pony for the filemap code, which clears
    + * PG_locked and tests PG_waiters,
    + */
    +#ifndef clear_bit_unlock_is_negative_byte
    +static inline bool clear_bit_unlock_is_negative_byte(unsigned int nr,
    + volatile unsigned long *p)
    +{
    + long old;
    + unsigned long mask = BIT_MASK(nr);
    +
    + p += BIT_WORD(nr);
    + old = atomic_long_fetch_andnot_release(mask, (atomic_long_t *)p);
    + return !!(old & BIT(7));
    +}
    +#define clear_bit_unlock_is_negative_byte clear_bit_unlock_is_negative_byte
    +#endif

    +#endif /* _ASM_GENERIC_BITOPS_LOCK_H_ */
    --
    2.1.4
    \
     
     \ /
      Last update: 2018-06-01 18:08    [W:2.612 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site