Atomics rewrite (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 8 Jun 2011 01:29:10 +0000 (18:29 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:04 +0000 (17:36 -0700)
The atomics have been slowly drifting out of control, esp with 64-bit
unfriendliness; this patch ought to fix some things.

1) All atomic ops take an atomic_t*, and if there are values added or
subtracted, they are longs.  The atomic_t helps ensure we only use
atomic ops on atomic variables.

2) Atomic ops on other types have their own functions, denoting the
type, such as atomic_cas_u32().  Careful using these, since you may have
other references to those vars that aren't atomic.

3) BCQs use u32s for their buffer indexes.  If we have programs that are
32 bit on a 64 bit kernel, we would have trouble if we tried using 64
bit values.

4) k/i/atomic.h now is the source of the function prototypes.  They are
extern inlines, which requires -fgnu-89inline (which we've been using),
allowing arches to implement the functions however they'd like, such as
with static inlines or with a regular function (like x86's
spinlock_debug() or riscv's CAS ops).

5) Some users of atomic_swap were cleaned up to represent its status as
an atomic, mostly in userlevel locking code.  Userlevel condition
variables use swap_u32(), which may not be what people want.  That bit
of code is a bit unmaintained at this point.

6) Userspace does not unify its atomics in an inc/atomic.h, since glibc
has its own atomic.h.  There will be a reckoning for userspace at some
point, dealing with the collision of atomic naming with glibc.  It's not
really the kernel's concern.  Also note that I didn't want to force the
-fgnu89-inline on userspace.

7) Rebuild your cross compiler/glibc.  Everything compiles on sparc and
x86.  I haven't been able to try riscv yet.

20 files changed:
kern/arch/i686/atomic.h
kern/arch/riscv/atomic.c
kern/arch/riscv/atomic.h
kern/arch/sparc/atomic.h
kern/include/atomic.h
kern/include/ros/atomic.h
kern/include/ros/bcq.h
kern/include/ros/bcq_struct.h
kern/include/ros/syscall.h
kern/src/blockdev.c
kern/src/syscall.c
kern/src/testing.c
user/parlib/bthread.c
user/parlib/include/bthread.h
user/parlib/include/i686/atomic.h
user/parlib/include/sparc/atomic.h
user/parlib/mcs.c
user/parlib/uthread.c
user/pthread/pthread.c
user/pthread/pthread.h

index b778275..5bf2021 100644 (file)
@@ -1,63 +1,39 @@
-#ifndef ROS_INCLUDE_ATOMIC_H
-#define ROS_INCLUDE_ATOMIC_H
+/* Copyright (c) 2009-2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * x86 atomics and locking functions. */
+
+#ifndef ROS_KERN_ARCH_ATOMIC_H
+#define ROS_KERN_ARCH_ATOMIC_H
 
 #include <ros/common.h>
 #include <ros/arch/membar.h>
 #include <arch/x86.h>
 #include <arch/arch.h>
-typedef void * RACY atomic_t;
-struct spinlock {
-       volatile uint32_t RACY rlock;
-#ifdef __CONFIG_SPINLOCK_DEBUG__
-       void *call_site;        
-       uint32_t calling_core;
-#endif
-};
-typedef struct spinlock spinlock_t;
-#define SPINLOCK_INITIALIZER {0}
-
-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_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,
-                                    uint32_t new_val);
+
 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
-static inline uint32_t spin_locked(spinlock_t *SAFE lock);
-static inline void __spin_lock(volatile uint32_t SRACY*CT(1) rlock);
-static inline void spin_lock(spinlock_t *lock);
-static inline void spin_unlock(spinlock_t *lock);
-static inline void spinlock_init(spinlock_t *lock);
-void spinlock_debug(spinlock_t *lock);
 
 /* Inlined functions declared above */
-static inline void atomic_init(atomic_t *number, int32_t val)
+static inline void atomic_init(atomic_t *number, long val)
 {
        asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
 }
 
-static inline int32_t atomic_read(atomic_t *number)
+static inline long atomic_read(atomic_t *number)
 {
-       int32_t val;
+       long val;
        asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
        return val;
 }
 
-static inline void atomic_set(atomic_t *number, int32_t val)
+static inline void atomic_set(atomic_t *number, long val)
 {
        asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
 }
 
-static inline void atomic_add(atomic_tnumber, long val)
+static inline void atomic_add(atomic_t *number, long val)
 {
        asm volatile("lock addl %1,%0" : "=m"(*number) : "r"(val) : "cc");
 }
@@ -84,41 +60,17 @@ static inline long atomic_fetch_and_add(atomic_t *number, long val)
        return val;
 }
 
-/* Adds val to number, so long as number was not zero.  Returns TRUE if the
- * operation succeeded (added, not zero), returns FALSE if number is zero. */
-static inline bool atomic_add_not_zero(atomic_t *number, long val)
-{
-       long old_num, new_num;
-       do {
-               old_num = atomic_read(number);
-               if (!old_num)
-                       return FALSE;
-               new_num = old_num + val;
-       } while (!atomic_comp_swap((uint32_t*)number, old_num, new_num));
-       return TRUE;
-}
-
-/* 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" : "=q"(b), "=m"(*number)
-                                              : "r"(val), "m"(*number)
-                                              : "cc" );
-       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)
+static inline void atomic_or(atomic_t *number, long mask)
 {
        asm volatile("lock orl %1,%0" : "=m"(*number) : "q"(mask) : "cc");
 }
 
-static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val)
+static inline long atomic_swap(atomic_t *addr, long val)
 {
        // this would work, but its code is bigger, and it's not like the others
        //asm volatile("xchgl %0,(%2)" : "=r"(val) : "0"(val), "r"(addr) : "memory");
@@ -128,8 +80,7 @@ static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val)
 
 /* reusing exp_val for the bool return.  1 (TRUE) for success (like test).  Need
  * to zero eax, since it will get set if the cmpxchgl failed. */
-static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
-                                    uint32_t new_val)
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
 {
        asm volatile("lock cmpxchgl %4,%1; movl $0,%%eax; sete %%al"
                     : "=a"(exp_val), "=m"(*addr)
@@ -138,6 +89,41 @@ static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
        return exp_val;
 }
 
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
+/* Adds val to number, so long as number was not zero.  Returns TRUE if the
+ * operation succeeded (added, not zero), returns FALSE if number is zero. */
+static inline bool atomic_add_not_zero(atomic_t *number, long val)
+{
+       long old_num, new_num;
+       do {
+               old_num = atomic_read(number);
+               if (!old_num)
+                       return FALSE;
+               new_num = old_num + val;
+       } while (!atomic_cas(number, old_num, new_num));
+       return TRUE;
+}
+
+/* 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" : "=q"(b), "=m"(*number)
+                                              : "r"(val), "m"(*number)
+                                              : "cc" );
+       return b;
+}
+
 /* Be sure to use "q" for byte operations (compared to longs), since this
  * constrains the asm to use e{a,b,c,d}x instead of esi and edi.  32 bit x86
  * cannot access the lower parts of esi or edi (will get warnings like "no such
@@ -152,7 +138,7 @@ static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
        asm volatile("lock orb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
 }
 
-static inline uint32_t spin_locked(spinlock_t *SAFE lock)
+static inline bool spin_locked(spinlock_t *lock)
 {
        // the lock status is the lowest byte of the lock
        return lock->rlock & 0xff;
@@ -205,4 +191,4 @@ WRITES(lock->rlock)
 #endif
 }
 
-#endif /* !ROS_INCLUDE_ATOMIC_H */
+#endif /* ROS_KERN_ARCH_ATOMIC_H */
index 8c54229..bbe10eb 100644 (file)
@@ -3,7 +3,34 @@
 // This emulates compare and swap by hashing the address into one of
 // K buckets, acquiring the lock for that bucket, then performing the
 // operation during the critical section.  :-(
-bool atomic_comp_swap(uintptr_t *addr, uintptr_t exp_val, uintptr_t new_val)
+bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+{
+       if ((long)*addr != exp_val)
+               return 0;
+       
+  #define K 17
+       static spinlock_t cas_locks[K*HW_CACHE_ALIGN/sizeof(spinlock_t)];
+
+  uintptr_t bucket = (uintptr_t)addr / sizeof(uintptr_t) % K;
+       spinlock_t* lock = &cas_locks[bucket*HW_CACHE_ALIGN/sizeof(spinlock_t)];
+       
+       bool retval = 0;
+       spin_lock_irqsave(lock);
+       if ((long)*addr == exp_val) {
+               atomic_swap(addr, new_val);
+               retval = 1;
+       }
+       spin_unlock_irqsave(lock);
+       return retval;
+}
+
+bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
+/* Ghetto, copied the regular CAS code... */
+bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val, uint32_t new_val)
 {
        if (*addr != exp_val)
                return 0;
@@ -17,7 +44,7 @@ bool atomic_comp_swap(uintptr_t *addr, uintptr_t exp_val, uintptr_t new_val)
        bool retval = 0;
        spin_lock_irqsave(lock);
        if (*addr == exp_val) {
-               atomic_swap(addr, new_val);
+               atomic_swap_u32(addr, new_val);
                retval = 1;
        }
        spin_unlock_irqsave(lock);
index 408fd4e..95c12b7 100644 (file)
@@ -1,85 +1,85 @@
-#ifndef ROS_INCLUDE_ATOMIC_H
-#define ROS_INCLUDE_ATOMIC_H
+#ifndef ROS_KERN_ARCH_ATOMIC_H
+#define ROS_KERN_ARCH_ATOMIC_H
 
 #include <ros/common.h>
 #include <arch/arch.h>
 
-typedef void* atomic_t;
-struct spinlock {
-       volatile uint32_t rlock;
-};
-typedef struct spinlock spinlock_t;
-#define SPINLOCK_INITIALIZER {0}
+bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
+bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val, uint32_t new_val);
 
-bool atomic_comp_swap(uintptr_t* addr, uintptr_t exp_val, uintptr_t new_val);
-
-static inline void atomic_init(atomic_t* number, uintptr_t val)
+static inline void atomic_init(atomic_t *number, long val)
 {
-  *(uintptr_t*)number = val;
+  *(long*)number = val;
 }
 
-static inline uintptr_t atomic_read(atomic_t* number)
+static inline long atomic_read(atomic_t *number)
 {
-  return *(uintptr_t*)number;
+  return *(long*)number;
 }
 
-static inline void atomic_set(atomic_t* number, uintptr_t val)
+static inline void atomic_set(atomic_t *number, long val)
 {
-  *(uintptr_t*)number = val;
+  *(long*)number = val;
 }
 
 /* Adds val to number, returning number's original value */
-static inline uintptr_t atomic_fetch_and_add(atomic_t* number, uintptr_t val)
+static inline long atomic_fetch_and_add(atomic_t *number, long val)
 {
-       return __sync_fetch_and_add((uintptr_t*)number, val);
+       return __sync_fetch_and_add((long*)number, val);
 }
 
-static inline void atomic_add(atomic_t* number, uintptr_t val)
+static inline void atomic_add(atomic_t *number, long val)
 {
        atomic_fetch_and_add(number, val);
 }
 
-static inline void atomic_inc(atomic_tnumber)
+static inline void atomic_inc(atomic_t *number)
 {
        atomic_add(number, 1);
 }
 
-static inline void atomic_dec(atomic_tnumber)
+static inline void atomic_dec(atomic_t *number)
 {
        atomic_add(number, -1);
 }
 
 /* Adds val to number, so long as number was not zero. Returns TRUE if the
  * operation succeeded (added, not zero), returns FALSE if number is zero. */
-static inline bool atomic_add_not_zero(atomic_t* number, uintptr_t val)
+static inline bool atomic_add_not_zero(atomic_t *number, long val)
 {
-       uintptr_t old_num, new_num;
+       long old_num, new_num;
        do {
                old_num = atomic_read(number);
                if (!old_num)
                        return FALSE;
                new_num = old_num + val;
-       } while (!atomic_comp_swap((uintptr_t*)number, old_num, new_num));
+       } while (!atomic_cas(number, old_num, new_num));
        return TRUE;
 }
 
 /* Subtraces val from number, returning True if the new value is 0. */
-static inline bool atomic_sub_and_test(atomic_t* number, uintptr_t val)
+static inline bool atomic_sub_and_test(atomic_t *number, long val)
 {
-       return __sync_fetch_and_sub((uintptr_t*)number, val) == val;
+       return __sync_fetch_and_sub((long*)number, val) == val;
 }
 
-static inline void atomic_and(atomic_t *number, uintptr_t mask)
+static inline void atomic_and(atomic_t *number, long mask)
 {
        __sync_fetch_and_and(number, mask);
 }
 
-static inline void atomic_or(atomic_t* number, uintptr_t mask)
+static inline void atomic_or(atomic_t *number, long mask)
 {
        __sync_fetch_and_or(number, mask);
 }
 
-static inline uintptr_t atomic_swap(uintptr_t* addr, uintptr_t val)
+static inline long atomic_swap(atomic_t *addr, long val)
+{
+       return __sync_lock_test_and_set(addr, val); // yes, really
+}
+
+static inline long atomic_swap_u32(uint32_t *addr, uint32_t val)
 {
        return __sync_lock_test_and_set(addr, val); // yes, really
 }
@@ -135,4 +135,4 @@ static inline void spinlock_debug(spinlock_t* lock)
 {
 }
 
-#endif /* !ROS_INCLUDE_ATOMIC_H */
+#endif /* ROS_KERN_ARCH_ATOMIC_H */
index 7a03176..c2522df 100644 (file)
@@ -1,98 +1,68 @@
-#ifndef ROS_INCLUDE_ATOMIC_H
-#define ROS_INCLUDE_ATOMIC_H
+#ifndef ROS_KERN_ARCH_ATOMIC_H
+#define ROS_KERN_ARCH_ATOMIC_H
 
 #include <ros/common.h>
 #include <ros/arch/membar.h>
 
-typedef struct
-{
-       volatile uint32_t rlock;
-} spinlock_t;
-
 /* This needs to be declared over here so that comp_and_swap down below can use
  * it.  Remove this when RAMP has a proper atomic compare and swap.  (TODO) */
-static inline void
-(SLOCK(0) spin_lock_irqsave)(spinlock_t RACY*SAFE lock);
-static inline void
-(SUNLOCK(0) spin_unlock_irqsave)(spinlock_t RACY*SAFE lock);
-static inline bool spin_lock_irq_enabled(spinlock_t *SAFE lock);
-
-#define SPINLOCK_INITIALIZER {0}
-
-// atomic_t is void*, so we can't accidentally dereference it
-typedef void* atomic_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, 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_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,
-                                    uint32_t new_val);
-static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
-static inline uint32_t spin_locked(spinlock_t*SAFE lock);
-static inline void spin_lock(spinlock_t*SAFE lock);
-static inline void spin_unlock(spinlock_t*SAFE lock);
-
-/* Inlined functions declared above */
-
-static inline void atomic_init(atomic_t* number, int32_t val)
+static inline void spin_lock_irqsave(spinlock_t *lock);
+static inline void spin_unlock_irqsave(spinlock_t *lock);
+/* Same deal with spin locks.  Note that Sparc can deadlock on an atomic op
+ * called from interrupt context (TODO) */
+static inline void spin_lock(spinlock_t *lock);
+
+/* Actual functions */
+static inline void atomic_init(atomic_t *number, long val)
 {
        val <<= 8;
        __asm__ __volatile__ ("st %0,[%1]" : : "r"(val), "r"(number) : "memory");
 }
 
-static inline int32_t atomic_read(atomic_t* number)
+static inline long atomic_read(atomic_t *number)
 {
-       int32_t val;
+       long val;
        __asm__ __volatile__ ("ld [%1],%0" : "=r"(val) : "r"(number));
        return val >> 8;
 }
 
-static inline void atomic_add(atomic_t* number, int32_t inc)
+/* Adds val to number, returning number's original value */
+static inline long atomic_fetch_and_add(atomic_t *number, long val)
 {
-       atomic_fetch_and_add(number, inc);
+       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;
 }
 
-static inline void atomic_set(atomic_t* number, int32_t val)
+static inline void atomic_add(atomic_t *number, long val)
+{
+       atomic_fetch_and_add(number, val);
+}
+
+static inline void atomic_set(atomic_t *number, long val)
 {
        // this works basically the same as atomic_add... but without the add
        spin_lock((spinlock_t*)number);
        atomic_init(number,val);
 }
 
-static inline void atomic_inc(atomic_tnumber)
+static inline void atomic_inc(atomic_t *number)
 {
        atomic_add(number,1);
 }
 
-static inline void atomic_dec(atomic_tnumber)
+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;
-}
-
 /* Adds val to number, so long as number was not zero.  Returns TRUE if the
  * operation succeeded (added, not zero), returns FALSE if number is zero. */
 static inline bool atomic_add_not_zero(atomic_t *number, long val)
@@ -141,9 +111,9 @@ static inline void atomic_and(atomic_t *number, long mask)
        atomic_init(number, val);
 }
 
-static inline void atomic_or(atomic_t *number, int mask)
+static inline void atomic_or(atomic_t *number, long mask)
 {
-       int val;
+       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);
@@ -154,24 +124,23 @@ static inline void atomic_or(atomic_t *number, int mask)
        atomic_init(number, val);
 }
 
-static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val)
+static inline long atomic_swap(atomic_t *addr, long val)
 {
        __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");
        return val;
 }
 
 // TODO: make this better! (no global locks, etc)
-static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
-                                    uint32_t new_val)
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
 {
        bool retval = 0;
-       uint32_t temp;
+       long temp;
        static spinlock_t cas_lock = SPINLOCK_INITIALIZER;
 
-       if (*addr != exp_val)
+       if ((long)*addr != exp_val)
                return 0;
        spin_lock_irqsave(&cas_lock);
-       if (*addr == exp_val) {
+       if ((long)*addr == exp_val) {
                atomic_swap(addr, new_val);
                retval = 1;
        }
@@ -179,6 +148,17 @@ static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
        return retval;
 }
 
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
 static inline uint32_t spin_trylock(spinlock_t*SAFE lock)
 {
        uint32_t reg;
@@ -186,11 +166,11 @@ static inline uint32_t spin_trylock(spinlock_t*SAFE lock)
        return reg;
 }
 
-static inline uint32_t spin_locked(spinlock_t*SAFE lock)
+static inline bool spin_locked(spinlock_t*SAFE lock)
 {
        uint32_t reg;
        __asm__ __volatile__ ("ldub [%1+3],%0" : "=r"(reg) : "r"(&lock->rlock));
-       return reg;
+       return (bool)reg;
 }
 
 static inline void spin_lock(spinlock_t*SAFE lock)
@@ -214,4 +194,4 @@ static inline void spinlock_debug(spinlock_t* lock)
 {
 }
 
-#endif /* !ROS_INCLUDE_ATOMIC_H */
+#endif /* ROS_KERN_ARCH_ATOMIC_H */
index 898547f..80d0877 100644 (file)
@@ -1,19 +1,65 @@
+/* Copyright (c) 2009-2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Kernel atomics and locking functions.
+ *
+ * The extern inline declarations are arch-dependent functions.  We do this
+ * so that each arch can either static inline or just have a regular function,
+ * whichever is appropriate. The actual implementation usually will be in
+ * arch/atomic.h (for inlines).
+ *
+ * The static inlines are defined farther down in the file (as always). */
+
 #ifndef ROS_KERN_ATOMIC_H
 #define ROS_KERN_ATOMIC_H
 
 #include <ros/common.h>
 #include <ros/atomic.h>
 #include <arch/mmu.h>
-#include <arch/atomic.h>
 #include <arch/arch.h>
 #include <assert.h>
 
-static inline void
-(SLOCK(0) spin_lock_irqsave)(spinlock_t RACY*SAFE lock);
-static inline void
-(SUNLOCK(0) spin_unlock_irqsave)(spinlock_t RACY*SAFE lock);
-static inline bool spin_lock_irq_enabled(spinlock_t *SAFE lock);
+/* Atomics */
+extern inline void atomic_init(atomic_t *number, long val);
+extern inline long atomic_read(atomic_t *number);
+extern inline void atomic_set(atomic_t *number, long val);
+extern inline void atomic_add(atomic_t *number, long val);
+extern inline void atomic_inc(atomic_t *number);
+extern inline void atomic_dec(atomic_t *number);
+extern inline long atomic_fetch_and_add(atomic_t *number, long val);
+extern inline void atomic_and(atomic_t *number, long mask);
+extern inline void atomic_or(atomic_t *number, long mask);
+extern inline long atomic_swap(atomic_t *addr, long val);
+extern inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+extern inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
+extern inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val);
+extern inline bool atomic_add_not_zero(atomic_t *number, long val);
+extern inline bool atomic_sub_and_test(atomic_t *number, long val);
+
+/* Spin locks */
+struct spinlock {
+       volatile uint32_t RACY rlock;
+#ifdef __CONFIG_SPINLOCK_DEBUG__
+       void *call_site;        
+       uint32_t calling_core;
+#endif
+};
+typedef struct spinlock spinlock_t;
+#define SPINLOCK_INITIALIZER {0}
+
+extern inline void spinlock_init(spinlock_t *lock);
+extern inline bool spin_locked(spinlock_t *lock);
+extern inline void spin_lock(spinlock_t *lock);
+extern inline void spin_unlock(spinlock_t *lock);
+extern inline void spinlock_debug(spinlock_t *lock);
+
+static inline void spin_lock_irqsave(spinlock_t *lock);
+static inline void spin_unlock_irqsave(spinlock_t *lock);
+static inline bool spin_lock_irq_enabled(spinlock_t *lock);
 
+/* Seq locks */
 /* An example seq lock, built from the counter.  I don't particularly like this,
  * since it forces you to use a specific locking type.  */
 typedef struct seq_lock {
@@ -28,6 +74,9 @@ static inline void write_sequnlock(seqlock_t *lock);
 static inline seq_ctr_t read_seqbegin(seqlock_t *lock);
 static inline bool read_seqretry(seqlock_t *lock, seq_ctr_t ctr);
 
+/* Arch-specific implementations / declarations go here */
+#include <arch/atomic.h>
+
 #define MAX_SPINS 1000000000
 
 /* Will spin for a little while, but not deadlock if it never happens */
@@ -182,4 +231,4 @@ static inline bool read_seqretry(seqlock_t *lock, seq_ctr_t ctr)
        return seqctr_retry(lock->r_ctr, ctr);
 }
 
-#endif /* !ROS_KERN_ATOMIC_H */
+#endif /* ROS_KERN_ATOMIC_H */
index d471cc2..29bb562 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <ros/common.h>
 
+typedef void* atomic_t;
+
 /* The seq counters are used by userspace to see if the kernel is updating
  * something or if something is valid, such as the vcore->pcore mapping.  The
  * way a reader can tell nothing has changed is to read the counter before and
@@ -37,4 +39,4 @@ static inline bool seqctr_retry(seq_ctr_t old_ctr, seq_ctr_t new_ctr)
        return (seq_is_locked(old_ctr)) || (old_ctr != new_ctr);        
 }
 
-#endif /* !ROS_INC_ATOMIC_H */
+#endif /* ROS_INC_ATOMIC_H */
index 53761eb..71214d9 100644 (file)
 
 #include <ros/common.h>
 #include <ros/bcq_struct.h>
-/* Each arch has some basic atomic ops.  We need comp_and_swap for now. */
-#include <arch/atomic.h>
 #include <string.h>
 
+/* Pain in the ass includes.  Glibc has an atomic.h, and eventually userspace
+ * will have to deal with the clobbering. */
+#ifdef ROS_KERNEL
+#include <atomic.h>
+#else
+#include <arch/atomic.h>
+#endif /* ROS_KERNEL */
+
 /* Bounded Concurrent Queues, untrusted consumer
  *
  * This is a producer/consumer circular buffer, in which the producer never
@@ -139,7 +145,7 @@ struct bcq_header {
                        break;                                                             \
                }                                                                      \
                __new_prod = __prod + 1;                                               \
-       } while (!atomic_comp_swap(&(_bcq)->hdr.prod_idx, __prod, __new_prod));    \
+       } while (!atomic_cas_u32(&(_bcq)->hdr.prod_idx, __prod, __new_prod));      \
        if (!__retval) {                                                           \
                /* from here out, __prod is the local __prod that we won */            \
                (_bcq)->wraps[__prod & ((_num_elems)-1)].elem = *(_elem);              \
@@ -163,7 +169,7 @@ struct bcq_header {
                        break;                                                             \
                }                                                                      \
                __new_cons_pvt = (__cons_pvt + 1);                                     \
-       } while (!atomic_comp_swap(&(_bcq)->hdr.cons_pvt_idx, __cons_pvt,          \
+       } while (!atomic_cas_u32(&(_bcq)->hdr.cons_pvt_idx, __cons_pvt,            \
                                   __new_cons_pvt));                               \
        if (!__retval) {                                                           \
                /* from here out, __cons_pvt is the local __cons_pvt that we won */    \
@@ -184,66 +190,4 @@ struct bcq_header {
 #define bcq_empty(_bcq)                                                        \
        BCQ_NO_WORK((_bcq)->hdr.prod_idx, (_bcq)->hdr.cons_pvt_idx)
 
-#if 0
-/* Original C Code, for posterity / debugging */
-static inline int enqueue(struct __name_bcq *bcq, __elem_t *elem,
-                          int num_fail)
-{
-       uint32_t __prod, __new_prod, __cons_pub, __failctr = 0;
-       do {
-               if ((num_fail) && (__failctr++ >= num_fail)) {
-                       printk("FAILED\n");
-                       return -EFAIL;
-               }
-               __prod = bcq->hdr.prod_idx;
-               __cons_pub = bcq->hdr.cons_pub_idx;
-       printk("# free slots : %d\n", BCQ_FREE_SLOTS(__prod, __cons_pub, __num_elems));
-
-//             printk("__prod = %p, cons_pub = %p\n", __prod, __cons_pub-1);
-//             printk("__prod mod = %p, cons_pub mod = %p\n", __prod &(__num_elems-1), (__cons_pub-1) &(__num_elems-1));
-
-               if (BCQ_FULL(__prod, __cons_pub, __num_elems)) {
-                       printk("BUSY\n");
-                       return -EBUSY;
-               }
-               __new_prod = __prod + 1;
-       } while (!atomic_comp_swap(&bcq->hdr.prod_idx, __prod, __new_prod));
-       /* from here out, __prod is the local __prod that we won */
-
-       printk("enqueuing to location %d\n", __prod & (__num_elems-1));
-
-       bcq->wraps[__prod & (__num_elems-1)].elem = *elem;
-       bcq->wraps[__prod & (__num_elems-1)].rdy_for_cons = TRUE;
-       return 0;
-}
-
-/* Similar to enqueue, spin afterwards til cons_pub is our element, then */
-/* advance it. */
-static inline int dequeue(struct __name_bcq *bcq, __elem_t *elem)
-{
-       uint32_t __prod, __cons_pvt, __new_cons_pvt, __cons_pub;
-       do {
-               __prod = bcq->hdr.prod_idx;
-               __cons_pvt = bcq->hdr.cons_pvt_idx;
-               if (BCQ_NO_WORK(__prod, __cons_pvt))
-                       return -EBUSY;
-               __new_cons_pvt = (__cons_pvt + 1);
-       } while (!atomic_comp_swap(&bcq->hdr.cons_pvt_idx, __cons_pvt,
-                                  __new_cons_pvt));
-       /* from here out, __cons_pvt is the local __cons_pvt that we won */
-       printk("dequeueing from location %d\n", __cons_pvt & (__num_elems-1));
-
-       /* wait for the producer to finish copying it in */
-       while (!bcq->wraps[__cons_pvt & (__num_elems-1)].rdy_for_cons)
-               cpu_relax();
-       *elem = bcq->wraps[__cons_pvt & (__num_elems-1)].elem;
-       bcq->wraps[__cons_pvt & (__num_elems-1)].rdy_for_cons = FALSE;
-       /* wait til we're the cons_pub, then advance it by one */
-       while (bcq->hdr.cons_pub_idx != __cons_pvt)
-               cpu_relax();
-       bcq->hdr.cons_pub_idx = __cons_pvt + 1;
-       return 0;
-}
-#endif
-
-#endif /* !ROS_INC_BCQ_H */
+#endif /* ROS_INC_BCQ_H */
index 0eab079..471416d 100644 (file)
@@ -8,10 +8,12 @@
 #ifndef ROS_INC_BCQ_STRUCT_H
 #define ROS_INC_BCQ_STRUCT_H
 
+#include <ros/common.h>
+
 struct bcq_header {
-       uintptr_t prod_idx;             /* next to be produced in */
-       uintptr_t cons_pub_idx; /* last completely consumed */
-       uintptr_t cons_pvt_idx; /* last a consumer has dibs on */
+       uint32_t prod_idx;              /* next to be produced in */
+       uint32_t cons_pub_idx;  /* last completely consumed */
+       uint32_t cons_pvt_idx;  /* last a consumer has dibs on */
 };
 
 #define DEFINE_BCQ_TYPES(__name, __elem_t, __num_elems)                        \
index c57204b..5c3d8e9 100644 (file)
@@ -1,11 +1,11 @@
-#ifndef ROS_INCLUDE_SYSCALL_H
-#define ROS_INCLUDE_SYSCALL_H
+#ifndef ROS_INC_SYSCALL_H
+#define ROS_INC_SYSCALL_H
 
 #include <arch/arch.h>
 #include <ros/bits/syscall.h>
 #include <ros/arch/syscall.h>
 #include <ros/event.h>
-#include <arch/atomic.h>
+#include <ros/atomic.h>
 
 /* Flags for an individual syscall.
  * Careful, sparc can't handle flags in byte 3. */
@@ -31,6 +31,8 @@ struct syscall {
 
 #ifndef ROS_KERNEL
 
+#include <arch/atomic.h>
+
 /* Attempts to block on sysc, returning when it is done or progress has been
  * made. */
 void ros_syscall_blockon(struct syscall *sysc);
@@ -90,4 +92,4 @@ static inline long __ros_syscall_errno(unsigned int _num, long _a0, long _a1,
 
 #endif /* ifndef ROS_KERNEL */
 
-#endif /* !ROS_INCLUDE_SYSCALL_H */
+#endif /* ROS_INC_SYSCALL_H */
index 453f397..3a40b8a 100644 (file)
@@ -239,7 +239,7 @@ retry:
        /* Normally, there'd be an ABA problem here, but we never actually remove
         * bhs from the chain until the whole page gets cleaned up, which can't
         * happen while we hold a reference to the page. */
-       if (!atomic_comp_swap((uintptr_t*)next_loc, (uintptr_t)bh, (uintptr_t)new)) {
+       if (!atomic_cas_ptr((void**)next_loc, bh, new)) {
                kmem_cache_free(bh_kcache, new);
                goto retry;
        }
index d82e5bb..0d785ac 100644 (file)
@@ -45,7 +45,7 @@ extern unsigned char device_mac[6];
 /* Tracing Globals */
 int systrace_flags = 0;
 struct systrace_record *systrace_buffer = 0;
-uintptr_t systrace_bufidx = 0;
+uint32_t systrace_bufidx = 0;
 size_t systrace_bufsize = 0;
 struct proc *systrace_procs[MAX_NUM_TRACED] = {0};
 spinlock_t systrace_lock = SPINLOCK_INITIALIZER;
@@ -1404,7 +1404,7 @@ intreg_t syscall(struct proc *p, uintreg_t sc_num, uintreg_t a0, uintreg_t a1,
                                do {
                                        idx = systrace_bufidx;
                                        new_idx = (idx + 1) % systrace_bufsize;
-                               } while (!atomic_comp_swap(&systrace_bufidx, idx, new_idx));
+                               } while (!atomic_cas_u32(&systrace_bufidx, idx, new_idx));
                                trace = &systrace_buffer[idx];
                                trace->timestamp = read_tsc();
                                trace->syscallno = sc_num;
@@ -1432,7 +1432,8 @@ void run_local_syscall(struct syscall *sysc)
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 
        /* TODO: (UMEM) assert / pin the memory for the sysc */
-       user_mem_assert(pcpui->cur_proc, sysc, sizeof(struct syscall), sizeof(uintptr_t), PTE_USER_RW);
+       user_mem_assert(pcpui->cur_proc, sysc, sizeof(struct syscall),
+                       sizeof(uintptr_t), PTE_USER_RW);
        pcpui->cur_sysc = sysc;                 /* let the core know which sysc it is */
        sysc->retval = syscall(pcpui->cur_proc, sysc->num, sysc->arg0, sysc->arg1,
                               sysc->arg2, sysc->arg3, sysc->arg4, sysc->arg5);
index 3ec3d6f..1cfd030 100644 (file)
@@ -1312,18 +1312,19 @@ void test_atomics(void)
        /* Simple test, make sure the bool retval of CAS handles failure */
        void test_cas_val(long init_val)
        {
-               long actual_num, old_num;
+               atomic_t actual_num;
+               long old_num;
                int attempt;
-               actual_num = init_val;
+               atomic_init(&actual_num, init_val);
                attempt = 0;
                do {
-                       old_num = actual_num;
+                       old_num = atomic_read(&actual_num);
                        /* First time, try to fail */
                        if (attempt == 0) 
                                old_num++;
                        attempt++;      
-               } while (!atomic_comp_swap((uintptr_t*)&actual_num, old_num, old_num + 10));
-               if (actual_num != init_val + 10)
+               } while (!atomic_cas(&actual_num, old_num, old_num + 10));
+               if (atomic_read(&actual_num) != init_val + 10)
                        printk("FUCK, CAS test failed for %d\n", init_val);
        }
        test_cas_val(257);
index 21ff428..912a13c 100644 (file)
@@ -138,7 +138,7 @@ int bthread_mutexattr_settype(bthread_mutexattr_t* attr, int type)
 int bthread_mutex_init(bthread_mutex_t* m, const bthread_mutexattr_t* attr)
 {
   m->attr = attr;
-  m->lock = 0;
+  atomic_init(&m->lock, 0);
   return 0;
 }
 
@@ -151,12 +151,12 @@ int bthread_mutex_lock(bthread_mutex_t* m)
 
 int bthread_mutex_trylock(bthread_mutex_t* m)
 {
-  return atomic_swap(&m->lock,1) == 0 ? 0 : EBUSY;
+  return atomic_swap(&m->lock, 1) == 0 ? 0 : EBUSY;
 }
 
 int bthread_mutex_unlock(bthread_mutex_t* m)
 {
-  m->lock = 0;
+  atomic_set(&m->lock, 0);
   return 0;
 }
 
@@ -269,7 +269,7 @@ void bthread_exit(void* ret)
 
 int bthread_once(bthread_once_t* once_control, void (*init_routine)(void))
 {
-  if(atomic_swap(once_control,1) == 0)
+  if (atomic_swap_u32(once_control, 1) == 0)
     init_routine();
   return 0;
 }
index 47c35f0..77ef49c 100644 (file)
@@ -34,7 +34,7 @@ typedef struct
 typedef struct
 {
   const bthread_mutexattr_t* attr;
-  int lock;
+  atomic_t lock;
 } bthread_mutex_t;
 
 typedef struct
@@ -54,7 +54,7 @@ typedef struct
 typedef struct
 {
   const bthread_condattr_t* attr;
-  int waiters[MAX_VCORES];
+  uint32_t waiters[MAX_VCORES];
 } bthread_cond_t;
 
 typedef struct bthread_wqt work_queue_t;
index f7358a2..421cbb0 100644 (file)
@@ -1,35 +1,38 @@
-#ifndef PARLIB_ATOMIC_H
-#define PARLIB_ATOMIC_H
+#ifndef PARLIB_ARCH_ATOMIC_H
+#define PARLIB_ARCH_ATOMIC_H
 
 #include <ros/common.h>
+#include <ros/atomic.h>
 
-typedef void * RACY atomic_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_init(atomic_t *number, long val);
+static inline long atomic_read(atomic_t *number);
+static inline void atomic_set(atomic_t *number, long val);
 static inline void atomic_inc(atomic_t *number);
 static inline void atomic_dec(atomic_t *number);
-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);
+static inline long atomic_swap(atomic_t *addr, long val);
+static inline void *atomic_swap_ptr(void **addr, void *val);
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val);
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val);
 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
 
 /* Inlined functions declared above */
-static inline void atomic_init(atomic_t *number, int32_t val)
+static inline void atomic_init(atomic_t *number, long val)
 {
        asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
 }
 
-static inline int32_t atomic_read(atomic_t *number)
+static inline long atomic_read(atomic_t *number)
 {
        int32_t val;
        asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
        return val;
 }
 
-static inline void atomic_set(atomic_t *number, int32_t val)
+static inline void atomic_set(atomic_t *number, long val)
 {
        asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
 }
@@ -47,7 +50,7 @@ static inline void atomic_dec(atomic_t *number)
        asm volatile("lock decl %0" : "=m"(*number) : : "cc");
 }
 
-static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val)
+static inline long atomic_swap(atomic_t *addr, long val)
 {
        // this would work, but its code is bigger, and it's not like the others
        //asm volatile("xchgl %0,(%2)" : "=r"(val) : "0"(val), "r"(addr) : "memory");
@@ -55,9 +58,21 @@ static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val)
        return val;
 }
 
-/* reusing exp_val for the bool return */
-static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
-                                    uint32_t new_val)
+static inline void *atomic_swap_ptr(void **addr, void *val)
+{
+       asm volatile("xchgl %0,%1" : "=r"(val), "=m"(*addr) : "0"(val), "m"(*addr));
+       return val;
+}
+
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
+{
+       asm volatile("xchgl %0,%1" : "=r"(val), "=m"(*addr) : "0"(val), "m"(*addr));
+       return val;
+}
+
+/* reusing exp_val for the bool return.  1 (TRUE) for success (like test).  Need
+ * to zero eax, since it will get set if the cmpxchgl failed. */
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
 {
        asm volatile("lock cmpxchgl %4,%1; movl $0,%%eax; sete %%al"
                     : "=a"(exp_val), "=m"(*addr)
@@ -66,6 +81,17 @@ static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
        return exp_val;
 }
 
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
 static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
 {
        asm volatile("lock andb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
@@ -76,4 +102,4 @@ static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
        asm volatile("lock orb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
 }
 
-#endif /* !PARLIB_ATOMIC_H */
+#endif /* !PARLIB_ARCH_ATOMIC_H */
index c0aceca..e0c734b 100644 (file)
@@ -1,11 +1,12 @@
-#ifndef PARLIB_ATOMIC_H
-#define PARLIB_ATOMIC_H
+#ifndef PARLIB_ARCH_ATOMIC_H
+#define PARLIB_ARCH_ATOMIC_H
 
 /* Unlike in x86, we need to include spinlocks in the user atomic ops file.
  * Since compare and swap isn't truely non-blocking, and we can't disable
  * interrupts in userspace, there is a slight chance of deadlock. */
 
 #include <ros/common.h>
+#include <ros/atomic.h>
 #include <ros/arch/membar.h>
 
 typedef struct
@@ -15,20 +16,19 @@ typedef struct
 
 #define SPINLOCK_INITIALIZER {0}
 
-// atomic_t is void*, so we can't accidentally dereference it
-typedef void* atomic_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_inc(atomic_t* number);
-static inline void atomic_dec(atomic_t* number);
+static inline void atomic_init(atomic_t *number, long val);
+static inline long atomic_read(atomic_t *number);
+static inline void atomic_set(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_add_not_zero(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);
+static inline long atomic_swap(atomic_t *addr, long val);
+static inline void *atomic_swap_ptr(void **addr, void *val);
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val);
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val);
 static inline void atomic_or_int(volatile int *number, int mask);
 static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
 static inline uint32_t spin_locked(spinlock_t*SAFE lock);
@@ -37,39 +37,39 @@ static inline void spin_unlock(spinlock_t*SAFE lock);
 
 /* Inlined functions declared above */
 
-static inline void atomic_init(atomic_t* number, int32_t val)
+static inline void atomic_init(atomic_t *number, long val)
 {
        val <<= 8;
        __asm__ __volatile__ ("st %0,[%1]" : : "r"(val), "r"(number) : "memory");
 }
 
-static inline int32_t atomic_read(atomic_t* number)
+static inline long atomic_read(atomic_t *number)
 {
-       int32_t val;
+       long val;
        __asm__ __volatile__ ("ld [%1],%0" : "=r"(val) : "r"(number));
        return val >> 8;
 }
 
 /* Sparc needs atomic add, but the regular ROS atomic add conflicts with
  * glibc's internal one. */
-static inline void ros_atomic_add(atomic_t* number, int32_t inc)
+static inline void ros_atomic_add(atomic_t *number, long inc)
 {
        atomic_fetch_and_add(number, inc);
 }
 
-static inline void atomic_set(atomic_t* number, int32_t val)
+static inline void atomic_set(atomic_t *number, long val)
 {
        // this works basically the same as atomic_add... but without the add
        spin_lock((spinlock_t*)number);
        atomic_init(number,val);
 }
 
-static inline void atomic_inc(atomic_tnumber)
+static inline void atomic_inc(atomic_t *number)
 {
        ros_atomic_add(number,1);
 }
 
-static inline void atomic_dec(atomic_tnumber)
+static inline void atomic_dec(atomic_t *number)
 {
        ros_atomic_add(number,-1);
 }
@@ -89,59 +89,34 @@ static inline long atomic_fetch_and_add(atomic_t *number, long val)
        return retval;
 }
 
-/* Adds val to number, so long as number was not zero.  Returns TRUE if the
- * operation succeeded (added, not zero), returns FALSE if number is zero. */
-static inline bool atomic_add_not_zero(atomic_t *number, long val)
+static inline long atomic_swap(atomic_t *addr, long val)
 {
-       long num;
-       bool retval = FALSE;
-       /* 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);
-       num = atomic_read(number);
-       if (num) {
-               num += val;
-               retval = TRUE;
-       }
-       /* set the new (maybe old) counter value.  the lock is cleared (for free) */
-       atomic_init(number, num);
-       return retval;
+       __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");
+       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)
+static inline void *atomic_swap_ptr(void **addr, void *val)
 {
-       long num;
-       bool retval = FALSE;
-       /* 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);
-       num = atomic_read(number);
-       num -= val;
-       retval = num ? FALSE : TRUE;
-       /* set the new counter value.  the lock is cleared (for free) */
-       atomic_init(number, num);
-       return retval;
+       __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");
+       return val;
 }
 
-static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val)
+static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
 {
        __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");
        return val;
 }
 
-// TODO: make this better! (no global locks, etc)
-static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
-                                    uint32_t new_val)
+static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
 {
        bool retval = 0;
-       uint32_t temp;
+       long temp;
        static spinlock_t cas_lock = SPINLOCK_INITIALIZER;
 
-       if (*addr != exp_val)
+       if ((long)*addr != exp_val)
                return 0;
        spin_lock(&cas_lock);
-       if (*addr == exp_val) {
+       if ((long)*addr == exp_val) {
                atomic_swap(addr, new_val);
                retval = 1;
        }
@@ -149,6 +124,17 @@ static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
        return retval;
 }
 
+static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
+static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val)
+{
+       return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
+}
+
 static inline void atomic_or_int(volatile int *number, int mask)
 {
        int val;
@@ -193,4 +179,4 @@ static inline void spinlock_init(spinlock_t* lock)
        lock->rlock = 0;
 }
 
-#endif /* !PARLIB_ATOMIC_H */
+#endif /* !PARLIB_ARCH_ATOMIC_H */
index 17bba43..dcfbd80 100644 (file)
@@ -13,7 +13,7 @@ void mcs_lock_init(struct mcs_lock *lock)
 static inline mcs_lock_qnode_t *mcs_qnode_swap(mcs_lock_qnode_t **addr,
                                                mcs_lock_qnode_t *val)
 {
-       return (mcs_lock_qnode_t*)atomic_swap((int*)addr,(int)val);
+       return (mcs_lock_qnode_t*)atomic_swap_ptr((void**)addr, val);
 }
 
 void mcs_lock_lock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode)
index 378a28c..718084f 100644 (file)
@@ -341,7 +341,7 @@ bool register_evq(struct syscall *sysc, struct event_queue *ev_q)
                        sysc->ev_q = 0;         /* not necessary, but might help with bugs */
                        return FALSE;
                }
-       } while (!atomic_comp_swap(&sysc->flags, old_flags, old_flags | SC_UEVENT));
+       } while (!atomic_cas(&sysc->flags, old_flags, old_flags | SC_UEVENT));
        return TRUE;
 }
 
@@ -369,7 +369,7 @@ void deregister_evq(struct syscall *sysc)
                        old_flags = atomic_read(&sysc->flags);
                /* Note we don't care if the SC_DONE flag is getting set.  We just need
                 * to avoid clobbering flags */
-       } while (!atomic_comp_swap(&sysc->flags, old_flags, old_flags & ~SC_UEVENT));
+       } while (!atomic_cas(&sysc->flags, old_flags, old_flags & ~SC_UEVENT));
 }
 
 /* TLS helpers */
index bf7d7d2..172aaa7 100644 (file)
@@ -490,7 +490,7 @@ int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
 int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr)
 {
   m->attr = attr;
-  m->lock = 0;
+  atomic_init(&m->lock, 0);
   return 0;
 }
 
@@ -517,7 +517,7 @@ int pthread_mutex_lock(pthread_mutex_t* m)
 
 int pthread_mutex_trylock(pthread_mutex_t* m)
 {
-  return atomic_swap(&m->lock,1) == 0 ? 0 : EBUSY;
+  return atomic_swap(&m->lock, 1) == 0 ? 0 : EBUSY;
 }
 
 int pthread_mutex_unlock(pthread_mutex_t* m)
@@ -525,7 +525,7 @@ int pthread_mutex_unlock(pthread_mutex_t* m)
   /* Need to prevent the compiler (and some arches) from reordering older
    * stores */
   wmb();
-  m->lock = 0;
+  atomic_set(&m->lock, 0);
   return 0;
 }
 
@@ -570,11 +570,11 @@ int pthread_cond_signal(pthread_cond_t *c)
 
 int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
 {
-  int old_waiter = c->next_waiter;
-  int my_waiter = c->next_waiter;
+  uint32_t old_waiter = c->next_waiter;
+  uint32_t my_waiter = c->next_waiter;
   
   //allocate a slot
-  while (atomic_swap (& (c->in_use[my_waiter]), SLOT_IN_USE) == SLOT_IN_USE)
+  while (atomic_swap_u32(& (c->in_use[my_waiter]), SLOT_IN_USE) == SLOT_IN_USE)
   {
     my_waiter = (my_waiter + 1) % MAX_PTHREADS;
     assert (old_waiter != my_waiter);  // do not want to wrap around
@@ -636,7 +636,7 @@ void pthread_exit(void *ret)
 
 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
 {
-  if(atomic_swap(once_control,1) == 0)
+  if (atomic_swap_u32(once_control, 1) == 0)
     init_routine();
   return 0;
 }
index d591855..490918e 100644 (file)
@@ -57,7 +57,7 @@ typedef struct
 typedef struct
 {
   const pthread_mutexattr_t* attr;
-  int lock;
+  atomic_t lock;
 } pthread_mutex_t;
 
 /* TODO: MAX_PTHREADS is arbitrarily defined for now.
@@ -101,9 +101,9 @@ typedef struct
 typedef struct
 {
   const pthread_condattr_t* attr;
-  int waiters[MAX_PTHREADS];
-  int in_use[MAX_PTHREADS];
-  int next_waiter; //start the search for an available waiter at this spot
+  uint32_t waiters[MAX_PTHREADS];
+  uint32_t in_use[MAX_PTHREADS];
+  uint32_t next_waiter; //start the search for an available waiter at this spot
 } pthread_cond_t;
 typedef struct 
 {