Add RISC-V CAS via load-reserved/store conditional
[akaros.git] / user / parlib / include / mcs.h
index 9016302..624ca4e 100644 (file)
@@ -9,6 +9,7 @@ extern "C" {
 #include <arch/arch.h>
 
 #define MCS_LOCK_INIT {0}
+#define MCS_QNODE_INIT {0, 0}
 
 typedef struct mcs_lock_qnode
 {
@@ -50,6 +51,39 @@ void mcs_lock_unlock(struct mcs_lock *lock, struct mcs_lock_qnode *qnode);
 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)));
+
+/* Want to pad out so lock doesn't share a CL with qnodes.  If we align both
+ * pointers so that they have their own cache line, this actually performs
+ * worse.  Meaning (for some unknown reason), if the lock shares a CL with
+ * other random bss/data, the lock tests perf better... */
+struct mcs_pdr_lock
+{
+       struct mcs_pdr_qnode *lock;
+       char padding[ARCH_CL_SIZE];
+       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
 }
 #endif