blob: c25f40077ec5aa9acbf4f6b53c8ee84559e5f49e [file] [log] [blame]
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/components/nearby/lock_impl.h"
namespace chromeos {
namespace nearby {
LockImpl::LockImpl() = default;
LockImpl::~LockImpl() {
#if DCHECK_IS_ON()
base::AutoLock al(bookkeeping_lock_);
DCHECK_EQ(0u, num_acquisitions_);
DCHECK_EQ(base::kInvalidThreadId, owning_thread_id_);
#endif
}
void LockImpl::lock() {
{
base::AutoLock al(bookkeeping_lock_);
if (num_acquisitions_ > 0u &&
owning_thread_id_ == base::PlatformThread::CurrentId()) {
real_lock_.AssertAcquired();
++num_acquisitions_;
return;
}
}
// At this point, either no thread currently holds |real_lock_|, in which case
// the current thread should be able to immediately acquire it, or a different
// thread holds it, in which case Acquire() will block. It's necessary that
// Acquire() happens outside the critical sections of |bookkeeping_lock_|,
// otherwise any future calls to unlock() will block on acquiring
// |bookkeeping_lock_|, which would prevent Release() from ever running on
// |real_lock_|, resulting in deadlock.
real_lock_.Acquire();
{
base::AutoLock al(bookkeeping_lock_);
DCHECK_EQ(0u, num_acquisitions_);
owning_thread_id_ = base::PlatformThread::CurrentId();
num_acquisitions_ = 1;
}
}
void LockImpl::unlock() {
base::AutoLock al(bookkeeping_lock_);
CHECK_GT(num_acquisitions_, 0u);
DCHECK_EQ(base::PlatformThread::CurrentId(), owning_thread_id_);
real_lock_.AssertAcquired();
--num_acquisitions_;
if (num_acquisitions_ == 0u) {
owning_thread_id_ = base::kInvalidThreadId;
real_lock_.Release();
}
}
bool LockImpl::IsHeldByCurrentThread() {
base::AutoLock al(bookkeeping_lock_);
return owning_thread_id_ == base::PlatformThread::CurrentId();
}
} // namespace nearby
} // namespace chromeos