lock_pool.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  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. * Copyright (c) 2011 Helge Bahmann
  7. * Copyright (c) 2013-2014, 2020 Andrey Semashev
  8. */
  9. /*!
  10. * \file atomic/detail/lock_pool.hpp
  11. *
  12. * This header contains declaration of the lock pool used to emulate atomic ops.
  13. */
  14. #ifndef BOOST_ATOMIC_DETAIL_LOCK_POOL_HPP_INCLUDED_
  15. #define BOOST_ATOMIC_DETAIL_LOCK_POOL_HPP_INCLUDED_
  16. #include <cstddef>
  17. #include <chrono>
  18. #include <boost/atomic/detail/config.hpp>
  19. #include <boost/atomic/detail/link.hpp>
  20. #include <boost/atomic/detail/intptr.hpp>
  21. #if defined(BOOST_WINDOWS)
  22. #include <boost/winapi/thread.hpp>
  23. #else // defined(BOOST_WINDOWS)
  24. #include <time.h>
  25. #if !defined(BOOST_HAS_NANOSLEEP)
  26. #include <unistd.h>
  27. #endif // !defined(BOOST_HAS_NANOSLEEP)
  28. #endif // defined(BOOST_WINDOWS)
  29. #include <boost/atomic/detail/header.hpp>
  30. #ifdef BOOST_HAS_PRAGMA_ONCE
  31. #pragma once
  32. #endif
  33. namespace boost {
  34. namespace atomics {
  35. namespace detail {
  36. BOOST_FORCEINLINE void wait_some() noexcept
  37. {
  38. #if defined(BOOST_WINDOWS)
  39. boost::winapi::SwitchToThread();
  40. #elif defined(BOOST_HAS_NANOSLEEP)
  41. // Do not use sched_yield or pthread_yield as at least on Linux it doesn't block the thread if there are no other
  42. // pending threads on the current CPU. Proper sleeping is guaranteed to block the thread, which allows other threads
  43. // to potentially migrate to this CPU and complete the tasks we're waiting for.
  44. timespec ts{};
  45. ts.tv_sec = 0;
  46. ts.tv_nsec = 1000;
  47. nanosleep(&ts, nullptr);
  48. #else
  49. usleep(1);
  50. #endif
  51. }
  52. namespace lock_pool {
  53. BOOST_ATOMIC_DECL void* short_lock(atomics::detail::uintptr_t h) noexcept;
  54. BOOST_ATOMIC_DECL void* long_lock(atomics::detail::uintptr_t h) noexcept;
  55. BOOST_ATOMIC_DECL void unlock(void* vls) noexcept;
  56. BOOST_ATOMIC_DECL void* allocate_wait_state(void* vls, const volatile void* addr) noexcept;
  57. BOOST_ATOMIC_DECL void free_wait_state(void* vls, void* vws) noexcept;
  58. BOOST_ATOMIC_DECL void wait(void* vls, void* vws) noexcept;
  59. #if !defined(BOOST_WINDOWS)
  60. BOOST_ATOMIC_DECL bool wait_until(void* vls, void* vws, clockid_t clock_id, timespec const& abs_timeout) noexcept;
  61. #endif // !defined(BOOST_WINDOWS)
  62. BOOST_ATOMIC_DECL bool wait_for(void* vls, void* vws, std::chrono::nanoseconds rel_timeout) noexcept;
  63. BOOST_ATOMIC_DECL void notify_one(void* vls, const volatile void* addr) noexcept;
  64. BOOST_ATOMIC_DECL void notify_all(void* vls, const volatile void* addr) noexcept;
  65. BOOST_ATOMIC_DECL void thread_fence() noexcept;
  66. BOOST_ATOMIC_DECL void signal_fence() noexcept;
  67. template< std::size_t Alignment >
  68. BOOST_FORCEINLINE atomics::detail::uintptr_t hash_ptr(const volatile void* addr) noexcept
  69. {
  70. atomics::detail::uintptr_t ptr = reinterpret_cast< atomics::detail::uintptr_t >(addr);
  71. atomics::detail::uintptr_t h = ptr / Alignment;
  72. // Since many malloc/new implementations return pointers with higher alignment
  73. // than indicated by Alignment, it makes sense to mix higher bits
  74. // into the lower ones. On 64-bit platforms, malloc typically aligns to 16 bytes,
  75. // on 32-bit - to 8 bytes.
  76. constexpr std::size_t malloc_alignment = sizeof(void*) >= 8u ? 16u : 8u;
  77. BOOST_IF_CONSTEXPR (Alignment != malloc_alignment)
  78. h ^= ptr / malloc_alignment;
  79. return h;
  80. }
  81. template< std::size_t Alignment, bool LongLock = false >
  82. class scoped_lock
  83. {
  84. private:
  85. void* m_lock;
  86. public:
  87. explicit scoped_lock(const volatile void* addr) noexcept
  88. {
  89. atomics::detail::uintptr_t h = lock_pool::hash_ptr< Alignment >(addr);
  90. BOOST_IF_CONSTEXPR (!LongLock)
  91. m_lock = lock_pool::short_lock(h);
  92. else
  93. m_lock = lock_pool::long_lock(h);
  94. }
  95. scoped_lock(scoped_lock const&) = delete;
  96. scoped_lock& operator=(scoped_lock const&) = delete;
  97. ~scoped_lock() noexcept
  98. {
  99. lock_pool::unlock(m_lock);
  100. }
  101. void* get_lock_state() const noexcept
  102. {
  103. return m_lock;
  104. }
  105. };
  106. template< std::size_t Alignment >
  107. class scoped_wait_state :
  108. public scoped_lock< Alignment, true >
  109. {
  110. private:
  111. void* m_wait_state;
  112. public:
  113. explicit scoped_wait_state(const volatile void* addr) noexcept :
  114. scoped_lock< Alignment, true >(addr)
  115. {
  116. m_wait_state = lock_pool::allocate_wait_state(this->get_lock_state(), addr);
  117. }
  118. scoped_wait_state(scoped_wait_state const&) = delete;
  119. scoped_wait_state& operator=(scoped_wait_state const&) = delete;
  120. ~scoped_wait_state() noexcept
  121. {
  122. lock_pool::free_wait_state(this->get_lock_state(), m_wait_state);
  123. }
  124. void wait() noexcept
  125. {
  126. lock_pool::wait(this->get_lock_state(), m_wait_state);
  127. }
  128. #if !defined(BOOST_WINDOWS)
  129. bool wait_until(clockid_t clock_id, timespec const& abs_timeout) noexcept
  130. {
  131. return lock_pool::wait_until(this->get_lock_state(), m_wait_state, clock_id, abs_timeout);
  132. }
  133. #endif // !defined(BOOST_WINDOWS)
  134. bool wait_for(std::chrono::nanoseconds rel_timeout) noexcept
  135. {
  136. return lock_pool::wait_for(this->get_lock_state(), m_wait_state, rel_timeout);
  137. }
  138. };
  139. } // namespace lock_pool
  140. } // namespace detail
  141. } // namespace atomics
  142. } // namespace boost
  143. #include <boost/atomic/detail/footer.hpp>
  144. #endif // BOOST_ATOMIC_DETAIL_LOCK_POOL_HPP_INCLUDED_