Rearranged arch-specific directory hierarchy
[akaros.git] / kern / arch / sparc / atomic.h
1 #ifndef ROS_INCLUDE_ATOMIC_H
2 #define ROS_INCLUDE_ATOMIC_H
3
4 #include <arch/types.h>
5
6 #define mb() {rmb(); wmb();}
7 #define rmb()
8 #define wmb() ({ asm volatile("stbar"); })
9
10 typedef volatile uint32_t spinlock_t;
11
12 //linux style atomic ops
13 typedef struct {volatile int32_t real_num;} atomic_t;
14 #define atomic_read(atom) ((atom)->real_num >> 8)
15 #define atomic_init(i) {(i) << 8}
16 //and the atomic incs, etc take an atomic_t ptr, deref inside
17
18 static inline void atomic_set(atomic_t*SAFE number, int32_t val);
19 static inline void atomic_add(atomic_t*SAFE number, int32_t inc);
20 static inline void atomic_inc(atomic_t*SAFE number);
21 static inline void atomic_dec(atomic_t*SAFE number);
22 static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
23 static inline void spin_lock(spinlock_t*SAFE lock);
24 static inline void spin_unlock(spinlock_t*SAFE lock);
25
26 /* Inlined functions declared above */
27
28 static inline void atomic_add(atomic_t*SAFE number, int32_t inc)
29 {
30         // this is pretty clever.  the lower 8 bits (i.e byte 3)
31         // of the atomic_t serve as a spinlock.  let's acquire it.
32         spin_lock((spinlock_t*SAFE)number);
33
34         // compute new counter value.
35         // must shift the old counter right by 8
36         inc += number->real_num >> 8;
37
38         // set the new counter value.
39         // since the lower 8 bits will be cleared by the shift,
40         // we also release the lock (for free!)
41         number->real_num = inc << 8;
42 }
43
44 static inline void atomic_set(atomic_t*SAFE number, uint32_t val)
45 {
46         // this works basically the same as atomic_add
47         spin_lock((spinlock_t*)number);
48         number->real_num = val << 8;
49 }
50
51 static inline void atomic_inc(atomic_t*SAFE number)
52 {
53         atomic_add(number,1);
54 }
55
56 static inline void atomic_dec(atomic_t*SAFE number)
57 {
58         atomic_add(number,-1);
59 }
60
61 static inline uint32_t spin_trylock(spinlock_t*SAFE lock)
62 {
63         // we don't need to initialize reg, but it quiets the compiler
64         uint32_t reg;
65         asm volatile("ldstub [%1+3],%0"
66                      : "=r"(reg)
67                      : "r"(lock)
68                      : "memory");
69         return reg;
70 }
71
72 static inline uint8_t spin_locked(spinlock_t*SAFE lock)
73 {
74         return *((volatile uint8_t*COUNT(sizeof(spinlock_t)))lock+3);
75 }
76
77 static inline void spin_lock(spinlock_t*SAFE lock)
78 {
79         while(spin_trylock(lock))
80                 while(spin_locked(lock));
81 }
82
83 static inline void spin_unlock(spinlock_t*SAFE lock)
84 {
85         wmb();
86         *((volatile uint8_t*COUNT(sizeof(spinlock_t)))lock+3) = 0;
87 }
88
89 #endif /* !ROS_INCLUDE_ATOMIC_H */