Split atomic library
[akaros.git] / include / atomic.h
1 #ifndef ROS_KERN_ATOMIC_H
2 #define ROS_KERN_ATOMIC_H
3
4 #include <arch/types.h>
5 #include <arch/mmu.h>
6 #include <arch/x86.h>
7 #include <arch/atomic.h>
8
9 /* //linux style atomic ops
10 typedef struct {uint32_t real_num;} atomic_t;
11 #define atomic_read(atom) ((atom)->real_num)
12 #define atomic_set(atom, val) (((atom)->real_num) = (val))
13 #define atomic_init(i) {(i)}
14 //and the atomic incs, etc take an atomic_t ptr, deref inside
15 */
16
17 static inline void spin_lock(volatile uint32_t* lock);
18 static inline void spin_unlock(volatile uint32_t* lock);
19 static inline void spin_lock_irqsave(volatile uint32_t* lock);
20 static inline void spin_unlock_irqsave(volatile uint32_t* lock);
21
22 /*********************** Checklist stuff **********************/
23 typedef struct checklist_mask {
24         // only need an uint8_t, but we need the bits[] to be word aligned
25         uint32_t size;
26         volatile uint8_t (COUNT(BYTES_FOR_BITMASK(size)) bits)[];
27 } checklist_mask_t;
28
29 // mask contains an unspecified array, so it needs to be at the bottom
30 typedef struct checklist {
31         volatile uint32_t lock;
32         checklist_mask_t mask;
33 } checklist_t;
34
35 #define ZEROS_ARRAY(size) {[0 ... ((size)-1)] 0}
36
37 #define DEFAULT_CHECKLIST_MASK(sz) {(sz), ZEROS_ARRAY(BYTES_FOR_BITMASK(sz))}
38 #define DEFAULT_CHECKLIST(sz) {0, DEFAULT_CHECKLIST_MASK(sz)}
39 #define INIT_CHECKLIST(nm, sz)  \
40         checklist_t nm = DEFAULT_CHECKLIST(sz);
41 #define INIT_CHECKLIST_MASK(nm, sz)     \
42         checklist_mask_t nm = DEFAULT_CHECKLIST_MASK(sz);
43
44 int commit_checklist_wait(checklist_t* list, checklist_mask_t* mask);
45 int commit_checklist_nowait(checklist_t* list, checklist_mask_t* mask);
46 int waiton_checklist(checklist_t* list);
47 int release_checklist(checklist_t* list);
48 int checklist_is_locked(checklist_t* list);
49 int checklist_is_clear(checklist_t* list);
50 void reset_checklist(checklist_t* list);
51 void down_checklist(checklist_t* list);
52 // TODO - do we want to adjust the size?  (YES, don't want to check it all)
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 // TODO - some sort of dynamic allocation of them in the future
57 // TODO - think about deadlock issues with one core spinning on a lock for
58 // something that it is the hold out for...
59 //      - probably should have interrupts enabled, and never grab these locks
60 //      from interrupt context (and not use irq_save)
61 /**************************************************************/
62
63 /* Barrier: currently made for everyone barriering.  Change to use checklist */
64 typedef struct barrier {
65         volatile uint32_t lock;
66         uint32_t init_count;
67         uint32_t current_count;
68     volatile uint8_t ready;
69 } barrier_t;
70
71 void init_barrier(barrier_t* barrier, uint32_t count);
72 void reset_barrier(barrier_t* barrier);
73 void waiton_barrier(barrier_t* barrier);
74
75 /* Inlined functions declared above */
76 static inline void spin_lock(volatile uint32_t* lock)
77 {
78         asm volatile(
79                         "1:                       "
80                         "       cmpb $0, %0;          "
81                         "       je 2f;                "
82                         "       pause;                "
83                         "       jmp 1b;               "
84                         "2:                       " 
85                         "       movb $1, %%al;        "
86                         "       xchgb %%al, %0;       "
87                         "       cmpb $0, %%al;        "
88                         "       jne 1b;               "
89                 : : "m"(*lock) : "eax", "cc");
90 }
91
92 static inline void spin_unlock(volatile uint32_t* lock)
93 {
94         *lock = 0;
95 }
96
97 // If ints are enabled, disable them and note it in the top bit of the lock
98 // There is an assumption about releasing locks in order here...
99 static inline void spin_lock_irqsave(volatile uint32_t* lock)
100 {
101         uint32_t eflags;
102         eflags = read_eflags();
103         disable_irq();
104         spin_lock(lock);
105         if (eflags & FL_IF)
106                 *lock |= 0x80000000;
107 }
108
109 // if the top bit of the lock is set, then re-enable interrupts
110 static inline void spin_unlock_irqsave(volatile uint32_t* lock)
111 {
112         if (*lock & 0x80000000) {
113                 *lock = 0;
114                 enable_irq();
115         } else
116                 *lock = 0;
117 }
118
119 #endif /* !ROS_KERN_ATOMIC_H */