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