SERVER-19549 clang thread safety annotations (#43219)

Co-authored-by: Mathias Stearn <mathias@mongodb.com>
GitOrigin-RevId: 71441319c7613ba0ea22ddae772c31cf1430d592
This commit is contained in:
Brad Cater 2025-11-05 16:37:22 -05:00 committed by MongoDB Bot
parent d545ba6fe4
commit 3cf541e9ef
12 changed files with 744 additions and 0 deletions

3
.github/CODEOWNERS vendored
View File

@ -2714,6 +2714,9 @@ WORKSPACE.bazel @10gen/devprod-build @svc-auto-approve-bot
/src/mongo/db/repl/**/*topology_coordinator* @10gen/server-replication-coordinator @svc-auto-approve-bot
/src/mongo/db/repl/**/FCV_AND_FEATURE_FLAG_README.md @10gen/server-catalog-and-routing-routing-and-topology @10gen/server-fcv @svc-auto-approve-bot
# The following patterns are parsed from ./src/mongo/db/repl/clang_checked/OWNERS.yml
/src/mongo/db/repl/clang_checked/**/* @10gen/server-replication-reviewers @svc-auto-approve-bot
# The following patterns are parsed from ./src/mongo/db/repl/dbcheck/OWNERS.yml
/src/mongo/db/repl/dbcheck/**/* @10gen/server-dbcheck @svc-auto-approve-bot

View File

@ -231,6 +231,7 @@ SYMBOL_ORDER_FILES = [
RE_ENABLE_DISABLED_3RD_PARTY_WARNINGS_FEATURES = select({
"//bazel/config:compiler_type_clang": [
"-disable_warnings_for_third_party_libraries_clang",
"thread_safety_warnings",
],
"//bazel/config:compiler_type_gcc": [
"-disable_warnings_for_third_party_libraries_gcc",

View File

@ -784,6 +784,20 @@ def _impl(ctx):
],
)
thread_safety_warnings_feature = feature(
name = "thread_safety_warnings",
enabled = False,
flag_sets = [
flag_set(
actions = all_cpp_compile_actions,
flag_groups = [flag_group(flags = [
# Warn about thread safety issues
"-Wthread-safety",
])],
),
],
)
disable_warnings_for_third_party_libraries_clang_feature = feature(
name = "disable_warnings_for_third_party_libraries_clang",
enabled = ctx.attr.compiler == COMPILERS.CLANG,
@ -1418,6 +1432,7 @@ def _impl(ctx):
pessimizing_move_warning_feature,
no_class_memaccess_warning_feature,
no_interference_size_warning_feature,
thread_safety_warnings_feature,
disable_warnings_for_third_party_libraries_clang_feature,
disable_warnings_for_third_party_libraries_gcc_feature,
disable_floating_point_contractions_feature,

View File

@ -985,6 +985,14 @@ replicated_storage_service:
files:
- src/mongo/db/rss
replication.clang_checked:
meta:
slack: server-replication
jira: Replication
fully_marked: true
files:
- src/mongo/db/repl/clang_checked/*
replication.hello:
meta:
slack: server-replication

View File

@ -0,0 +1,30 @@
load("//bazel:mongo_src_rules.bzl", "mongo_cc_library", "mongo_cc_unit_test")
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.h"]))
mongo_cc_library(
name = "clang_checked",
hdrs = [
"checked_mutex.h",
"lockable_concepts.h",
"mutex.h",
"thread_safety_annotations.h",
],
)
mongo_cc_unit_test(
name = "clang_checked_test",
srcs = [
"checked_mutex_test.cpp",
"mutex_test.cpp",
],
tags = [
"mongo_unittest_second_group",
"server-programmability",
],
deps = [
"//src/mongo/db/repl/clang_checked",
],
)

View File

@ -0,0 +1,5 @@
version: 1.0.0
filters:
- "*":
approvers:
- 10gen/server-replication-reviewers

View File

@ -0,0 +1,72 @@
/**
* Copyright (C) 2025-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/db/repl/clang_checked/lockable_concepts.h"
#include "mongo/db/repl/clang_checked/thread_safety_annotations.h"
#include "mongo/util/modules.h"
#include <concepts>
namespace MONGO_MOD_PUB mongo {
namespace clang_checked {
/**
* CheckedMutex is a wrapper for other mutex types for cases where clang's
* thread safety checks are desirable. By combining CheckedMutex and the
* annotations defined in thread_safety_annotations.h in this directory, you
* can enforce constraints such as "this member is always guarded by that
* mutex."
*/
template <BaseLockable MutexT>
class MONGO_LOCKING_CAPABILITY("mutex") CheckedMutex {
public:
using mutex_type = MutexT;
void lock() MONGO_LOCKING_ACQUIRE() {
_m.lock();
}
bool try_lock()
requires TryLockable<mutex_type>
MONGO_LOCKING_TRY_ACQUIRE(true) {
return _m.try_lock();
}
void unlock() MONGO_LOCKING_RELEASE() {
_m.unlock();
}
private:
mutable mutex_type _m;
};
} // namespace clang_checked
} // namespace MONGO_MOD_PUB mongo

View File

@ -0,0 +1,78 @@
/**
* Copyright (C) 2025-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/db/repl/clang_checked/checked_mutex.h"
#include "mongo/db/repl/clang_checked/mutex.h"
#include "mongo/db/repl/clang_checked/thread_safety_annotations.h"
#include "mongo/stdx/mutex.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/observable_mutex.h"
namespace mongo {
namespace {
template <typename MutexT>
class Foo {
public:
using mutex_type = MutexT;
explicit Foo(int i) : _i(i) {}
void incI() {
clang_checked::lock_guard lk(_m);
_i++;
}
int getI() {
clang_checked::lock_guard lk(_m);
return _i;
}
private:
mutable clang_checked::CheckedMutex<mutex_type> _m;
int _i MONGO_LOCKING_GUARDED_BY(_m);
};
TEST(CheckedMutexTest, CheckedMutexShouldWorkWithStdxMutex) {
auto f = Foo<stdx::mutex>(0);
ASSERT_EQ(f.getI(), 0);
f.incI();
ASSERT_EQ(f.getI(), 1);
}
TEST(CheckedMutexTest, CheckedMutexShouldWorkWithObservableMutexStdxMutex) {
auto f = Foo<ObservableMutex<mongo::stdx::mutex>>(0);
ASSERT_EQ(f.getI(), 0);
f.incI();
ASSERT_EQ(f.getI(), 1);
}
} // namespace
} // namespace mongo

View File

@ -0,0 +1,52 @@
/**
* Copyright (C) 2025-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/util/modules.h"
#include <concepts>
namespace MONGO_MOD_PUB mongo {
namespace clang_checked {
template <typename T>
concept BaseLockable = requires(T obj) {
{ obj.lock() };
{ obj.unlock() };
};
template <typename T>
concept TryLockable = requires(T obj) {
requires BaseLockable<T>;
{ obj.try_lock() };
};
} // namespace clang_checked
} // namespace MONGO_MOD_PUB mongo

View File

@ -0,0 +1,197 @@
/**
* Copyright (C) 2025-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/db/repl/clang_checked/lockable_concepts.h"
#include "mongo/db/repl/clang_checked/thread_safety_annotations.h"
#include "mongo/util/concurrency/with_lock.h"
#include "mongo/util/modules.h"
#include <system_error>
namespace MONGO_MOD_PUB mongo {
namespace clang_checked {
struct adopt_lock_t {
explicit adopt_lock_t() = default;
};
constexpr inline adopt_lock_t adopt_lock;
struct defer_lock_t {
explicit defer_lock_t() = default;
};
constexpr inline defer_lock_t defer_lock;
struct try_to_lock_t {
explicit try_to_lock_t() = default;
};
constexpr inline try_to_lock_t try_to_lock;
/**
* lock_guard is analagous to std::lock_guard and is compatible with
* CheckedMutex defined in checked_mutex.h.
*/
template <BaseLockable MutexT>
class MONGO_LOCKING_SCOPED_CAPABILITY lock_guard {
public:
using mutex_type = MutexT;
explicit lock_guard(mutex_type& mu) MONGO_LOCKING_ACQUIRE(mu) : _mu(mu) {
_mu.lock();
}
lock_guard(mutex_type& mu, adopt_lock_t) MONGO_LOCKING_ACQUIRE(mu) : _mu(mu) {}
lock_guard(lock_guard&&) = delete;
lock_guard& operator=(lock_guard&&) = delete;
~lock_guard() MONGO_LOCKING_RELEASE() {
_mu.unlock();
}
operator WithLock() {
// We know that we hold the lock.
return WithLock::withoutLock();
}
private:
mutex_type& _mu;
};
/**
* unique_lock is analagous to std::unique_lock and is compatible with
* CheckedMutex defined in checked_mutex.h.
*/
template <BaseLockable MutexT>
class MONGO_LOCKING_SCOPED_CAPABILITY unique_lock {
public:
using mutex_type = MutexT;
unique_lock() noexcept : _mu(nullptr), _locked(true) {}
explicit unique_lock(mutex_type& mu) MONGO_LOCKING_ACQUIRE(mu) : _mu(&mu), _locked(true) {
_mu->lock();
}
unique_lock(mutex_type& mu, defer_lock_t) noexcept : _mu(&mu) {}
unique_lock(mutex_type& mu, try_to_lock_t) MONGO_LOCKING_TRY_ACQUIRE(true, mu) : _mu(&mu) {
_locked = _mu->try_lock();
}
unique_lock(mutex_type& mu, adopt_lock_t) MONGO_LOCKING_ACQUIRE(mu) : _mu(&mu), _locked(true) {
invariant(_mu->owns_lock());
}
unique_lock(unique_lock&& other) noexcept
: _mu{std::exchange(other._mu, nullptr)}, _locked{std::exchange(other._locked, false)} {}
unique_lock& operator=(unique_lock&& other) noexcept MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
if (this != &other) {
if (_locked) {
_mu->unlock();
}
_mu = std::exchange(other._mu, nullptr);
_locked = std::exchange(other._locked, false);
}
return *this;
}
~unique_lock() MONGO_LOCKING_RELEASE() {
if (_locked) {
_mu->unlock();
}
}
void lock() MONGO_LOCKING_ACQUIRE(_mu) {
assertHasMutex();
_mu->lock();
_locked = true;
}
bool try_lock()
requires TryLockable<mutex_type>
MONGO_LOCKING_TRY_ACQUIRE(true, _mu) {
assertHasMutex();
if (_locked) {
return false;
}
_locked = _mu->try_lock();
return _locked;
}
void unlock() MONGO_LOCKING_RELEASE() {
assertHasMutex();
_mu->unlock();
_locked = false;
}
bool owns_lock() const noexcept {
return _locked;
}
mutex_type* mutex() const noexcept {
return _mu;
}
explicit operator bool() const noexcept {
return _locked;
}
void swap(unique_lock& other) noexcept {
using std::swap;
swap(_mu, other._mu);
swap(_locked, other._locked);
}
friend void swap(unique_lock& lhs, unique_lock& rhs) {
lhs.swap(rhs);
}
operator WithLock() {
invariant(owns_lock());
return WithLock::withoutLock();
}
private:
void assertHasMutex() {
if (MONGO_unlikely(_mu == nullptr)) {
std::error_code ec = std::make_error_code(std::errc::operation_not_permitted);
throw std::system_error(ec, "No mutex!");
}
}
mutable mutex_type* _mu;
bool _locked;
};
} // namespace clang_checked
} // namespace MONGO_MOD_PUB mongo

View File

@ -0,0 +1,187 @@
/**
* Copyright (C) 2025-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/db/repl/clang_checked/mutex.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
namespace {
TEST(MutexTest, LockGuardShouldLock) {
stdx::mutex m;
clang_checked::lock_guard lk(m);
// If lock_guard locked m, then try_lock() should return false.
ASSERT_FALSE(m.try_lock());
}
TEST(MutexTest, UniqueLockShouldLockAndUnlock) {
stdx::mutex m;
clang_checked::unique_lock lk(m);
ASSERT_TRUE(lk.owns_lock());
lk.unlock();
ASSERT_FALSE(lk.owns_lock());
}
TEST(MutexTest, UniqueLockShouldTryLockAndOwnsLock) MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
stdx::mutex m;
clang_checked::unique_lock lk(m);
ASSERT_FALSE(lk.try_lock());
ASSERT_TRUE(lk.owns_lock());
lk.unlock();
ASSERT_FALSE(lk.owns_lock());
ASSERT_TRUE(lk.try_lock());
ASSERT_TRUE(lk.owns_lock());
lk.unlock();
ASSERT_FALSE(lk.owns_lock());
}
TEST(MutexTest, UniqueLockShouldConvertToBoolean) MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
stdx::mutex m;
clang_checked::unique_lock lk(m);
ASSERT_FALSE(lk.try_lock());
ASSERT_TRUE(lk);
lk.unlock();
ASSERT_FALSE(lk);
ASSERT_TRUE(lk.try_lock());
ASSERT_TRUE(lk);
lk.unlock();
ASSERT_FALSE(lk);
}
class MONGO_LOCKING_SCOPED_CAPABILITY MutexWithId {
public:
explicit MutexWithId(int id) : _id(id) {}
void lock() MONGO_LOCKING_ACQUIRE() {}
void unlock() MONGO_LOCKING_RELEASE() {}
int id() const {
return _id;
}
private:
int _id;
};
TEST(MutexTest, UniqueLockShouldReturnMutex) MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
MutexWithId m(3);
clang_checked::unique_lock lk(m);
ASSERT_EQ(lk.mutex()->id(), m.id());
lk.lock();
ASSERT_EQ(lk.mutex()->id(), m.id());
lk.unlock();
ASSERT_EQ(lk.mutex()->id(), m.id());
}
TEST(MutexTest, UniqueLockCanSwapWhenBothLocked) MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
MutexWithId m0(0);
clang_checked::unique_lock lk0(m0);
MutexWithId m1(1);
clang_checked::unique_lock lk1(m1);
ASSERT_EQ(lk0.mutex()->id(), m0.id());
ASSERT_EQ(lk1.mutex()->id(), m1.id());
ASSERT_TRUE(lk0.owns_lock());
ASSERT_TRUE(lk1.owns_lock());
lk0.swap(lk1);
ASSERT_EQ(lk1.mutex()->id(), m0.id());
ASSERT_EQ(lk0.mutex()->id(), m1.id());
ASSERT_TRUE(lk0.owns_lock());
ASSERT_TRUE(lk1.owns_lock());
}
TEST(MutexTest, UniqueLockCanSwapWhenNeitherLocked) MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
MutexWithId m0(0);
clang_checked::unique_lock lk0(m0);
lk0.unlock();
MutexWithId m1(1);
clang_checked::unique_lock lk1(m1);
lk1.unlock();
ASSERT_EQ(lk0.mutex()->id(), m0.id());
ASSERT_EQ(lk1.mutex()->id(), m1.id());
ASSERT_FALSE(lk0.owns_lock());
ASSERT_FALSE(lk1.owns_lock());
lk0.swap(lk1);
ASSERT_EQ(lk1.mutex()->id(), m0.id());
ASSERT_EQ(lk0.mutex()->id(), m1.id());
ASSERT_FALSE(lk0.owns_lock());
ASSERT_FALSE(lk1.owns_lock());
}
TEST(MutexTest, UniqueLockCanSwapWhenFirstLockedSecondUnlocked)
MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
MutexWithId m0(0);
clang_checked::unique_lock lk0(m0);
MutexWithId m1(1);
clang_checked::unique_lock lk1(m1);
lk1.unlock();
ASSERT_EQ(lk0.mutex()->id(), m0.id());
ASSERT_EQ(lk1.mutex()->id(), m1.id());
ASSERT_TRUE(lk0.owns_lock());
ASSERT_FALSE(lk1.owns_lock());
lk0.swap(lk1);
ASSERT_EQ(lk1.mutex()->id(), m0.id());
ASSERT_EQ(lk0.mutex()->id(), m1.id());
ASSERT_FALSE(lk0.owns_lock());
ASSERT_TRUE(lk1.owns_lock());
}
TEST(MutexTest, UniqueLockCanSwapWhenFirstUnlockedSecondLocked)
MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS {
MutexWithId m0(0);
clang_checked::unique_lock lk0(m0);
lk0.unlock();
MutexWithId m1(1);
clang_checked::unique_lock lk1(m1);
ASSERT_EQ(lk0.mutex()->id(), m0.id());
ASSERT_EQ(lk1.mutex()->id(), m1.id());
ASSERT_FALSE(lk0.owns_lock());
ASSERT_TRUE(lk1.owns_lock());
lk0.swap(lk1);
ASSERT_EQ(lk1.mutex()->id(), m0.id());
ASSERT_EQ(lk0.mutex()->id(), m1.id());
ASSERT_TRUE(lk0.owns_lock());
ASSERT_FALSE(lk1.owns_lock());
}
void takesWithLock(WithLock) {}
TEST(MutexTest, LockGuardShouldConvertToWithLock) {
stdx::mutex m;
clang_checked::lock_guard lk(m);
takesWithLock(lk);
}
TEST(MutexTest, UniqueLockShouldConvertToWithLock) {
stdx::mutex m;
clang_checked::unique_lock lk(m);
takesWithLock(lk);
}
} // namespace
} // namespace mongo

View File

@ -0,0 +1,96 @@
/**
* Copyright (C) 2025-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
/**
* This is heavily inspired by https://clang.llvm.org/docs/ThreadSafetyAnalysis.html.
*
* To enforce a modicum of thread safety at compile time, we use the clang
* thread safety annotations. Mutex and mutex-like classes along with RAII-
* style guards must be annotated as such.
*
* When an error results from clang's failure to prove that a code block is
* safe, or when you do something unsafe on purpose, you can use the
* MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS annotation. There are examples
* throughout the codebase.
*/
// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(__clang__)
#define MONGO_LOCKING_ATTR(x) __attribute__((x))
#else
#define MONGO_LOCKING_ATTR(x)
#endif
#define MONGO_LOCKING_CAPABILITY(x) MONGO_LOCKING_ATTR(capability(x))
#define MONGO_LOCKING_REENTRANT_CAPABILITY MONGO_LOCKING_ATTR(reentrant_capability)
#define MONGO_LOCKING_SCOPED_CAPABILITY MONGO_LOCKING_ATTR(scoped_lockable)
#define MONGO_LOCKING_GUARDED_BY(x) MONGO_LOCKING_ATTR(guarded_by(x))
#define MONGO_LOCKING_PT_GUARDED_BY(x) MONGO_LOCKING_ATTR(pt_guarded_by(x))
#define MONGO_LOCKING_ACQUIRED_BEFORE(...) MONGO_LOCKING_ATTR(acquired_before(__VA_ARGS__))
#define MONGO_LOCKING_ACQUIRED_AFTER(...) MONGO_LOCKING_ATTR(acquired_after(__VA_ARGS__))
#define MONGO_LOCKING_REQUIRES(...) MONGO_LOCKING_ATTR(requires_capability(__VA_ARGS__))
#define MONGO_LOCKING_REQUIRES_SHARED(...) \
MONGO_LOCKING_ATTR(requires_shared_capability(__VA_ARGS__))
#define MONGO_LOCKING_ACQUIRE(...) MONGO_LOCKING_ATTR(acquire_capability(__VA_ARGS__))
#define MONGO_LOCKING_ACQUIRE_SHARED(...) MONGO_LOCKING_ATTR(acquire_shared_capability(__VA_ARGS__))
#define MONGO_LOCKING_RELEASE(...) MONGO_LOCKING_ATTR(release_capability(__VA_ARGS__))
#define MONGO_LOCKING_RELEASE_SHARED(...) MONGO_LOCKING_ATTR(release_shared_capability(__VA_ARGS__))
#define MONGO_LOCKING_RELEASE_GENERIC(...) \
MONGO_LOCKING_ATTR(release_generic_capability(__VA_ARGS__))
#define MONGO_LOCKING_TRY_ACQUIRE(...) MONGO_LOCKING_ATTR(try_acquire_capability(__VA_ARGS__))
#define MONGO_LOCKING_TRY_ACQUIRE_SHARED(...) \
MONGO_LOCKING_ATTR(try_acquire_shared_capability(__VA_ARGS__))
#define MONGO_LOCKING_EXCLUDES(...) MONGO_LOCKING_ATTR(locks_excluded(__VA_ARGS__))
#define MONGO_LOCKING_ASSERT_CAPABILITY(x) MONGO_LOCKING_ATTR(assert_capability(x))
#define MONGO_LOCKING_ASSERT_SHARED_CAPABILITY(x) MONGO_LOCKING_ATTR(assert_shared_capability(x))
#define MONGO_LOCKING_RETURN_CAPABILITY(x) MONGO_LOCKING_ATTR(lock_returned(x))
#define MONGO_LOCKING_NO_THREAD_SAFETY_ANALYSIS MONGO_LOCKING_ATTR(no_thread_safety_analysis)