mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-11 13:34:06 +00:00
first draft of Clang thread safety analysis support
This commit is contained in:
parent
f919ce532a
commit
f85ec3e9fb
138
include/boost/unordered/detail/foa/annotated_mutex.hpp
Normal file
138
include/boost/unordered/detail/foa/annotated_mutex.hpp
Normal file
@ -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 <boost/config.hpp>
|
||||
#include <utility>
|
||||
|
||||
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<typename Mutex>
|
||||
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
|
@ -19,6 +19,7 @@
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/mp11/tuple.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/unordered/detail/foa/annotated_mutex.hpp>
|
||||
#include <boost/unordered/detail/foa/core.hpp>
|
||||
#include <boost/unordered/detail/foa/reentrancy_check.hpp>
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
@ -108,8 +109,10 @@ public:
|
||||
return mutexes[pos];
|
||||
}
|
||||
|
||||
void lock()noexcept{for(std::size_t n=0;n<N;)mutexes[n++].lock();}
|
||||
void unlock()noexcept{for(auto n=N;n>0;)mutexes[--n].unlock();}
|
||||
void lock()noexcept BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS
|
||||
{for(std::size_t n=0;n<N;)mutexes[n++].lock();}
|
||||
void unlock()noexcept BOOST_UNORDERED_NO_THREAD_SAFETY_ANALYSIS
|
||||
{for(auto n=N;n>0;)mutexes[--n].unlock();}
|
||||
|
||||
private:
|
||||
cache_aligned_array<Mutex,N> 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<rw_spinlock>;
|
||||
using shared_lock_guard=shared_lock<mutex_type>;
|
||||
using exclusive_lock_guard=lock_guard<mutex_type>;
|
||||
using insert_counter_type=std::atomic<boost::uint32_t>;
|
||||
@ -836,8 +841,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
using mutex_type=rw_spinlock;
|
||||
using multimutex_type=multimutex<mutex_type,128>; // TODO: adapt 128 to the machine
|
||||
using mutex_type=annotated_mutex<rw_spinlock>;
|
||||
using multimutex_type=annotated_mutex<multimutex<mutex_type,128>>; // TODO: adapt 128 to the machine
|
||||
using shared_lock_guard=reentrancy_checked<shared_lock<mutex_type>>;
|
||||
using exclusive_lock_guard=reentrancy_checked<lock_guard<multimutex_type>>;
|
||||
using exclusive_bilock_guard=reentrancy_bichecked<scoped_bilock<multimutex_type>>;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_REENTRANCY_CHECK_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/foa/annotated_mutex.hpp>
|
||||
#include <utility>
|
||||
|
||||
#if !defined(BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK)&& \
|
||||
@ -67,65 +68,107 @@ private:
|
||||
entry_trace *next=header();
|
||||
};
|
||||
|
||||
template<typename LockGuard>
|
||||
struct reentrancy_checked
|
||||
{
|
||||
template<typename... Args>
|
||||
reentrancy_checked(const void* px,Args&&... args):
|
||||
tr{px},lck{std::forward<Args>(args)...}{}
|
||||
template<typename>
|
||||
struct reentrancy_checked;
|
||||
|
||||
void unlock()
|
||||
template<template <typename> class LockGuard,typename Mutex>
|
||||
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_checked<LockGuard<Mutex>>
|
||||
{
|
||||
reentrancy_checked(const void* px,Mutex& m_)
|
||||
BOOST_UNORDERED_ACQUIRE(m_):
|
||||
tr{px},lck{m_},m{m_}{}
|
||||
|
||||
reentrancy_checked(const reentrancy_checked& x) BOOST_UNORDERED_ACQUIRE(x.m);
|
||||
|
||||
~reentrancy_checked() BOOST_UNORDERED_RELEASE() = default;
|
||||
|
||||
void unlock() BOOST_UNORDERED_RELEASE()
|
||||
{
|
||||
lck.unlock();
|
||||
tr.clear();
|
||||
}
|
||||
|
||||
entry_trace tr;
|
||||
LockGuard lck;
|
||||
entry_trace tr;
|
||||
LockGuard<Mutex> lck;
|
||||
Mutex& m;
|
||||
};
|
||||
|
||||
template<typename LockGuard>
|
||||
struct reentrancy_bichecked
|
||||
{
|
||||
template<typename... Args>
|
||||
reentrancy_bichecked(const void* px,const void* py,Args&&... args):
|
||||
tr1{px},tr2{py!=px?py:nullptr},lck{std::forward<Args>(args)...}{}
|
||||
template<typename>
|
||||
struct reentrancy_bichecked;
|
||||
|
||||
void unlock()
|
||||
template<template <typename> class LockGuard,typename Mutex>
|
||||
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_bichecked<LockGuard<Mutex>>
|
||||
{
|
||||
template<typename Mutex1, typename Mutex2>
|
||||
reentrancy_bichecked(const void* px,const void* py,Mutex1& m1_,Mutex2& m2_)
|
||||
BOOST_UNORDERED_ACQUIRE(m1_,m2_):
|
||||
tr1{px},tr2{py!=px?py:nullptr},lck{m1_,m2_},m1{m1_},m2{m2_}{}
|
||||
|
||||
reentrancy_bichecked(const reentrancy_bichecked& x)
|
||||
BOOST_UNORDERED_ACQUIRE(x.m1,x.m2);
|
||||
|
||||
~reentrancy_bichecked() BOOST_UNORDERED_RELEASE() = default;
|
||||
|
||||
void unlock() BOOST_UNORDERED_RELEASE()
|
||||
{
|
||||
lck.unlock();
|
||||
tr2.clear();
|
||||
tr1.clear();
|
||||
}
|
||||
|
||||
entry_trace tr1,tr2;
|
||||
LockGuard lck;
|
||||
entry_trace tr1,tr2;
|
||||
LockGuard<Mutex> lck;
|
||||
Mutex &m1,&m2;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<typename LockGuard>
|
||||
struct reentrancy_checked
|
||||
template<typename>
|
||||
struct reentrancy_checked;
|
||||
|
||||
template<template <typename> class LockGuard,typename Mutex>
|
||||
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_checked<LockGuard<Mutex>>
|
||||
{
|
||||
template<typename... Args>
|
||||
reentrancy_checked(const void*,Args&&... args):
|
||||
lck{std::forward<Args>(args)...}{}
|
||||
reentrancy_checked(const void*,Mutex& m_)
|
||||
BOOST_UNORDERED_ACQUIRE(m_):
|
||||
lck{m_},m{m_}{}
|
||||
|
||||
void unlock(){lck.unlock();}
|
||||
reentrancy_checked(const reentrancy_checked& x) BOOST_UNORDERED_ACQUIRE(x.m);
|
||||
|
||||
LockGuard lck;
|
||||
~reentrancy_checked() BOOST_UNORDERED_RELEASE() = default;
|
||||
|
||||
void unlock() BOOST_UNORDERED_RELEASE()
|
||||
{
|
||||
lck.unlock();
|
||||
}
|
||||
|
||||
LockGuard<Mutex> lck;
|
||||
Mutex& m;
|
||||
};
|
||||
|
||||
template<typename LockGuard>
|
||||
struct reentrancy_bichecked
|
||||
template<typename>
|
||||
struct reentrancy_bichecked;
|
||||
|
||||
template<template <typename> class LockGuard,typename Mutex>
|
||||
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_bichecked<LockGuard<Mutex>>
|
||||
{
|
||||
template<typename... Args>
|
||||
reentrancy_bichecked(const void*,const void*,Args&&... args):
|
||||
lck{std::forward<Args>(args)...}{}
|
||||
template<typename Mutex1, typename Mutex2>
|
||||
reentrancy_bichecked(const void*,const void*,Mutex1& m1_,Mutex2& m2_)
|
||||
BOOST_UNORDERED_ACQUIRE(m1_,m2_):
|
||||
lck{m1_,m2_},m1{m1_},m2{m2_}{}
|
||||
|
||||
void unlock(){lck.unlock();}
|
||||
reentrancy_bichecked(const reentrancy_bichecked& x)
|
||||
BOOST_UNORDERED_ACQUIRE(x.m1,x.m2);
|
||||
|
||||
LockGuard lck;
|
||||
~reentrancy_bichecked() BOOST_UNORDERED_RELEASE() = default;
|
||||
|
||||
void unlock() BOOST_UNORDERED_RELEASE()
|
||||
{
|
||||
lck.unlock();
|
||||
}
|
||||
|
||||
LockGuard<Mutex> lck;
|
||||
Mutex &m1,&m2;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user