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