changeset 818:82d528d417a5

ARM atomic primitives.
author Andrew Haley <aph@redhat.com>
date Wed, 16 Apr 2008 16:46:37 +0100
parents 3f3dd2815005
children 698de8663419
files ports/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp
diffstat 1 files changed, 51 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/ports/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp	Wed Apr 16 10:34:20 2008 -0400
+++ b/ports/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp	Wed Apr 16 16:46:37 2008 +0100
@@ -26,28 +26,69 @@
 // Implementation of class atomic
 
 #ifdef ARM
+
+/*
+ * __kernel_cmpxchg
+ *
+ * Atomically store newval in *ptr if *ptr is equal to oldval for user space.
+ * Return zero if *ptr was changed or non-zero if no exchange happened.
+ * The C flag is also set if *ptr was changed to allow for assembly
+ * optimization in the calling code.
+ *
+ */
+
 typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
 #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) 0xffff0fc0)
 
+
+
+/* Perform an atomic compare and swap: if the current value of `*PTR'
+   is OLDVAL, then write NEWVAL into `*PTR'.  Return the contents of
+   `*PTR' before the operation.*/
 static inline int arm_compare_and_swap(volatile int *ptr,
                                        int oldval,
-                                       int newval) {
-  int old = *ptr;
-  __kernel_cmpxchg(oldval, newval, (volatile int*) ptr);
-  return old;
+                                       int newval) 
+{
+  for (;;)
+    {
+      int prev = *ptr;
+      if (prev != oldval)
+	return prev;
+
+      if (__kernel_cmpxchg (prev, newval, ptr) == 0)
+	// Success.
+	return prev;
+
+      // We failed even though prev == oldval.  Try again.
+    }
 }
 
-static inline int arm_add_and_fetch(volatile int *dest, int add_value)
+/* Atomically add an int to memory.  */
+static inline int arm_add_and_fetch(volatile int *ptr, int add_value)
 {
-  arm_compare_and_swap(dest, *dest, *dest + add_value);
-  return *dest;
+  for (;;)
+    {
+      // Loop until a __kernel_cmpxchg succeeds.
+
+      int prev = *ptr;
+
+      if (__kernel_cmpxchg (prev, prev + add_value, ptr) == 0)
+	return prev + add_value;
+    }
 }
 
+/* Atomically write VALUE into `*PTR' and returns the previous
+   contents of `*PTR'.  */
 static inline int arm_lock_test_and_set(volatile int *ptr, int newval)
 {
-  int old = *ptr;
-  arm_compare_and_swap(ptr, *ptr, newval);
-  return old;
+  for (;;)
+    {
+      // Loop until a __kernel_cmpxchg succeeds.
+      int prev = *ptr;
+
+      if (__kernel_cmpxchg (prev, newval, ptr) == 0)
+	return prev;
+    }
 }
 #endif // ARM