32a297e5bb1b94b4083411b23cf9d4df0846115d
[akaros.git] / kern / atomic.h
1 #ifndef ROS_INC_ATOMIC_H
2 #define ROS_INC_ATOMIC_H
3
4 #include <inc/types.h>
5 #include <inc/mmu.h>
6 #include <inc/x86.h>
7
8 /* //linux style atomic ops
9 typedef struct {uint32_t real_num;} atomic_t;
10 #define atomic_read(atom) ((atom)->real_num)
11 #define atomic_set(atom, val) (((atom)->real_num) = (val))
12 #define atomic_init(i) {(i)}
13 //and the atomic incs, etc take an atomic_t ptr, deref inside
14 */
15
16 static inline void spin_lock(volatile uint32_t* lock);
17 static inline void spin_unlock(volatile uint32_t* lock);
18 static inline void spin_lock_irqsave(volatile uint32_t* lock);
19 static inline void spin_unlock_irqsave(volatile uint32_t* lock);
20 static inline void atomic_inc(volatile uint32_t* number);
21 static inline void atomic_dec(volatile uint32_t* number);
22 static inline void atomic_andb(volatile uint8_t* number, uint8_t mask);
23
24 /*********************** Checklist stuff **********************/
25 typedef struct checklist_mask {
26         // only need an uint8_t, but we need the bits[] to be word aligned
27         uint32_t size;
28         volatile uint8_t (COUNT(BYTES_FOR_BITMASK(size)) bits)[];
29 } checklist_mask_t;
30
31 // mask contains an unspecified array, so it need to be at the bottom
32 typedef struct checklist {
33         volatile uint32_t lock;
34         checklist_mask_t mask;
35 } checklist_t;
36
37 #define BUILD_ZEROS_ARRAY_255   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 
38 #define ZEROS_ARRAY(size)       \
39         BUILD_ZEROS_ARRAY_##size
40
41 #define INIT_CHECKLIST(nm, sz)  \
42         checklist_t nm = {0, {(sz), ZEROS_ARRAY(sz)}};
43 #define INIT_CHECKLIST_MASK(nm, sz)     \
44         checklist_mask_t nm = {(sz), ZEROS_ARRAY(sz)};
45
46 int commit_checklist_wait(checklist_t* list, checklist_mask_t* mask);
47 int commit_checklist_nowait(checklist_t* list, checklist_mask_t* mask);
48 int waiton_checklist(checklist_t* list);
49 void down_checklist(checklist_t* list);
50 // TODO - want a destroy checklist (when we have kmalloc, or whatever)
51 /**************************************************************/
52
53 /* Barrier: currently made for everyone barriering.  Change to use checklist */
54 typedef struct barrier {
55         volatile uint8_t COUNT(MAX_NUM_CPUS) cpu_array[MAX_NUM_CPUS]; 
56     volatile uint8_t ready;
57         } barrier_t;
58
59 void init_barrier_all(barrier_t* cpu_barrier);
60 void barrier_all(barrier_t* cpu_barrier);
61
62 /* Inlined functions declared above */
63 static inline void spin_lock(volatile uint32_t* lock)
64 {
65         asm volatile(
66                         "1:                       "
67                         "       cmpb $0, %0;          "
68                         "       je 2f;                "
69                         "       pause;                "
70                         "       jmp 1b;               "
71                         "2:                       " 
72                         "       movb $1, %%al;        "
73                         "       xchgb %%al, %0;       "
74                         "       cmpb $0, %%al;        "
75                         "       jne 1b;               "
76                 : : "m"(*lock) : "eax", "cc");
77 }
78
79 static inline void spin_unlock(volatile uint32_t* lock)
80 {
81         *lock = 0;
82 }
83
84 // If ints are enabled, disable them and note it in the top bit of the lock
85 // There is an assumption about releasing locks in order here...
86 static inline void spin_lock_irqsave(volatile uint32_t* lock)
87 {
88         uint32_t eflags;
89         eflags = read_eflags();
90         disable_irq();
91         spin_lock(lock);
92         if (eflags & FL_IF)
93                 *lock |= 0x80000000;
94 }
95
96 // if the top bit of the lock is set, then re-enable interrupts
97 static inline void spin_unlock_irqsave(volatile uint32_t* lock)
98 {
99         if (*lock & 0x80000000) {
100                 *lock = 0;
101                 enable_irq();
102         } else
103                 *lock = 0;
104 }
105
106 // need to do this with pointers and deref.  %0 needs to be the memory address
107 static inline void atomic_inc(volatile uint32_t* number)
108 {
109         asm volatile("lock incl %0" : "=m"(*number) : : "cc");
110 }
111
112 static inline void atomic_dec(volatile uint32_t* number)
113 {
114         asm volatile("lock decl %0" : "=m"(*number) : : "cc");
115 }
116
117 static inline void atomic_andb(volatile uint8_t* number, uint8_t mask)
118 {
119         asm volatile("lock andb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
120 }
121 #endif /* !ROS_INC_ATOMIC_H */