Major reorganization in prep for appserver merge
[akaros.git] / kern / arch / i686 / atomic.h
1 #ifndef ROS_INCLUDE_ATOMIC_H
2 #define ROS_INCLUDE_ATOMIC_H
3
4 /* This enables tracking who last locked a spinlock. */
5 #define SPINLOCK_DEBUG
6
7 #include <ros/common.h>
8 #include <arch/x86.h>
9 #include <arch/arch.h>
10 #include <arch/membar.h>
11
12 typedef void * RACY atomic_t;
13 struct spinlock {
14         volatile uint32_t RACY rlock;
15 #ifdef SPINLOCK_DEBUG
16         void *call_site;        
17         uint32_t calling_core;
18 #endif
19 };
20 typedef struct spinlock RACY spinlock_t;
21 #define SPINLOCK_INITIALIZER {0}
22
23 static inline void atomic_init(atomic_t *number, int32_t val);
24 static inline int32_t atomic_read(atomic_t *number);
25 static inline void atomic_set(atomic_t *number, int32_t val);
26 static inline void atomic_inc(atomic_t *number);
27 static inline void atomic_dec(atomic_t *number);
28 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
29 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
30 static inline uint32_t spin_locked(spinlock_t *SAFE lock);
31 static inline void __spin_lock(volatile uint32_t SRACY*CT(1) rlock);
32 static inline void spin_lock(spinlock_t *lock);
33 static inline void spin_unlock(spinlock_t *lock);
34 static inline void spinlock_init(spinlock_t *lock);
35 void spinlock_debug(spinlock_t *lock);
36
37 /* Inlined functions declared above */
38 static inline void atomic_init(atomic_t *number, int32_t val)
39 {
40         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
41 }
42
43 static inline int32_t atomic_read(atomic_t *number)
44 {
45         int32_t val;
46         asm volatile("movl %1,%0" : "=r"(val) : "m"(*number));
47         return val;
48 }
49
50 static inline void atomic_set(atomic_t *number, int32_t val)
51 {
52         asm volatile("movl %1,%0" : "=m"(*number) : "r"(val));
53 }
54
55 // need to do this with pointers and deref.  %0 needs to be the memory address
56 static inline void atomic_inc(atomic_t *number)
57 {
58         asm volatile("lock incl %0" : "=m"(*number) : : "cc");
59 }
60
61 static inline void atomic_dec(atomic_t *number)
62 {
63         asm volatile("lock decl %0" : "=m"(*number) : : "cc");
64 }
65
66 static inline void atomic_andb(volatile uint8_t RACY*number, uint8_t mask)
67 {
68         asm volatile("lock andb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
69 }
70
71 static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
72 {
73         asm volatile("lock orb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
74 }
75
76 static inline uint32_t spin_locked(spinlock_t *SAFE lock)
77 {
78         // the lock status is the lowest byte of the lock
79         return lock->rlock & 0xff;
80 }
81
82 static inline void __spin_lock(volatile uint32_t *rlock)
83 {
84         asm volatile(
85                         "1:                       "
86                         "       cmpb $0, %0;          "
87                         "       je 2f;                "
88                         "       pause;                "
89                         "       jmp 1b;               "
90                         "2:                       " 
91                         "       movb $1, %%al;        "
92                         "       xchgb %%al, %0;       "
93                         "       cmpb $0, %%al;        "
94                         "       jne 1b;               "
95                 : : "m"(*rlock) : "eax", "cc");
96 }
97
98 static inline void spin_lock(spinlock_t *lock)
99 {
100         __spin_lock(&lock->rlock);
101 #ifdef SPINLOCK_DEBUG
102         lock->call_site = (void RACY*CT(1))TC(read_eip());
103         lock->calling_core = core_id();
104 #endif
105 }
106
107 static inline void spin_unlock(spinlock_t *lock)
108 {
109         lock->rlock = 0;
110 }
111
112 static inline void spinlock_init(spinlock_t *lock)
113 #ifdef SPINLOCK_DEBUG
114 WRITES(lock->rlock,lock->call_site,lock->calling_core)
115 #else
116 WRITES(lock->rlock)
117 #endif
118 {
119         lock->rlock = 0;
120 #ifdef SPINLOCK_DEBUG
121         lock->call_site = 0;
122         lock->calling_core = 0;
123 #endif
124 }
125
126 #endif /* !ROS_INCLUDE_ATOMIC_H */