Tracks state properly for paused uthreads
[akaros.git] / user / parlib / include / mcs.h
index 0f9c378..57d332d 100644 (file)
@@ -14,14 +14,11 @@ typedef struct mcs_lock_qnode
 {
        volatile struct mcs_lock_qnode* volatile next;
        volatile int locked;
-       char pad[ARCH_CL_SIZE-sizeof(void*)-sizeof(int)];
 } mcs_lock_qnode_t;
 
-typedef struct
+typedef struct mcs_lock
 {
        mcs_lock_qnode_t* lock;
-       char pad[ARCH_CL_SIZE-sizeof(mcs_lock_qnode_t*)];
-       mcs_lock_qnode_t qnode[MAX_VCORES] __attribute__((aligned(8)));
 } mcs_lock_t;
 
 typedef struct
@@ -43,9 +40,44 @@ typedef struct
 int mcs_barrier_init(mcs_barrier_t* b, size_t nprocs);
 void mcs_barrier_wait(mcs_barrier_t* b, size_t vcoreid);
 
-void mcs_lock_init(mcs_lock_t* lock);
-void mcs_lock_unlock(mcs_lock_t* lock);
-void mcs_lock_lock(mcs_lock_t* l);
+void mcs_lock_init(struct mcs_lock *lock);
+/* Caller needs to alloc (and zero) their own qnode to spin on.  The memory
+ * should be on a cacheline that is 'per-thread'.  This could be on the stack,
+ * in a thread control block, etc. */
+void mcs_lock_lock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+void mcs_lock_unlock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+/* If you lock the lock from vcore context, you must use these. */
+void mcs_lock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+void mcs_unlock_notifsafe(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
+
+/* Preemption detection and recovering MCS locks.
+ *
+ * The basic idea is that when spinning, vcores make sure someone else is
+ * making progress that will lead to them not spinning.  Usually, it'll be to
+ * make sure the lock holder (if known) is running.  If we don't know the lock
+ * holder, we nsure the end of whatever chain we can see is running, which will
+ * make sure its predecessor runs, which will eventually unjam the system.
+ *
+ * These are memory safe ones.  In the future, we can make ones that you pass
+ * the qnode to, so long as you never free the qnode storage (stacks).  */
+struct mcs_pdr_qnode
+{
+       struct mcs_pdr_qnode *next;
+       int locked;
+       uint32_t vcoreid;
+}__attribute__((aligned(ARCH_CL_SIZE)));
+
+struct mcs_pdr_lock
+{
+       struct mcs_pdr_qnode *lock;
+       struct mcs_pdr_qnode *lock_holder;
+       struct mcs_pdr_qnode *vc_qnodes;        /* malloc this at init time */
+};
+
+void mcs_pdr_init(struct mcs_pdr_lock *lock);
+void mcs_pdr_fini(struct mcs_pdr_lock *lock);
+void mcs_pdr_lock(struct mcs_pdr_lock *lock);
+void mcs_pdr_unlock(struct mcs_pdr_lock *lock);
 
 #ifdef __cplusplus
 }