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