namespace starboard {

Mutex::Mutex() : mutex_() {
  SbMutexCreate(&mutex_);
  debugInit();
}

Mutex::~Mutex() {
  SbMutexDestroy(&mutex_);
}

void Mutex::Acquire() const {
  debugPreAcquire();
  SbMutexAcquire(&mutex_);
  debugSetAcquired();
}
bool Mutex::AcquireTry() const {
  bool ok = SbMutexAcquireTry(&mutex_) == kSbMutexAcquired;
  if (ok) {
    debugSetAcquired();
  }
  return ok;
}

void Mutex::Release() const {
  debugSetReleased();
  SbMutexRelease(&mutex_);
}

void Mutex::DCheckAcquired() const {
#ifdef _DEBUG
  SB_DCHECK(current_thread_acquired_ == SbThreadGetCurrent());
#endif  // _DEBUG
}

#ifdef _DEBUG
void Mutex::debugInit() {
  current_thread_acquired_ = kSbThreadInvalid;
}
void Mutex::debugSetReleased() const {
  SbThread current_thread = SbThreadGetCurrent();
  SB_DCHECK(current_thread_acquired_ == current_thread);
  current_thread_acquired_ = kSbThreadInvalid;
}
void Mutex::debugPreAcquire() const {
  // Check that the mutex is not held by the current thread.
  SbThread current_thread = SbThreadGetCurrent();
  SB_DCHECK(current_thread_acquired_ != current_thread);
}
void Mutex::debugSetAcquired() const {
  // Check that the thread has already not been held.
  SB_DCHECK(current_thread_acquired_ == kSbThreadInvalid);
  current_thread_acquired_ = SbThreadGetCurrent();
}
#else
void Mutex::debugInit() {}
void Mutex::debugSetReleased() const {}
void Mutex::debugPreAcquire() const {}
void Mutex::debugSetAcquired() const {}
#endif

SbMutex* Mutex::mutex() const {
  return &mutex_;
}

ScopedLock::ScopedLock(const Mutex& mutex) : mutex_(mutex) {
  mutex_.Acquire();
}

ScopedLock::~ScopedLock() {
  mutex_.Release();
}

ScopedTryLock::ScopedTryLock(const Mutex& mutex) : mutex_(mutex) {
  is_locked_ = mutex_.AcquireTry();
}

ScopedTryLock::~ScopedTryLock() {
  if (is_locked_) {
    mutex_.Release();
  }
}

bool ScopedTryLock::is_locked() const {
  return is_locked_;
}

}  // namespace starboard
