reentrancy_check.hpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* Copyright 2023 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See https://www.boost.org/libs/unordered for library home page.
  7. */
  8. #ifndef BOOST_UNORDERED_DETAIL_FOA_REENTRANCY_CHECK_HPP
  9. #define BOOST_UNORDERED_DETAIL_FOA_REENTRANCY_CHECK_HPP
  10. #include <boost/assert.hpp>
  11. #include <utility>
  12. #if !defined(BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK)&& \
  13. !defined(BOOST_ASSERT_IS_VOID)
  14. #define BOOST_UNORDERED_REENTRANCY_CHECK
  15. #endif
  16. namespace boost{
  17. namespace unordered{
  18. namespace detail{
  19. namespace foa{
  20. #if defined(BOOST_UNORDERED_REENTRANCY_CHECK)
  21. class entry_trace
  22. {
  23. public:
  24. entry_trace(const void* px_):px{px_}
  25. {
  26. if(px){
  27. BOOST_ASSERT_MSG(!find(px),"reentrancy not allowed");
  28. header()=this;
  29. }
  30. }
  31. /* not used but VS in pre-C++17 mode needs to see it for RVO */
  32. entry_trace(const entry_trace&);
  33. ~entry_trace(){clear();}
  34. void clear()
  35. {
  36. if(px){
  37. header()=next;
  38. px=nullptr;
  39. }
  40. }
  41. private:
  42. static entry_trace*& header()
  43. {
  44. thread_local entry_trace *pe=nullptr;
  45. return pe;
  46. }
  47. static bool find(const void* px)
  48. {
  49. for(auto pe=header();pe;pe=pe->next){
  50. if(pe->px==px)return true;
  51. }
  52. return false;
  53. }
  54. const void *px;
  55. entry_trace *next=header();
  56. };
  57. template<typename LockGuard>
  58. struct reentrancy_checked
  59. {
  60. template<typename... Args>
  61. reentrancy_checked(const void* px,Args&&... args):
  62. tr{px},lck{std::forward<Args>(args)...}{}
  63. void unlock()
  64. {
  65. lck.unlock();
  66. tr.clear();
  67. }
  68. entry_trace tr;
  69. LockGuard lck;
  70. };
  71. template<typename LockGuard>
  72. struct reentrancy_bichecked
  73. {
  74. template<typename... Args>
  75. reentrancy_bichecked(const void* px,const void* py,Args&&... args):
  76. tr1{px},tr2{py!=px?py:nullptr},lck{std::forward<Args>(args)...}{}
  77. void unlock()
  78. {
  79. lck.unlock();
  80. tr2.clear();
  81. tr1.clear();
  82. }
  83. entry_trace tr1,tr2;
  84. LockGuard lck;
  85. };
  86. #else
  87. template<typename LockGuard>
  88. struct reentrancy_checked
  89. {
  90. template<typename... Args>
  91. reentrancy_checked(const void*,Args&&... args):
  92. lck{std::forward<Args>(args)...}{}
  93. void unlock(){lck.unlock();}
  94. LockGuard lck;
  95. };
  96. template<typename LockGuard>
  97. struct reentrancy_bichecked
  98. {
  99. template<typename... Args>
  100. reentrancy_bichecked(const void*,const void*,Args&&... args):
  101. lck{std::forward<Args>(args)...}{}
  102. void unlock(){lck.unlock();}
  103. LockGuard lck;
  104. };
  105. #endif
  106. } /* namespace foa */
  107. } /* namespace detail */
  108. } /* namespace unordered */
  109. } /* namespace boost */
  110. #endif