an implementation of the Mellor-Crummey Scott (MCS) lock
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#define __HEADER_X86_COMMON_ARCH_LOCK
|
#define __HEADER_X86_COMMON_ARCH_LOCK
|
||||||
|
|
||||||
#include <ihk/cpu.h>
|
#include <ihk/cpu.h>
|
||||||
|
#include <ihk/atomic.h>
|
||||||
|
|
||||||
//#define DEBUG_SPINLOCK
|
//#define DEBUG_SPINLOCK
|
||||||
|
|
||||||
@@ -99,5 +100,59 @@ static void ihk_mc_spinlock_unlock(ihk_spinlock_t *lock, unsigned long flags)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* An implementation of the Mellor-Crummey Scott (MCS) lock */
|
||||||
|
typedef struct mcs_lock_node {
|
||||||
|
unsigned long locked;
|
||||||
|
struct mcs_lock_node *next;
|
||||||
|
} __attribute__((aligned(64))) mcs_lock_node_t;
|
||||||
|
|
||||||
|
static void mcs_lock_init(struct mcs_lock_node *node)
|
||||||
|
{
|
||||||
|
node->locked = 0;
|
||||||
|
node->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcs_lock_lock(struct mcs_lock_node *lock,
|
||||||
|
struct mcs_lock_node *node)
|
||||||
|
{
|
||||||
|
struct mcs_lock_node *pred;
|
||||||
|
|
||||||
|
node->next = NULL;
|
||||||
|
node->locked = 0;
|
||||||
|
pred = (struct mcs_lock_node *)xchg8((unsigned long *)&lock->next,
|
||||||
|
(unsigned long)node);
|
||||||
|
|
||||||
|
if (pred) {
|
||||||
|
node->locked = 1;
|
||||||
|
pred->next = node;
|
||||||
|
while (node->locked != 0) {
|
||||||
|
cpu_pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcs_lock_unlock(struct mcs_lock_node *lock,
|
||||||
|
struct mcs_lock_node *node)
|
||||||
|
{
|
||||||
|
if (node->next == NULL) {
|
||||||
|
struct mcs_lock_node *old = (struct mcs_lock_node *)
|
||||||
|
atomic_cmpxchg8((unsigned long *)&lock->next,
|
||||||
|
(unsigned long)node, (unsigned long)0);
|
||||||
|
|
||||||
|
if (old == node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (node->next == NULL) {
|
||||||
|
cpu_pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node->next->locked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,17 @@ static inline int ihk_atomic_sub_return(int i, ihk_atomic_t *v)
|
|||||||
__x; \
|
__x; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
static inline unsigned long xchg8(unsigned long *ptr, unsigned long x)
|
||||||
|
{
|
||||||
|
unsigned long __x = (x);
|
||||||
|
asm volatile("xchgq %0,%1"
|
||||||
|
: "=r" (__x)
|
||||||
|
: "m" (*(volatile unsigned long*)(ptr)), "0" (__x)
|
||||||
|
: "memory");
|
||||||
|
|
||||||
|
return __x;
|
||||||
|
}
|
||||||
|
|
||||||
#define __xchg(x, ptr, size) \
|
#define __xchg(x, ptr, size) \
|
||||||
({ \
|
({ \
|
||||||
__typeof(*(ptr)) __x = (x); \
|
__typeof(*(ptr)) __x = (x); \
|
||||||
@@ -150,5 +161,17 @@ static inline int ihk_atomic_sub_return(int i, ihk_atomic_t *v)
|
|||||||
#define xchg(ptr, v) \
|
#define xchg(ptr, v) \
|
||||||
__xchg((v), (ptr), sizeof(*ptr))
|
__xchg((v), (ptr), sizeof(*ptr))
|
||||||
|
|
||||||
|
static inline unsigned long atomic_cmpxchg8(unsigned long *addr,
|
||||||
|
unsigned long oldval,
|
||||||
|
unsigned long newval)
|
||||||
|
{
|
||||||
|
asm volatile("lock; cmpxchgq %3, %1\n"
|
||||||
|
: "=a" (oldval), "+m" (*addr)
|
||||||
|
: "r" (newval), "0" (oldval)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
return oldval;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user