xref: /openbsd-src/gnu/llvm/libcxx/src/memory.cpp (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
1*4bdff4beSrobert //===----------------------------------------------------------------------===//
246035553Spatrick //
346035553Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
446035553Spatrick // See https://llvm.org/LICENSE.txt for license information.
546035553Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
646035553Spatrick //
746035553Spatrick //===----------------------------------------------------------------------===//
846035553Spatrick 
9*4bdff4beSrobert #include <__config>
10*4bdff4beSrobert #ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
11*4bdff4beSrobert #   define _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS
12*4bdff4beSrobert #endif
13*4bdff4beSrobert 
14*4bdff4beSrobert #include <memory>
15*4bdff4beSrobert 
1646035553Spatrick #ifndef _LIBCPP_HAS_NO_THREADS
17*4bdff4beSrobert #  include <mutex>
18*4bdff4beSrobert #  include <thread>
1946035553Spatrick #  if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
2046035553Spatrick #    pragma comment(lib, "pthread")
2146035553Spatrick #  endif
2246035553Spatrick #endif
23*4bdff4beSrobert 
2446035553Spatrick #include "include/atomic_support.h"
2546035553Spatrick 
2646035553Spatrick _LIBCPP_BEGIN_NAMESPACE_STD
2746035553Spatrick 
2846035553Spatrick const allocator_arg_t allocator_arg = allocator_arg_t();
2946035553Spatrick 
~bad_weak_ptr()3076d0caaeSpatrick bad_weak_ptr::~bad_weak_ptr() noexcept {}
3146035553Spatrick 
3246035553Spatrick const char*
what() const3376d0caaeSpatrick bad_weak_ptr::what() const noexcept
3446035553Spatrick {
3546035553Spatrick     return "bad_weak_ptr";
3646035553Spatrick }
3746035553Spatrick 
~__shared_count()3846035553Spatrick __shared_count::~__shared_count()
3946035553Spatrick {
4046035553Spatrick }
4146035553Spatrick 
~__shared_weak_count()4246035553Spatrick __shared_weak_count::~__shared_weak_count()
4346035553Spatrick {
4446035553Spatrick }
4546035553Spatrick 
46*4bdff4beSrobert #if defined(_LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS)
4746035553Spatrick void
__add_shared()4876d0caaeSpatrick __shared_count::__add_shared() noexcept
4946035553Spatrick {
5046035553Spatrick     __libcpp_atomic_refcount_increment(__shared_owners_);
5146035553Spatrick }
5246035553Spatrick 
5346035553Spatrick bool
__release_shared()5476d0caaeSpatrick __shared_count::__release_shared() noexcept
5546035553Spatrick {
5646035553Spatrick     if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1)
5746035553Spatrick     {
5846035553Spatrick         __on_zero_shared();
5946035553Spatrick         return true;
6046035553Spatrick     }
6146035553Spatrick     return false;
6246035553Spatrick }
6346035553Spatrick 
6446035553Spatrick void
__add_shared()6576d0caaeSpatrick __shared_weak_count::__add_shared() noexcept
6646035553Spatrick {
6746035553Spatrick     __shared_count::__add_shared();
6846035553Spatrick }
6946035553Spatrick 
7046035553Spatrick void
__add_weak()7176d0caaeSpatrick __shared_weak_count::__add_weak() noexcept
7246035553Spatrick {
7346035553Spatrick     __libcpp_atomic_refcount_increment(__shared_weak_owners_);
7446035553Spatrick }
7546035553Spatrick 
7646035553Spatrick void
__release_shared()7776d0caaeSpatrick __shared_weak_count::__release_shared() noexcept
7846035553Spatrick {
7946035553Spatrick     if (__shared_count::__release_shared())
8046035553Spatrick         __release_weak();
8146035553Spatrick }
82*4bdff4beSrobert #endif // _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS
8346035553Spatrick 
8446035553Spatrick void
__release_weak()8576d0caaeSpatrick __shared_weak_count::__release_weak() noexcept
8646035553Spatrick {
8746035553Spatrick     // NOTE: The acquire load here is an optimization of the very
8846035553Spatrick     // common case where a shared pointer is being destructed while
8946035553Spatrick     // having no other contended references.
9046035553Spatrick     //
9146035553Spatrick     // BENEFIT: We avoid expensive atomic stores like XADD and STREX
9246035553Spatrick     // in a common case.  Those instructions are slow and do nasty
9346035553Spatrick     // things to caches.
9446035553Spatrick     //
9546035553Spatrick     // IS THIS SAFE?  Yes.  During weak destruction, if we see that we
9646035553Spatrick     // are the last reference, we know that no-one else is accessing
9746035553Spatrick     // us. If someone were accessing us, then they would be doing so
9846035553Spatrick     // while the last shared / weak_ptr was being destructed, and
9946035553Spatrick     // that's undefined anyway.
10046035553Spatrick     //
10146035553Spatrick     // If we see anything other than a 0, then we have possible
10246035553Spatrick     // contention, and need to use an atomicrmw primitive.
10346035553Spatrick     // The same arguments don't apply for increment, where it is legal
10446035553Spatrick     // (though inadvisable) to share shared_ptr references between
10546035553Spatrick     // threads, and have them all get copied at once.  The argument
10646035553Spatrick     // also doesn't apply for __release_shared, because an outstanding
10746035553Spatrick     // weak_ptr::lock() could read / modify the shared count.
10846035553Spatrick     if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0)
10946035553Spatrick     {
11046035553Spatrick         // no need to do this store, because we are about
11146035553Spatrick         // to destroy everything.
11246035553Spatrick         //__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release);
11346035553Spatrick         __on_zero_shared_weak();
11446035553Spatrick     }
11546035553Spatrick     else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1)
11646035553Spatrick         __on_zero_shared_weak();
11746035553Spatrick }
11846035553Spatrick 
11946035553Spatrick __shared_weak_count*
lock()12076d0caaeSpatrick __shared_weak_count::lock() noexcept
12146035553Spatrick {
12246035553Spatrick     long object_owners = __libcpp_atomic_load(&__shared_owners_);
12346035553Spatrick     while (object_owners != -1)
12446035553Spatrick     {
12546035553Spatrick         if (__libcpp_atomic_compare_exchange(&__shared_owners_,
12646035553Spatrick                                              &object_owners,
12746035553Spatrick                                              object_owners+1))
12846035553Spatrick             return this;
12946035553Spatrick     }
13046035553Spatrick     return nullptr;
13146035553Spatrick }
13246035553Spatrick 
13346035553Spatrick const void*
__get_deleter(const type_info &) const13476d0caaeSpatrick __shared_weak_count::__get_deleter(const type_info&) const noexcept
13546035553Spatrick {
13646035553Spatrick     return nullptr;
13746035553Spatrick }
13846035553Spatrick 
139*4bdff4beSrobert #if !defined(_LIBCPP_HAS_NO_THREADS)
14046035553Spatrick 
141*4bdff4beSrobert static constexpr std::size_t __sp_mut_count = 32;
142*4bdff4beSrobert static constinit __libcpp_mutex_t mut_back[__sp_mut_count] =
14346035553Spatrick {
14446035553Spatrick     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
14546035553Spatrick     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
14646035553Spatrick     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
147*4bdff4beSrobert     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
148*4bdff4beSrobert     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
149*4bdff4beSrobert     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
150*4bdff4beSrobert     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
15146035553Spatrick     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER
15246035553Spatrick };
15346035553Spatrick 
__sp_mut(void * p)15476d0caaeSpatrick _LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) noexcept
155*4bdff4beSrobert    : __lx_(p)
15646035553Spatrick {
15746035553Spatrick }
15846035553Spatrick 
15946035553Spatrick void
lock()16076d0caaeSpatrick __sp_mut::lock() noexcept
16146035553Spatrick {
162*4bdff4beSrobert     auto m = static_cast<__libcpp_mutex_t*>(__lx_);
16346035553Spatrick     __libcpp_mutex_lock(m);
16446035553Spatrick }
16546035553Spatrick 
16646035553Spatrick void
unlock()16776d0caaeSpatrick __sp_mut::unlock() noexcept
16846035553Spatrick {
169*4bdff4beSrobert     __libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx_));
17046035553Spatrick }
17146035553Spatrick 
17246035553Spatrick __sp_mut&
__get_sp_mut(const void * p)17346035553Spatrick __get_sp_mut(const void* p)
17446035553Spatrick {
175*4bdff4beSrobert     static constinit __sp_mut muts[__sp_mut_count] = {
17646035553Spatrick         &mut_back[ 0], &mut_back[ 1], &mut_back[ 2], &mut_back[ 3],
17746035553Spatrick         &mut_back[ 4], &mut_back[ 5], &mut_back[ 6], &mut_back[ 7],
17846035553Spatrick         &mut_back[ 8], &mut_back[ 9], &mut_back[10], &mut_back[11],
179*4bdff4beSrobert         &mut_back[12], &mut_back[13], &mut_back[14], &mut_back[15],
180*4bdff4beSrobert         &mut_back[16], &mut_back[17], &mut_back[18], &mut_back[19],
181*4bdff4beSrobert         &mut_back[20], &mut_back[21], &mut_back[22], &mut_back[23],
182*4bdff4beSrobert         &mut_back[24], &mut_back[25], &mut_back[26], &mut_back[27],
183*4bdff4beSrobert         &mut_back[28], &mut_back[29], &mut_back[30], &mut_back[31]
18446035553Spatrick     };
18546035553Spatrick     return muts[hash<const void*>()(p) & (__sp_mut_count-1)];
18646035553Spatrick }
18746035553Spatrick 
188*4bdff4beSrobert #endif // !defined(_LIBCPP_HAS_NO_THREADS)
18946035553Spatrick 
19046035553Spatrick void*
align(size_t alignment,size_t size,void * & ptr,size_t & space)19146035553Spatrick align(size_t alignment, size_t size, void*& ptr, size_t& space)
19246035553Spatrick {
19346035553Spatrick     void* r = nullptr;
19446035553Spatrick     if (size <= space)
19546035553Spatrick     {
19646035553Spatrick         char* p1 = static_cast<char*>(ptr);
197*4bdff4beSrobert         char* p2 = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(p1 + (alignment - 1)) & -alignment);
19846035553Spatrick         size_t d = static_cast<size_t>(p2 - p1);
19946035553Spatrick         if (d <= space - size)
20046035553Spatrick         {
20146035553Spatrick             r = p2;
20246035553Spatrick             ptr = r;
20346035553Spatrick             space -= d;
20446035553Spatrick         }
20546035553Spatrick     }
20646035553Spatrick     return r;
20746035553Spatrick }
20846035553Spatrick 
20946035553Spatrick _LIBCPP_END_NAMESPACE_STD
210