Merge branch 'master' of ssh://scm.millennium.berkeley.edu/project/cs/radlab/src...
[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)(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)[MAX_NUM_CPUS];
19 } checklist_mask_t;
20
21 // mask contains an unspecified array, so it needs to be at the bottom
22 struct checklist {
23         volatile uint32_t lock;
24         checklist_mask_t mask;
25         // eagle-eyed readers may know why this might have been needed. 2009-09-04
26         //volatile uint8_t (COUNT(BYTES_FOR_BITMASK(size)) bits)[];
27 };
28 typedef struct checklist RACY checklist_t;
29
30 #define ZEROS_ARRAY(size) {[0 ... ((size)-1)] 0}
31
32 #define DEFAULT_CHECKLIST_MASK(sz) {(sz), ZEROS_ARRAY(BYTES_FOR_BITMASK(sz))}
33 #define DEFAULT_CHECKLIST(sz) {0, DEFAULT_CHECKLIST_MASK(sz)}
34 #define INIT_CHECKLIST(nm, sz)  \
35         checklist_t nm = DEFAULT_CHECKLIST(sz);
36 #define INIT_CHECKLIST_MASK(nm, sz)     \
37         checklist_mask_t nm = DEFAULT_CHECKLIST_MASK(sz);
38
39 int commit_checklist_wait(checklist_t* list, checklist_mask_t* mask);
40 int commit_checklist_nowait(checklist_t* list, checklist_mask_t* mask);
41 int waiton_checklist(checklist_t* list);
42 int release_checklist(checklist_t* list);
43 int checklist_is_locked(checklist_t* list);
44 int checklist_is_clear(checklist_t* list);
45 void reset_checklist(checklist_t* list);
46 void down_checklist(checklist_t* list);
47 // TODO - do we want to adjust the size?  (YES, don't want to check it all)
48 // TODO - do we want to be able to call waiton without having called commit?
49 //      - in the case of protected checklists
50 // TODO - want a destroy checklist (when we have kmalloc, or whatever)
51 // TODO - some sort of dynamic allocation of them in the future
52 // TODO - think about deadlock issues with one core spinning on a lock for
53 // something that it is the hold out for...
54 //      - probably should have interrupts enabled, and never grab these locks
55 //      from interrupt context (and not use irq_save)
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*COUNT(1) barrier, uint32_t count);
67 void reset_barrier(barrier_t* barrier);
68 void waiton_barrier(barrier_t* barrier);
69
70 // If ints are enabled, disable them and note it in the top bit of the lock
71 // There is an assumption about releasing locks in order here...
72 static inline void spin_lock_irqsave(volatile uint32_t*SAFE lock)
73 {
74         uint32_t irq_en;
75         irq_en = irq_is_enabled();
76         disable_irq();
77         spin_lock(lock);
78         if (irq_en)
79                 *lock |= 0x80000000;
80 }
81
82 // if the high bit of the lock is set, then re-enable interrupts
83 // (note from asw: you're lucky this works, you little-endian jerks)
84 static inline void spin_unlock_irqsave(volatile uint32_t*SAFE lock)
85 {
86         if (*lock & 0x80000000) {
87                 *lock = 0;
88                 enable_irq();
89         } else
90                 *lock = 0;
91 }
92
93 #endif /* !ROS_KERN_ATOMIC_H */