Moves 9ns endian helpers
[akaros.git] / kern / arch / x86 / atomic.h
1 /* Copyright (c) 2009-2011 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * x86 atomics and locking functions. */
6
7 #ifndef ROS_KERN_ARCH_ATOMIC_H
8 #define ROS_KERN_ARCH_ATOMIC_H
9
10 #include <ros/common.h>
11 #include <ros/arch/membar.h>
12 #include <arch/x86.h>
13 #include <arch/arch.h>
14
15 static inline void atomic_andb(volatile uint8_t *number, uint8_t mask);
16 static inline void atomic_orb(volatile uint8_t *number, uint8_t mask);
17
18 /* Inlined functions declared above */
19 static inline void atomic_init(atomic_t *number, long val)
20 {
21         asm volatile("mov %1,%0" : "=m"(*number) : "r"(val));
22 }
23
24 static inline long atomic_read(atomic_t *number)
25 {
26         long val;
27         asm volatile("mov %1,%0" : "=r"(val) : "m"(*number));
28         return val;
29 }
30
31 static inline void atomic_set(atomic_t *number, long val)
32 {
33         asm volatile("mov %1,%0" : "=m"(*number) : "r"(val));
34 }
35
36 static inline void atomic_add(atomic_t *number, long val)
37 {
38         __sync_fetch_and_add(number, val);
39 }
40
41 static inline void atomic_inc(atomic_t *number)
42 {
43         __sync_fetch_and_add(number, 1);
44 }
45
46 static inline void atomic_dec(atomic_t *number)
47 {
48         __sync_fetch_and_sub(number, 1);
49 }
50
51 static inline long atomic_fetch_and_add(atomic_t *number, long val)
52 {
53         return (long)__sync_fetch_and_add(number, val);
54 }
55
56 static inline void atomic_and(atomic_t *number, long mask)
57 {
58         __sync_fetch_and_and(number, mask);
59 }
60
61 static inline void atomic_or(atomic_t *number, long mask)
62 {
63         __sync_fetch_and_or(number, mask);
64 }
65
66 static inline long atomic_swap(atomic_t *addr, long val)
67 {
68         /* This poorly named function does an xchg */
69         return (long)__sync_lock_test_and_set(addr, val);
70 }
71
72 static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
73 {
74         return __sync_bool_compare_and_swap(addr, exp_val, new_val);
75 }
76
77 static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
78 {
79         return __sync_bool_compare_and_swap(addr, exp_val, new_val);
80 }
81
82 static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
83                                   uint32_t new_val)
84 {
85         return __sync_bool_compare_and_swap(addr, exp_val, new_val);
86 }
87
88 /* Adds val to number, so long as number was not zero.  Returns TRUE if the
89  * operation succeeded (added, not zero), returns FALSE if number is zero. */
90 static inline bool atomic_add_not_zero(atomic_t *number, long val)
91 {
92         long old_num, new_num;
93         do {
94                 old_num = atomic_read(number);
95                 if (!old_num)
96                         return FALSE;
97                 new_num = old_num + val;
98         } while (!atomic_cas(number, old_num, new_num));
99         return TRUE;
100 }
101
102 /* Subtracts val from number, returning True if the new value is 0. */
103 static inline bool atomic_sub_and_test(atomic_t *number, long val)
104 {
105         bool b;
106         asm volatile("lock sub %2,%1; setz %0" : "=q"(b), "=m"(*number)
107                                                : "r"(val), "m"(*number)
108                                                : "cc" );
109         return b;
110 }
111
112 static inline void atomic_andb(volatile uint8_t *number, uint8_t mask)
113 {
114         __sync_fetch_and_and(number, mask);
115 }
116
117 static inline void atomic_orb(volatile uint8_t *number, uint8_t mask)
118 {
119         __sync_fetch_and_or(number, mask);
120 }
121
122 static inline bool spin_locked(spinlock_t *lock)
123 {
124         // the lock status is the lowest byte of the lock
125         return lock->rlock & 0xff;
126 }
127
128 static inline void __spin_lock_raw(volatile uint32_t *rlock)
129 {
130         asm volatile(
131                         "1:                       "
132                         "       cmpb $0, %0;          "
133                         "       je 2f;                "
134                         "       pause;                "
135                         "       jmp 1b;               "
136                         "2:                       " 
137                         "       movb $1, %%al;        "
138                         "       xchgb %%al, %0;       "
139                         "       cmpb $0, %%al;        "
140                         "       jne 1b;               "
141                 : : "m"(*rlock) : "eax", "cc");
142         cmb();  /* need cmb(), the CPU mb() was handled by the xchg */
143 }
144
145 static inline void __spin_lock(spinlock_t *lock)
146 {
147         __spin_lock_raw(&lock->rlock);
148 }
149
150 static inline bool __spin_trylock(spinlock_t *lock)
151 {
152         /* since this is an or, we're not going to clobber the top bytes (if that
153          * matters) */
154         return !__sync_fetch_and_or(&lock->rlock, 1);
155 }
156
157 static inline void __spin_unlock(spinlock_t *lock)
158 {
159         /* Need to prevent the compiler from reordering older stores. */
160         wmb();
161         rwmb(); /* x86 makes both of these a cmb() */
162         lock->rlock = 0;
163 }
164
165 static inline void __spinlock_init(spinlock_t *lock)
166 {
167         lock->rlock = 0;
168 }
169
170 #endif /* ROS_KERN_ARCH_ATOMIC_H */