#include "tile/base/memory_barrier.h"

#include <mutex>
#include <sys/mman.h>

#include "tile/base/logging.h"
#include "tile/base/never_destroyed.h"

namespace tile {
namespace internal {
namespace {
void *
CreateOneByteDummyPage()
{
    auto ptr = mmap(nullptr, 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    TILE_PCHECK(ptr, "Cannot create dummy page for asymmetric memory barrier.");
    (void) mlock(ptr, 1);
    return ptr;
}

void
HomemadeMembarrier()
{
    static void *dummy_page = CreateOneByteDummyPage();
    MemoryBarrier();
    static NeverDestroyed<std::mutex> lock;
    std::lock_guard<std::mutex> _(*lock);

    TILE_PCHECK(mprotect(dummy_page, 1, PROT_READ | PROT_WRITE) == 0, "Cannot protect dummy page.");
    *static_cast<char volatile *>(dummy_page) = 0;
    TILE_PCHECK(mprotect(dummy_page, 1, PROT_READ) == 0);

    MemoryBarrier();
}

}// namespace

void
AsymmetricBarrierHeavy()
{
    HomemadeMembarrier();
}
}// namespace internal

}// namespace tile
