From f85ec3e9fb02b82cff1bcd5b4ce7789efbef0866 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 28 Jul 2023 13:20:11 +0200 Subject: [PATCH] first draft of Clang thread safety analysis support --- .../unordered/detail/foa/annotated_mutex.hpp | 138 ++++++++++++++++++ .../unordered/detail/foa/concurrent_table.hpp | 19 ++- .../unordered/detail/foa/reentrancy_check.hpp | 107 ++++++++++---- 3 files changed, 225 insertions(+), 39 deletions(-) create mode 100644 include/boost/unordered/detail/foa/annotated_mutex.hpp diff --git a/include/boost/unordered/detail/foa/annotated_mutex.hpp b/include/boost/unordered/detail/foa/annotated_mutex.hpp new file mode 100644 index 00000000..5d93f568 --- /dev/null +++ b/include/boost/unordered/detail/foa/annotated_mutex.hpp @@ -0,0 +1,138 @@ +/* Copyright 2023 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_DETAIL_FOA_ANNOTATED_MUTEX_HPP +#define BOOST_UNORDERED_DETAIL_FOA_ANNOTATED_MUTEX_HPP + +#include +#include + +namespace boost{ +namespace unordered{ +namespace detail{ +namespace foa{ + +/* reference: https://clang.llvm.org/docs/ThreadSafetyAnalysis.htm */ + +#if defined(BOOST_CLANG)&&!defined(SWIG) +#define BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(x) __attribute__((x)) +#else +#define BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(x) +#endif + +#define BOOST_UNORDERED_CAPABILITY(x) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(capability(x)) + +#define BOOST_UNORDERED_SCOPED_CAPABILITY \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(scoped_lockable) + +#define BOOST_UNORDERED_GUARDED_BY(x) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(guarded_by(x)) + +#define BOOST_UNORDERED_PT_GUARDED_BY(x) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(pt_guarded_by(x)) + +#define BOOST_UNORDERED_ACQUIRED_BEFORE(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquired_before(__VA_ARGS__)) + +#define BOOST_UNORDERED_ACQUIRED_AFTER(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquired_after(__VA_ARGS__)) + +#define BOOST_UNORDERED_REQUIRES(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(requires_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_REQUIRES_SHARED(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(requires_shared_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_ACQUIRE(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquire_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_ACQUIRE_SHARED(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(acquire_shared_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_RELEASE(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(release_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_RELEASE_SHARED(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(release_shared_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_RELEASE_GENERIC(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(release_generic_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_TRY_ACQUIRE(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(try_acquire_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_TRY_ACQUIRE_SHARED(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR( \ + try_acquire_shared_capability(__VA_ARGS__)) + +#define BOOST_UNORDERED_EXCLUDES(...) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(locks_excluded(__VA_ARGS__)) + +#define BOOST_UNORDERED_ASSERT_CAPABILITY(x) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(assert_capability(x)) + +#define BOOST_UNORDERED_ASSERT_SHARED_CAPABILITY(x) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(assert_shared_capability(x)) + +#define BOOST_UNORDERED_RETURN_CAPABILITY(x) \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(lock_returned(x)) + +#define BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS \ +BOOST_UNORDERED_THREAD_ANNOTATION_ATTR(no_thread_safety_analysis) + +template +struct BOOST_UNORDERED_CAPABILITY("mutex") annotated_mutex:Mutex +{ + using super=Mutex; + + using super::super; + + void lock() noexcept(noexcept(super::lock())) + BOOST_UNORDERED_ACQUIRE() + { + super::lock(); + } + + bool try_lock() noexcept(noexcept(super::try_lock())) + BOOST_UNORDERED_TRY_ACQUIRE(true) + { + return super::try_lock(); + } + + void unlock() noexcept(noexcept(super::unlock())) + BOOST_UNORDERED_RELEASE() + { + super::unlock(); + } + + void lock_shared() noexcept(noexcept(super::lock_shared())) + BOOST_UNORDERED_ACQUIRE_SHARED() + { + super::lock_shared(); + } + + bool try_lock_shared() noexcept(noexcept(super::try_lock_shared())) + BOOST_UNORDERED_TRY_ACQUIRE_SHARED(true) + { + return super::try_lock(); + } + + void unlock_shared() noexcept(noexcept(super::unlock_shared())) + BOOST_UNORDERED_RELEASE_SHARED() + { + super::unlock_shared(); + } +}; + +} /* namespace foa */ +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#endif diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index 7fc397cc..c7f17ca3 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -108,8 +109,10 @@ public: return mutexes[pos]; } - void lock()noexcept{for(std::size_t n=0;n0;)mutexes[--n].unlock();} + void lock()noexcept BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS + {for(std::size_t n=0;n0;)mutexes[--n].unlock();} private: cache_aligned_array mutexes; @@ -127,8 +130,10 @@ public: /* not used but VS in pre-C++17 mode needs to see it for RVO */ shared_lock(const shared_lock&); - void lock(){BOOST_ASSERT(!owns);m.lock_shared();owns=true;} - void unlock(){BOOST_ASSERT(owns);m.unlock_shared();owns=false;} + void lock() BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS + {BOOST_ASSERT(!owns);m.lock_shared();owns=true;} + void unlock() BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS + {BOOST_ASSERT(owns);m.unlock_shared();owns=false;} private: Mutex &m; @@ -212,7 +217,7 @@ struct atomic_integral struct group_access { - using mutex_type=rw_spinlock; + using mutex_type=annotated_mutex; using shared_lock_guard=shared_lock; using exclusive_lock_guard=lock_guard; using insert_counter_type=std::atomic; @@ -836,8 +841,8 @@ public: } private: - using mutex_type=rw_spinlock; - using multimutex_type=multimutex; // TODO: adapt 128 to the machine + using mutex_type=annotated_mutex; + using multimutex_type=annotated_mutex>; // TODO: adapt 128 to the machine using shared_lock_guard=reentrancy_checked>; using exclusive_lock_guard=reentrancy_checked>; using exclusive_bilock_guard=reentrancy_bichecked>; diff --git a/include/boost/unordered/detail/foa/reentrancy_check.hpp b/include/boost/unordered/detail/foa/reentrancy_check.hpp index 2855056a..e824ec32 100644 --- a/include/boost/unordered/detail/foa/reentrancy_check.hpp +++ b/include/boost/unordered/detail/foa/reentrancy_check.hpp @@ -10,6 +10,7 @@ #define BOOST_UNORDERED_DETAIL_FOA_REENTRANCY_CHECK_HPP #include +#include #include #if !defined(BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK)&& \ @@ -67,65 +68,107 @@ private: entry_trace *next=header(); }; -template -struct reentrancy_checked -{ - template - reentrancy_checked(const void* px,Args&&... args): - tr{px},lck{std::forward(args)...}{} +template +struct reentrancy_checked; - void unlock() +template