Compare commits

..

1 Commits

Author SHA1 Message Date
Christian Mazakas 5339bf67d9 Add missing #include's 2023-08-03 10:52:03 -07:00
8 changed files with 16 additions and 424 deletions
-5
View File
@@ -6,11 +6,6 @@
:github-pr-url: https://github.com/boostorg/unordered/pull
:cpp: C++
== Release 1.84.0
* Added debug mode mechanisms for detecting illegal reentrancies into
a `boost::concurrent_flat_map` from user code.
== Release 1.83.0 - Major update
* Added `boost::concurrent_flat_map`, a fast, thread-safe hashmap based on open addressing.
@@ -1,138 +0,0 @@
/* 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,9 +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>
#include <boost/unordered/detail/foa/tuple_rotate_right.hpp>
#include <cstddef>
@@ -109,10 +107,8 @@ public:
return mutexes[pos];
}
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();}
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();}
private:
cache_aligned_array<Mutex,N> mutexes;
@@ -130,10 +126,8 @@ public:
/* not used but VS in pre-C++17 mode needs to see it for RVO */
shared_lock(const shared_lock&);
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;}
void lock(){BOOST_ASSERT(!owns);m.lock_shared();owns=true;}
void unlock(){BOOST_ASSERT(owns);m.unlock_shared();owns=false;}
private:
Mutex &m;
@@ -217,7 +211,7 @@ struct atomic_integral
struct group_access
{
using mutex_type=annotated_mutex<rw_spinlock>;
using mutex_type=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>;
@@ -841,11 +835,11 @@ public:
}
private:
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>>;
using mutex_type=rw_spinlock;
using multimutex_type=multimutex<mutex_type,128>; // TODO: adapt 128 to the machine
using shared_lock_guard=shared_lock<mutex_type>;
using exclusive_lock_guard=lock_guard<multimutex_type>;
using exclusive_bilock_guard=scoped_bilock<multimutex_type>;
using group_shared_lock_guard=typename group_access::shared_lock_guard;
using group_exclusive_lock_guard=typename group_access::exclusive_lock_guard;
using group_insert_counter_type=typename group_access::insert_counter_type;
@@ -865,18 +859,18 @@ private:
{
thread_local auto id=(++thread_counter)%mutexes.size();
return shared_lock_guard{this,mutexes[id]};
return shared_lock_guard{mutexes[id]};
}
inline exclusive_lock_guard exclusive_access()const
{
return exclusive_lock_guard{this,mutexes};
return exclusive_lock_guard{mutexes};
}
static inline exclusive_bilock_guard exclusive_access(
const concurrent_table& x,const concurrent_table& y)
{
return {&x,&y,x.mutexes,y.mutexes};
return {x.mutexes,y.mutexes};
}
template<typename Hash2,typename Pred2>
@@ -884,7 +878,7 @@ private:
const concurrent_table& x,
const concurrent_table<TypePolicy,Hash2,Pred2,Allocator>& y)
{
return {&x,&y,x.mutexes,y.mutexes};
return {x.mutexes,y.mutexes};
}
/* Tag-dispatched shared/exclusive group access */
@@ -6,6 +6,7 @@
#define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP
#include <boost/core/allocator_access.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/core/pointer_traits.hpp>
namespace boost {
@@ -6,6 +6,7 @@
#define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP
#include <boost/core/allocator_access.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/core/pointer_traits.hpp>
namespace boost {
@@ -1,181 +0,0 @@
/* 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_REENTRANCY_CHECK_HPP
#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)&& \
!defined(BOOST_ASSERT_IS_VOID)
#define BOOST_UNORDERED_REENTRANCY_CHECK
#endif
namespace boost{
namespace unordered{
namespace detail{
namespace foa{
#if defined(BOOST_UNORDERED_REENTRANCY_CHECK)
class entry_trace
{
public:
entry_trace(const void* px_):px{px_}
{
if(px){
BOOST_ASSERT_MSG(!find(px),"reentrancy not allowed");
header()=this;
}
}
/* not used but VS in pre-C++17 mode needs to see it for RVO */
entry_trace(const entry_trace&);
~entry_trace(){clear();}
void clear()
{
if(px){
header()=next;
px=nullptr;
}
}
private:
static entry_trace*& header()
{
thread_local entry_trace *pe=nullptr;
return pe;
}
static bool find(const void* px)
{
for(auto pe=header();pe;pe=pe->next){
if(pe->px==px)return true;
}
return false;
}
const void *px;
entry_trace *next=header();
};
template<typename>
struct reentrancy_checked;
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<Mutex> lck;
Mutex& m;
};
template<typename>
struct reentrancy_bichecked;
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<Mutex> lck;
Mutex &m1,&m2;
};
#else
template<typename>
struct reentrancy_checked;
template<template <typename> class LockGuard,typename Mutex>
struct BOOST_UNORDERED_SCOPED_CAPABILITY reentrancy_checked<LockGuard<Mutex>>
{
reentrancy_checked(const void*,Mutex& m_)
BOOST_UNORDERED_ACQUIRE(m_):
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();
}
LockGuard<Mutex> lck;
Mutex& m;
};
template<typename>
struct reentrancy_bichecked;
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*,const void*,Mutex1& m1_,Mutex2& m2_)
BOOST_UNORDERED_ACQUIRE(m1_,m2_):
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();
}
LockGuard<Mutex> lck;
Mutex &m1,&m2;
};
#endif
} /* namespace foa */
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif
-1
View File
@@ -202,7 +202,6 @@ local CFOA_TESTS =
rw_spinlock_test6
rw_spinlock_test7
rw_spinlock_test8
reentrancy_check_test
;
for local test in $(CFOA_TESTS)
-79
View File
@@ -1,79 +0,0 @@
// Copyright 2023 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <cstdlib>
#define BOOST_ENABLE_ASSERT_HANDLER
static bool reentrancy_detected = false;
namespace boost {
// Caveat lector: a proper handler shouldn't throw as it may be executed
// within a noexcept function.
void assertion_failed_msg(
char const*, char const*, char const*, char const*, long)
{
reentrancy_detected = true;
throw 0;
}
void assertion_failed(char const*, char const*, char const*, long) // LCOV_EXCL_START
{
std::abort();
} // LCOV_EXCL_STOP
}
#include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/core/lightweight_test.hpp>
template<typename F>
void detect_reentrancy(F f)
{
reentrancy_detected = false;
try {
f();
}
catch(int) {}
BOOST_TEST(reentrancy_detected);
}
int main()
{
using map = boost::concurrent_flat_map<int, int>;
using value_type = typename map::value_type;
map m1, m2;
m1.emplace(0, 0);
m2.emplace(1, 0);
detect_reentrancy([&] {
m1.visit_all([&](value_type&) { (void)m1.contains(0); });
}); // LCOV_EXCL_LINE
detect_reentrancy([&] {
m1.visit_all([&](value_type&) { m1.rehash(0); });
}); // LCOV_EXCL_LINE
detect_reentrancy([&] {
m1.visit_all([&](value_type&) {
m2.visit_all([&](value_type&) {
m1=m2;
}); // LCOV_EXCL_START
});
});
// LCOV_EXCL_STOP
detect_reentrancy([&] {
m1.visit_all([&](value_type&) {
m2.visit_all([&](value_type&) {
m2=m1;
}); // LCOV_EXCL_START
});
});
// LCOV_EXCL_STOP
return boost::report_errors();
}