Barrier work
[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 DEFAULT_CHECKLIST_MASK(sz) {(sz), ZEROS_ARRAY(sz)}
42 #define DEFAULT_CHECKLIST(sz) {0, DEFAULT_CHECKLIST_MASK(sz)}
43 #define INIT_CHECKLIST(nm, sz)  \
44         checklist_t nm = DEFAULT_CHECKLIST(sz);
45 #define INIT_CHECKLIST_MASK(nm, sz)     \
46         checklist_mask_t nm = DEFAULT_CHECKLIST_MASK(sz);
47
48 int commit_checklist_wait(checklist_t* list, checklist_mask_t* mask);
49 int commit_checklist_nowait(checklist_t* list, checklist_mask_t* mask);
50 int waiton_checklist(checklist_t* list);
51 void down_checklist(checklist_t* list);
52 // TODO - do we want to adjust the size?
53 // TODO - do we want to be able to call waiton without having called commit?
54 //      - in the case of protected checklists
55 // TODO - want a destroy checklist (when we have kmalloc, or whatever)
56 /**************************************************************/
57
58 /* Barrier: currently made for everyone barriering.  Change to use checklist */
59 typedef struct barrier {
60         volatile uint32_t lock;
61         uint32_t init_count;
62         uint32_t current_count;
63     volatile uint8_t ready;
64 } barrier_t;
65
66 void init_barrier(barrier_t* barrier, uint32_t count);
67 void reset_barrier(barrier_t* barrier);
68 void waiton_barrier(barrier_t* barrier);
69
70 /* Inlined functions declared above */
71 static inline void spin_lock(volatile uint32_t* lock)
72 {
73         asm volatile(
74                         "1:                       "
75                         "       cmpb $0, %0;          "
76                         "       je 2f;                "
77                         "       pause;                "
78                         "       jmp 1b;               "
79                         "2:                       " 
80                         "       movb $1, %%al;        "
81                         "       xchgb %%al, %0;       "
82                         "       cmpb $0, %%al;        "
83                         "       jne 1b;               "
84                 : : "m"(*lock) : "eax", "cc");
85 }
86
87 static inline void spin_unlock(volatile uint32_t* lock)
88 {
89         *lock = 0;
90 }
91
92 // If ints are enabled, disable them and note it in the top bit of the lock
93 // There is an assumption about releasing locks in order here...
94 static inline void spin_lock_irqsave(volatile uint32_t* lock)
95 {
96         uint32_t eflags;
97         eflags = read_eflags();
98         disable_irq();
99         spin_lock(lock);
100         if (eflags & FL_IF)
101                 *lock |= 0x80000000;
102 }
103
104 // if the top bit of the lock is set, then re-enable interrupts
105 static inline void spin_unlock_irqsave(volatile uint32_t* lock)
106 {
107         if (*lock & 0x80000000) {
108                 *lock = 0;
109                 enable_irq();
110         } else
111                 *lock = 0;
112 }
113
114 // need to do this with pointers and deref.  %0 needs to be the memory address
115 static inline void atomic_inc(volatile uint32_t* number)
116 {
117         asm volatile("lock incl %0" : "=m"(*number) : : "cc");
118 }
119
120 static inline void atomic_dec(volatile uint32_t* number)
121 {
122         asm volatile("lock decl %0" : "=m"(*number) : : "cc");
123 }
124
125 static inline void atomic_andb(volatile uint8_t* number, uint8_t mask)
126 {
127         asm volatile("lock andb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
128 }
129 #endif /* !ROS_INC_ATOMIC_H */