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