commit e1a0a69fb646f748b55c07cec9b2839c52b242ec
parent 3a86ba96296bead08c90a338524dd3bf504e8942
Author: oblique <psyberbits@gmail.com>
Date: Sun, 28 Oct 2012 02:00:13 +0300
add some atomic operations
Diffstat:
A | include/atomic.h | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 64 insertions(+), 0 deletions(-)
diff --git a/include/atomic.h b/include/atomic.h
@@ -0,0 +1,64 @@
+#ifndef __ATOMIC_H
+#define __ATOMIC_H
+
+#include <inttypes.h>
+
+typedef struct {
+ u32 counter;
+} uatomic_t;
+
+#define UATOMIC_INIT(i) { (i) }
+#define uatomic_read(v) (__uatomic_read(v).counter)
+
+static inline uatomic_t
+__uatomic_read(uatomic_t *v)
+{
+ uatomic_t r;
+ asm volatile (
+ "1: \n\t"
+ "ldrex %0, [%1] \n\t"
+ "strex v1, %0, [%1] \n\t"
+ "teq v1, #0 \n\t"
+ "bne 1b \n\t"
+ /* '&' guarantees that 'r' variable will have its own
+ * register so GCC will not produce assembly code
+ * like this one: ldrex r5, [r5] */
+ : "=&r" (r)
+ : "r" (v)
+ : "v1", "memory"
+ );
+ return r;
+}
+
+static inline void
+uatomic_set(uatomic_t *v, u32 i)
+{
+ asm volatile (
+ "1: \n\t"
+ "ldrex v1, [%1] \n\t"
+ "strex v1, %0, [%1] \n\t"
+ "teq v1, #0 \n\t"
+ "bne 1b \n\t"
+ :
+ : "r" (i), "r" (v)
+ : "v1", "memory"
+ );
+}
+
+static inline void
+uatomic_add(u32 i, uatomic_t *v)
+{
+ asm volatile (
+ "1: \n\t"
+ "ldrex v1, [%1] \n\t"
+ "add v1, v1, %0 \n\t"
+ "strex v2, v1, [%1] \n\t"
+ "teq v2, #0 \n\t"
+ "bne 1b \n\t"
+ :
+ : "r" (i), "r" (v)
+ : "v1", "v2", "memory"
+ );
+}
+
+#endif /* __ATOMIC_H */