Done Deputizing kernel
[akaros.git] / kern / 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/atomic.h>
7 #include <arch/arch.h>
8
9 static inline void spin_lock_irqsave(volatile uint32_t*SAFE lock);
10 static inline void spin_unlock_irqsave(volatile uint32_t*SAFE lock);
11
12 /*********************** Checklist stuff **********************/
13 typedef struct checklist_mask {
14         // only need an uint8_t, but we need the bits[] to be word aligned
15         uint32_t size;
16         volatile uint8_t (COUNT(BYTES_FOR_BITMASK(size)) bits)[];
17 } checklist_mask_t;
18
19 // mask contains an unspecified array, so it needs to be at the bottom
20 typedef struct checklist {
21         volatile uint32_t lock;
22         checklist_mask_t mask;
23 } checklist_t;
24
25 #define ZEROS_ARRAY(size) {[0 ... ((size)-1)] 0}
26
27 #define DEFAULT_CHECKLIST_MASK(sz) {(sz), ZEROS_ARRAY(BYTES_FOR_BITMASK(sz))}
28 #define DEFAULT_CHECKLIST(sz) {0, DEFAULT_CHECKLIST_MASK(sz)}
29 #define INIT_CHECKLIST(nm, sz)  \
30         checklist_t nm = DEFAULT_CHECKLIST(sz);
31 #define INIT_CHECKLIST_MASK(nm, sz)     \
32         checklist_mask_t nm = DEFAULT_CHECKLIST_MASK(sz);
33
34 int commit_checklist_wait(checklist_t* list, checklist_mask_t* mask);
35 int commit_checklist_nowait(checklist_t* list, checklist_mask_t* mask);
36 int waiton_checklist(checklist_t* list);
37 int release_checklist(checklist_t* list);
38 int checklist_is_locked(checklist_t* list);
39 int checklist_is_clear(checklist_t* list);
40 void reset_checklist(checklist_t* list);
41 void down_checklist(checklist_t* list);
42 // TODO - do we want to adjust the size?  (YES, don't want to check it all)
43 // TODO - do we want to be able to call waiton without having called commit?
44 //      - in the case of protected checklists
45 // TODO - want a destroy checklist (when we have kmalloc, or whatever)
46 // TODO - some sort of dynamic allocation of them in the future
47 // TODO - think about deadlock issues with one core spinning on a lock for
48 // something that it is the hold out for...
49 //      - probably should have interrupts enabled, and never grab these locks
50 //      from interrupt context (and not use irq_save)
51 /**************************************************************/
52
53 /* Barrier: currently made for everyone barriering.  Change to use checklist */
54 typedef struct barrier {
55         volatile uint32_t lock;
56         uint32_t init_count;
57         uint32_t current_count;
58     volatile uint8_t ready;
59 } barrier_t;
60
61 void init_barrier(barrier_t*COUNT(1) barrier, uint32_t count);
62 void reset_barrier(barrier_t* barrier);
63 void waiton_barrier(barrier_t* barrier);
64
65 // If ints are enabled, disable them and note it in the top bit of the lock
66 // There is an assumption about releasing locks in order here...
67 static inline void spin_lock_irqsave(volatile uint32_t*SAFE lock)
68 {
69         uint32_t irq_en;
70         irq_en = irq_is_enabled();
71         disable_irq();
72         spin_lock(lock);
73         if (irq_en)
74                 *lock |= 0x80000000;
75 }
76
77 // if the high bit of the lock is set, then re-enable interrupts
78 // (note from asw: you're lucky this works, you little-endian jerks)
79 static inline void spin_unlock_irqsave(volatile uint32_t*SAFE lock)
80 {
81         if (*lock & 0x80000000) {
82                 *lock = 0;
83                 enable_irq();
84         } else
85                 *lock = 0;
86 }
87
88 #endif /* !ROS_KERN_ATOMIC_H */