atomic_and()
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 6 Jun 2011 19:10:09 +0000 (12:10 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:04 +0000 (17:36 -0700)
Should work for RISCV - I don't have the compiler to check yet.

kern/arch/i686/atomic.h
kern/arch/riscv/atomic.h
kern/arch/sparc/atomic.h

index fae5c9b..b778275 100644 (file)
@@ -25,6 +25,7 @@ static inline void atomic_dec(atomic_t *number);
 static inline long atomic_fetch_and_add(atomic_t *number, long val);
 static inline bool atomic_add_not_zero(atomic_t *number, long val);
 static inline bool atomic_sub_and_test(atomic_t *number, long val);
+static inline void atomic_and(atomic_t *number, long mask);
 static inline void atomic_or(atomic_t *number, int mask);
 static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val);
 static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
@@ -58,7 +59,7 @@ static inline void atomic_set(atomic_t *number, int32_t val)
 
 static inline void atomic_add(atomic_t* number, long val)
 {
-       asm volatile("lock addl %1,%0" : "=m"(*number) : "r"(val));
+       asm volatile("lock addl %1,%0" : "=m"(*number) : "r"(val) : "cc");
 }
 
 // need to do this with pointers and deref.  %0 needs to be the memory address
@@ -107,6 +108,11 @@ static inline bool atomic_sub_and_test(atomic_t *number, long val)
        return b;
 }
 
+static inline void atomic_and(atomic_t *number, long mask)
+{
+       asm volatile("lock andl %1,%0" : "=m"(*number) : "q"(mask) : "cc");
+}
+
 static inline void atomic_or(atomic_t *number, int mask)
 {
        asm volatile("lock orl %1,%0" : "=m"(*number) : "q"(mask) : "cc");
index 4cf6fe5..408fd4e 100644 (file)
@@ -69,6 +69,11 @@ static inline bool atomic_sub_and_test(atomic_t* number, uintptr_t val)
        return __sync_fetch_and_sub((uintptr_t*)number, val) == val;
 }
 
+static inline void atomic_and(atomic_t *number, uintptr_t mask)
+{
+       __sync_fetch_and_and(number, mask);
+}
+
 static inline void atomic_or(atomic_t* number, uintptr_t mask)
 {
        __sync_fetch_and_or(number, mask);
index ea5f8b1..7a03176 100644 (file)
@@ -31,6 +31,7 @@ static inline void atomic_dec(atomic_t* number);
 static inline long atomic_fetch_and_add(atomic_t *number, long val);
 static inline bool atomic_add_not_zero(atomic_t *number, long val);
 static inline bool atomic_sub_and_test(atomic_t *number, long val);
+static inline void atomic_and(atomic_t *number, long mask);
 static inline void atomic_or(atomic_t *number, int mask);
 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val);
 static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
@@ -127,6 +128,19 @@ static inline bool atomic_sub_and_test(atomic_t *number, long val)
        return retval;
 }
 
+static inline void atomic_and(atomic_t *number, long mask)
+{
+       long val;
+       /* this is pretty clever.  the lower 8 bits (i.e byte 3)
+        * of the atomic_t serve as a spinlock.  let's acquire it. */
+       spin_lock((spinlock_t*)number);
+       val = atomic_read(number);
+       /* compute new counter value. */
+       val &= mask;
+       /* set the new counter value.  the lock is cleared (for free) */
+       atomic_init(number, val);
+}
+
 static inline void atomic_or(atomic_t *number, int mask)
 {
        int val;