Basic POSIX signal handling (XCC)
[akaros.git] / user / parlib / include / mcs.h
1 #ifndef _MCS_H
2 #define _MCS_H
3
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7
8 #include <vcore.h>
9 #include <arch/arch.h>
10
11 #define MCS_LOCK_INIT {0}
12 #define MCS_QNODE_INIT {0, 0}
13
14 typedef struct mcs_lock_qnode
15 {
16         volatile struct mcs_lock_qnode* volatile next;
17         volatile int locked;
18 } mcs_lock_qnode_t;
19
20 typedef struct mcs_lock
21 {
22         mcs_lock_qnode_t* lock;
23 } mcs_lock_t;
24
25 typedef struct
26 {
27         volatile int myflags[2][LOG2_MAX_VCORES];
28         volatile int* partnerflags[2][LOG2_MAX_VCORES];
29         int parity;
30         int sense;
31         char pad[ARCH_CL_SIZE];
32 } mcs_dissem_flags_t;
33
34 typedef struct
35 {
36         size_t nprocs;
37         mcs_dissem_flags_t* allnodes;
38         size_t logp;
39 } mcs_barrier_t;
40
41 int mcs_barrier_init(mcs_barrier_t* b, size_t nprocs);
42 void mcs_barrier_wait(mcs_barrier_t* b, size_t vcoreid);
43
44 void mcs_lock_init(struct mcs_lock *lock);
45 /* Caller needs to alloc (and zero) their own qnode to spin on.  The memory
46  * should be on a cacheline that is 'per-thread'.  This could be on the stack,
47  * in a thread control block, etc. */
48 void mcs_lock_lock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
49 void mcs_lock_unlock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
50 /* If you lock the lock from vcore context, you must use these. */
51 void mcs_lock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
52 void mcs_unlock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
53
54 /* Preemption detection and recovering MCS locks.
55  *
56  * The basic idea is that when spinning, vcores make sure someone else is
57  * making progress that will lead to them not spinning.  Usually, it'll be to
58  * make sure the lock holder (if known) is running.  If we don't know the lock
59  * holder, we nsure the end of whatever chain we can see is running, which will
60  * make sure its predecessor runs, which will eventually unjam the system.
61  *
62  * These are memory safe ones.  In the future, we can make ones that you pass
63  * the qnode to, so long as you never free the qnode storage (stacks).  */
64 struct mcs_pdr_qnode
65 {
66         struct mcs_pdr_qnode *next;
67         int locked;
68         uint32_t vcoreid;
69 }__attribute__((aligned(ARCH_CL_SIZE)));
70
71 struct mcs_pdr_lock
72 {
73         struct mcs_pdr_qnode *lock;
74         struct mcs_pdr_qnode *lock_holder;
75         struct mcs_pdr_qnode *vc_qnodes;        /* malloc this at init time */
76 };
77
78 void mcs_pdr_init(struct mcs_pdr_lock *lock);
79 void mcs_pdr_fini(struct mcs_pdr_lock *lock);
80 void mcs_pdr_lock(struct mcs_pdr_lock *lock);
81 void mcs_pdr_unlock(struct mcs_pdr_lock *lock);
82
83 #ifdef __cplusplus
84 }
85 #endif
86
87 #endif