[BLEREFACTOR]: Add Mutex::AssertHeld.

PiperOrigin-RevId: 834563947
This commit is contained in:
Edwin Wu
2025-11-19 20:35:47 -08:00
committed by Copybara-Service
parent 0eb6b57423
commit 7bf001a8c9
9 changed files with 96 additions and 3 deletions
@@ -347,6 +347,7 @@ cc_test(
":Platform_cc",
"//internal/platform/implementation/g3:crypto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
@@ -15,6 +15,7 @@
#ifndef PLATFORM_IMPL_APPLE_MUTEX_H_
#define PLATFORM_IMPL_APPLE_MUTEX_H_
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/mutex.h"
@@ -36,6 +37,10 @@ class ABSL_LOCKABLE Mutex : public api::Mutex {
}
void Unlock() ABSL_UNLOCK_FUNCTION() override { mutex_.Unlock(); }
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() override {
mutex_.AssertHeld();
}
private:
friend class ConditionVariable;
absl::Mutex mutex_;
@@ -65,6 +70,12 @@ class ABSL_LOCKABLE RecursiveMutex : public api::Mutex {
}
}
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() override {
#ifndef NDEBUG
assert(thread_id_.load(std::memory_order_acquire) == ThreadId());
#endif
}
private:
static inline intptr_t ThreadId() {
ABSL_CONST_INIT thread_local int per_thread = 0;
@@ -15,9 +15,8 @@
#include "internal/platform/implementation/apple/mutex.h"
#include "gtest/gtest.h"
#include "absl/synchronization/mutex.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/notification.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "thread/fiber/fiber.h"
@@ -85,6 +84,36 @@ TEST(MutexTest, RecursiveLockingForNestedWorks) {
f.Join();
}
TEST(MutexTest, AssertHeld) {
Mutex mutex;
mutex.Lock();
mutex.AssertHeld();
mutex.Unlock();
}
TEST(MutexTest, RecursiveAssertHeld) ABSL_NO_THREAD_SAFETY_ANALYSIS {
RecursiveMutex mutex;
mutex.Lock();
mutex.AssertHeld();
mutex.Lock();
mutex.AssertHeld();
mutex.Unlock();
mutex.AssertHeld();
mutex.Unlock();
}
#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST)
TEST(MutexDeathTest, MutexAssertHeldWithoutLock) {
Mutex mutex;
EXPECT_DEATH(mutex.AssertHeld(), "");
}
TEST(MutexDeathTest, RecursiveMutexAssertHeldWithoutLock) {
RecursiveMutex mutex;
EXPECT_DEATH(mutex.AssertHeld(), "");
}
#endif // !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST)
} // namespace
} // namespace apple
} // namespace nearby
@@ -15,6 +15,7 @@
#ifndef PLATFORM_IMPL_G3_MUTEX_H_
#define PLATFORM_IMPL_G3_MUTEX_H_
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/mutex.h"
#include "internal/platform/implementation/shared/posix_mutex.h"
@@ -35,8 +36,13 @@ class ABSL_LOCKABLE Mutex : public api::Mutex {
mutex_.Lock();
if (!check_) mutex_.ForgetDeadlockInfo();
}
void Unlock() ABSL_UNLOCK_FUNCTION() override { mutex_.Unlock(); }
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() override {
mutex_.AssertHeld();
}
private:
friend class ConditionVariable;
absl::Mutex mutex_;
+2
View File
@@ -45,6 +45,8 @@ class ABSL_LOCKABLE Mutex {
virtual void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() = 0;
virtual void Unlock() ABSL_UNLOCK_FUNCTION() = 0;
// Assert that this mutex is held by the calling thread.
virtual void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() {}
};
} // namespace api
@@ -29,6 +29,7 @@ class ABSL_LOCKABLE Mutex : public api::Mutex {
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override;
void Unlock() ABSL_UNLOCK_FUNCTION() override;
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() override {}
private:
friend class ConditionVariable;
@@ -52,6 +52,12 @@ class ABSL_LOCKABLE Mutex : public api::Mutex {
}
}
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() override {
if (mode_ == Mode::kRegular || mode_ == Mode::kRegularNoCheck) {
mutex_.AssertHeld();
}
}
absl::Mutex& GetMutex() { return mutex_; }
std::recursive_mutex& GetRecursiveMutex() { return recursive_mutex_; }
+2
View File
@@ -41,6 +41,7 @@ class ABSL_LOCKABLE Mutex final {
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { impl_->Lock(); }
void Unlock() ABSL_UNLOCK_FUNCTION() { impl_->Unlock(); }
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() { impl_->AssertHeld(); }
private:
friend class ConditionVariable;
@@ -65,6 +66,7 @@ class ABSL_LOCKABLE RecursiveMutex final {
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { impl_->Lock(); }
void Unlock() ABSL_UNLOCK_FUNCTION() { impl_->Unlock(); }
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() { impl_->AssertHeld(); }
private:
friend class MutexLock;
+36 -1
View File
@@ -14,11 +14,13 @@
#include "internal/platform/mutex.h"
#include <atomic>
#include "gtest/gtest.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/platform/condition_variable.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
@@ -111,5 +113,38 @@ TEST_F(MutexTest, DoubleLockIsNotDeadlock) {
VerifyStepReached(2);
}
TEST_F(MutexTest, AssertHeld) {
Mutex mutex;
mutex.Lock();
mutex.AssertHeld();
mutex.Unlock();
}
TEST_F(MutexTest, RecursiveAssertHeld) ABSL_NO_THREAD_SAFETY_ANALYSIS {
RecursiveMutex mutex;
mutex.Lock();
mutex.AssertHeld();
mutex.Lock();
mutex.AssertHeld();
mutex.Unlock();
mutex.AssertHeld();
mutex.Unlock();
}
#ifndef NDEBUG
using MutexDeathTest = MutexTest;
// Mutex death test may fail on some platforms.
TEST_F(MutexDeathTest, DISABLED_MutexAssertHeldWithoutLock) {
Mutex mutex;
EXPECT_DEATH(mutex.AssertHeld(), "");
}
// RecursiveMutex death test may fail on some platforms.
TEST_F(MutexDeathTest, DISABLED_RecursiveMutexAssertHeldWithoutLock) {
RecursiveMutex mutex;
EXPECT_DEATH(mutex.AssertHeld(), "");
}
#endif
} // namespace
} // namespace nearby