Adds useful atomics
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 28 Jul 2010 21:50:44 +0000 (14:50 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:49 +0000 (17:35 -0700)
kern/arch/i686/atomic.h
kern/arch/sparc/atomic.h

index 70716a8..b79bfd8 100644 (file)
@@ -20,8 +20,11 @@ typedef struct spinlock RACY spinlock_t;
 static inline void atomic_init(atomic_t *number, int32_t val);
 static inline int32_t atomic_read(atomic_t *number);
 static inline void atomic_set(atomic_t *number, int32_t val);
+static inline void atomic_add(atomic_t* number, long val);
 static inline void atomic_inc(atomic_t *number);
 static inline void atomic_dec(atomic_t *number);
+static inline long atomic_fetch_and_add(atomic_t *number, long val);
+static inline bool atomic_sub_and_test(atomic_t *number, long val);
 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,
                                     uint32_t new_val);
@@ -52,6 +55,11 @@ static inline void atomic_set(atomic_t *number, int32_t val)
        asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
 }
 
+static inline void atomic_add(atomic_t* number, long val)
+{
+       asm volatile("lock addl %1,%0" : "=m"(*number) : "r"(val));
+}
+
 // need to do this with pointers and deref.  %0 needs to be the memory address
 static inline void atomic_inc(atomic_t *number)
 {
@@ -65,6 +73,25 @@ static inline void atomic_dec(atomic_t *number)
        asm volatile("lock decl %0" : "=m"(*number) : : "cc");
 }
 
+/* Adds val to number, returning number's original value */
+static inline long atomic_fetch_and_add(atomic_t *number, long val)
+{
+       asm volatile("lock xadd %0,%1" : "=r"(val), "=m"(*number)
+                                      : "0"(val), "m"(*number)
+                                      : "cc" );
+       return val;
+}
+
+/* Subtraces val from number, returning True if the new value is 0. */
+static inline bool atomic_sub_and_test(atomic_t *number, long val)
+{
+       bool b;
+       asm volatile("lock sub %2,%1; setz %0" : "=r"(b), "=m"(*number)
+                                              : "r"(val), "m"(*number)
+                                              : "cc" );
+       return b;
+}
+
 static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val)
 {
        // this would work, but its code is bigger, and it's not like the others
index f2d060d..1adf268 100644 (file)
@@ -28,6 +28,8 @@ static inline void atomic_set(atomic_t* number, int32_t val);
 static inline void atomic_add(atomic_t* number, int32_t inc);
 static inline void atomic_inc(atomic_t* number);
 static inline void atomic_dec(atomic_t* number);
+static inline long atomic_fetch_and_add(atomic_t *number, long val);
+static inline bool atomic_sub_and_test(atomic_t *number, long val);
 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,
                                     uint32_t new_val);
@@ -53,15 +55,7 @@ static inline int32_t atomic_read(atomic_t* number)
 
 static inline void atomic_add(atomic_t* number, int32_t inc)
 {
-       // this is pretty clever.  the lower 8 bits (i.e byte 3)
-       // of the atomic_t serve as a spinlock.  let's acquire it.
-       { TRUSTEDBLOCK spin_lock((spinlock_t*)number); }
-
-       // compute new counter value.
-       inc += atomic_read(number);
-
-       // set the new counter value.  the lock is cleared (for free)
-       atomic_init(number,inc);
+       atomic_fetch_and_add(number, inc);
 }
 
 static inline void atomic_set(atomic_t* number, int32_t val)
@@ -81,6 +75,31 @@ static inline void atomic_dec(atomic_t* number)
        atomic_add(number,-1);
 }
 
+/* Adds val to number, returning number's original value */
+static inline long atomic_fetch_and_add(atomic_t *number, long val)
+{
+       long retval;
+       /* 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);
+       retval = atomic_read(number);
+       /* compute new counter value. */
+       val += retval;
+       /* set the new counter value.  the lock is cleared (for free) */
+       atomic_init(number, val);
+       return retval;
+}
+
+/* Subtraces val from number, returning True if the new value is 0. */
+static inline bool atomic_sub_and_test(atomic_t *number, long val)
+{
+       long retval = atomic_fetch_and_add(number, -val);
+       if (retval)
+               return FALSE;
+       else
+               return TRUE;
+}
+
 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val)
 {
        __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");