#include "xsched/utils/lock.h"
#include "xsched/utils/common.h"

#if defined(__linux__)
    #if defined(ARCH_X86_64)
        #define memory_barrier() asm volatile("pause" ::: "memory")
    #elif defined(ARCH_AARCH64)
        #define memory_barrier() asm volatile("yield" ::: "memory")
    #endif
#elif defined(_WIN32)
    #include <intrin.h>
    #define memory_barrier() _mm_pause()
#endif

using namespace xsched::utils;

thread_local MCSLock::MCSNode MCSLock::me;

void MCSLock::lock()
{
    MCSNode *tail = nullptr;
    me.flag = kLockWaiting;
    me.next = nullptr;
    tail = tail_.exchange(&me);
    if (tail) {
        tail->next = &me;
        while (me.flag != kLockGranted) {
            memory_barrier();
        }
    }
}

void MCSLock::unlock()
{
    if (!me.next) {
        MCSNode *me_ptr = &me;
        if (tail_.compare_exchange_strong(me_ptr, nullptr)) {
            return;
        }
        while (!me.next) {
            memory_barrier();
        }
    }
    me.next->flag = kLockGranted;
}