Atomics rewrite (XCC)
[akaros.git] / user / parlib / include / i686 / atomic.h
1 #ifndef PARLIB_ARCH_ATOMIC_H
2 #define PARLIB_ARCH_ATOMIC_H
3
4 #include <ros/common.h>
5 #include <ros/atomic.h>
6
7 static inline void atomic_init(atomic_t *number, long val);
8 static inline long atomic_read(atomic_t *number);
9 static inline void atomic_set(atomic_t *number, long val);
10 static inline void atomic_inc(atomic_t *number);
11 static inline void atomic_dec(atomic_t *number);
12 static inline long atomic_swap(atomic_t *addr, long val);
13 static inline void *atomic_swap_ptr(void **addr, void *val);
14 static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val);
15 static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
16 static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
17 static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
18                                   uint32_t new_val);
19 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
20 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
21
22 /* Inlined functions declared above */
23 static inline void atomic_init(atomic_t *number, long val)
24 {
25         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
26 }
27
28 static inline long atomic_read(atomic_t *number)
29 {
30         int32_t val;
31         asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
32         return val;
33 }
34
35 static inline void atomic_set(atomic_t *number, long val)
36 {
37         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
38 }
39
40 // need to do this with pointers and deref.  %0 needs to be the memory address
41 static inline void atomic_inc(atomic_t *number)
42 {
43         asm volatile("lock incl %0" : "=m"(*number) : : "cc");
44 }
45
46 static inline void atomic_dec(atomic_t *number)
47 {
48         // for instance, this doesn't work:
49         //asm volatile("lock decl (%0)" : "=r"(number) : : "cc");
50         asm volatile("lock decl %0" : "=m"(*number) : : "cc");
51 }
52
53 static inline long atomic_swap(atomic_t *addr, long val)
54 {
55         // this would work, but its code is bigger, and it's not like the others
56         //asm volatile("xchgl %0,(%2)" : "=r"(val) : "0"(val), "r"(addr) : "memory");
57         asm volatile("xchgl %0,%1" : "=r"(val), "=m"(*addr) : "0"(val), "m"(*addr));
58         return val;
59 }
60
61 static inline void *atomic_swap_ptr(void **addr, void *val)
62 {
63         asm volatile("xchgl %0,%1" : "=r"(val), "=m"(*addr) : "0"(val), "m"(*addr));
64         return val;
65 }
66
67 static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
68 {
69         asm volatile("xchgl %0,%1" : "=r"(val), "=m"(*addr) : "0"(val), "m"(*addr));
70         return val;
71 }
72
73 /* reusing exp_val for the bool return.  1 (TRUE) for success (like test).  Need
74  * to zero eax, since it will get set if the cmpxchgl failed. */
75 static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
76 {
77         asm volatile("lock cmpxchgl %4,%1; movl $0,%%eax; sete %%al"
78                      : "=a"(exp_val), "=m"(*addr)
79                      : "m"(*addr), "a"(exp_val), "r"(new_val)
80                      : "cc", "memory");
81         return exp_val;
82 }
83
84 static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
85 {
86         return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
87 }
88
89 static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
90                                   uint32_t new_val)
91 {
92         return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
93 }
94
95 static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
96 {
97         asm volatile("lock andb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
98 }
99
100 static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
101 {
102         asm volatile("lock orb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
103 }
104
105 #endif /* !PARLIB_ARCH_ATOMIC_H */