#include "pls/internal/helpers/profiler.h"
#include "pls/internal/base/ttas_spin_lock.h"
#include "pls/internal/base/backoff.h"

namespace pls {
namespace internal {
namespace base {

void ttas_spin_lock::lock() {
  PROFILE_LOCK("Acquire Lock")
  int expected = 0;
  backoff backoff_;

  while (true) {
    while (flag_.load(std::memory_order_relaxed) == 1)
      system_details::relax_cpu(); // Spin

    expected = 0;
    if (flag_.compare_exchange_weak(expected, 1, std::memory_order_acquire)) {
      return;
    }
    backoff_.do_backoff();
  }
}

bool ttas_spin_lock::try_lock(unsigned int num_tries) {
  PROFILE_LOCK("Try Acquire Lock")
  int expected = 0;
  backoff backoff_;

  while (true) {
    while (flag_.load() == 1) {
      num_tries--;
      if (num_tries <= 0) {
        return false;
      }
      system_details::relax_cpu();
    }

    expected = 0;
    if (flag_.compare_exchange_weak(expected, 1, std::memory_order_acquire)) {
      return true;
    }
    num_tries--;
    if (num_tries <= 0) {
      return false;
    }
    backoff_.do_backoff();
  }
}

void ttas_spin_lock::unlock() {
  PROFILE_LOCK("Unlock")
  flag_.store(0, std::memory_order_release);
}

}
}
}
