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