xref: /freebsd/contrib/llvm-project/libcxx/src/memory.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
1349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
981ad6265SDimitry Andric #include <__config>
1081ad6265SDimitry Andric #ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
1181ad6265SDimitry Andric #  define _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS
1281ad6265SDimitry Andric #endif
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include <memory>
1581ad6265SDimitry Andric 
160b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
1781ad6265SDimitry Andric #  include <mutex>
1881ad6265SDimitry Andric #  include <thread>
19480093f4SDimitry Andric #  if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
200b57cec5SDimitry Andric #    pragma comment(lib, "pthread")
210b57cec5SDimitry Andric #  endif
220b57cec5SDimitry Andric #endif
2381ad6265SDimitry Andric 
240b57cec5SDimitry Andric #include "include/atomic_support.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
270b57cec5SDimitry Andric 
28fe6060f1SDimitry Andric bad_weak_ptr::~bad_weak_ptr() noexcept {}
290b57cec5SDimitry Andric 
30*cb14a3feSDimitry Andric const char* bad_weak_ptr::what() const noexcept { return "bad_weak_ptr"; }
310b57cec5SDimitry Andric 
32*cb14a3feSDimitry Andric __shared_count::~__shared_count() {}
330b57cec5SDimitry Andric 
34*cb14a3feSDimitry Andric __shared_weak_count::~__shared_weak_count() {}
350b57cec5SDimitry Andric 
3681ad6265SDimitry Andric #if defined(_LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS)
37*cb14a3feSDimitry Andric void __shared_count::__add_shared() noexcept { __libcpp_atomic_refcount_increment(__shared_owners_); }
380b57cec5SDimitry Andric 
39*cb14a3feSDimitry Andric bool __shared_count::__release_shared() noexcept {
40*cb14a3feSDimitry Andric   if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1) {
410b57cec5SDimitry Andric     __on_zero_shared();
420b57cec5SDimitry Andric     return true;
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric   return false;
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
47*cb14a3feSDimitry Andric void __shared_weak_count::__add_shared() noexcept { __shared_count::__add_shared(); }
480b57cec5SDimitry Andric 
49*cb14a3feSDimitry Andric void __shared_weak_count::__add_weak() noexcept { __libcpp_atomic_refcount_increment(__shared_weak_owners_); }
500b57cec5SDimitry Andric 
51*cb14a3feSDimitry Andric void __shared_weak_count::__release_shared() noexcept {
520b57cec5SDimitry Andric   if (__shared_count::__release_shared())
530b57cec5SDimitry Andric     __release_weak();
540b57cec5SDimitry Andric }
5581ad6265SDimitry Andric #endif // _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS
560b57cec5SDimitry Andric 
57*cb14a3feSDimitry Andric void __shared_weak_count::__release_weak() noexcept {
580b57cec5SDimitry Andric   // NOTE: The acquire load here is an optimization of the very
590b57cec5SDimitry Andric   // common case where a shared pointer is being destructed while
600b57cec5SDimitry Andric   // having no other contended references.
610b57cec5SDimitry Andric   //
620b57cec5SDimitry Andric   // BENEFIT: We avoid expensive atomic stores like XADD and STREX
630b57cec5SDimitry Andric   // in a common case.  Those instructions are slow and do nasty
640b57cec5SDimitry Andric   // things to caches.
650b57cec5SDimitry Andric   //
660b57cec5SDimitry Andric   // IS THIS SAFE?  Yes.  During weak destruction, if we see that we
670b57cec5SDimitry Andric   // are the last reference, we know that no-one else is accessing
680b57cec5SDimitry Andric   // us. If someone were accessing us, then they would be doing so
690b57cec5SDimitry Andric   // while the last shared / weak_ptr was being destructed, and
700b57cec5SDimitry Andric   // that's undefined anyway.
710b57cec5SDimitry Andric   //
720b57cec5SDimitry Andric   // If we see anything other than a 0, then we have possible
730b57cec5SDimitry Andric   // contention, and need to use an atomicrmw primitive.
740b57cec5SDimitry Andric   // The same arguments don't apply for increment, where it is legal
750b57cec5SDimitry Andric   // (though inadvisable) to share shared_ptr references between
760b57cec5SDimitry Andric   // threads, and have them all get copied at once.  The argument
770b57cec5SDimitry Andric   // also doesn't apply for __release_shared, because an outstanding
780b57cec5SDimitry Andric   // weak_ptr::lock() could read / modify the shared count.
79*cb14a3feSDimitry Andric   if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0) {
800b57cec5SDimitry Andric     // no need to do this store, because we are about
810b57cec5SDimitry Andric     // to destroy everything.
820b57cec5SDimitry Andric     //__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release);
830b57cec5SDimitry Andric     __on_zero_shared_weak();
84*cb14a3feSDimitry Andric   } else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1)
850b57cec5SDimitry Andric     __on_zero_shared_weak();
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
88*cb14a3feSDimitry Andric __shared_weak_count* __shared_weak_count::lock() noexcept {
890b57cec5SDimitry Andric   long object_owners = __libcpp_atomic_load(&__shared_owners_);
90*cb14a3feSDimitry Andric   while (object_owners != -1) {
91*cb14a3feSDimitry Andric     if (__libcpp_atomic_compare_exchange(&__shared_owners_, &object_owners, object_owners + 1))
920b57cec5SDimitry Andric       return this;
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric   return nullptr;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
97*cb14a3feSDimitry Andric const void* __shared_weak_count::__get_deleter(const type_info&) const noexcept { return nullptr; }
980b57cec5SDimitry Andric 
99349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_THREADS)
1000b57cec5SDimitry Andric 
10181ad6265SDimitry Andric static constexpr std::size_t __sp_mut_count                = 32;
102*cb14a3feSDimitry Andric static constinit __libcpp_mutex_t mut_back[__sp_mut_count] = {
1030b57cec5SDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
1040b57cec5SDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
1050b57cec5SDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
10681ad6265SDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
10781ad6265SDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
10881ad6265SDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
10981ad6265SDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
110*cb14a3feSDimitry Andric     _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER};
1110b57cec5SDimitry Andric 
112*cb14a3feSDimitry Andric constexpr __sp_mut::__sp_mut(void* p) noexcept : __lx_(p) {}
1130b57cec5SDimitry Andric 
114*cb14a3feSDimitry Andric void __sp_mut::lock() noexcept {
115bdd1243dSDimitry Andric   auto m = static_cast<__libcpp_mutex_t*>(__lx_);
1160b57cec5SDimitry Andric   __libcpp_mutex_lock(m);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
119*cb14a3feSDimitry Andric void __sp_mut::unlock() noexcept { __libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx_)); }
1200b57cec5SDimitry Andric 
121*cb14a3feSDimitry Andric __sp_mut& __get_sp_mut(const void* p) {
12281ad6265SDimitry Andric   static constinit __sp_mut muts[__sp_mut_count] = {
123*cb14a3feSDimitry Andric       &mut_back[0],  &mut_back[1],  &mut_back[2],  &mut_back[3],  &mut_back[4],  &mut_back[5],  &mut_back[6],
124*cb14a3feSDimitry Andric       &mut_back[7],  &mut_back[8],  &mut_back[9],  &mut_back[10], &mut_back[11], &mut_back[12], &mut_back[13],
125*cb14a3feSDimitry Andric       &mut_back[14], &mut_back[15], &mut_back[16], &mut_back[17], &mut_back[18], &mut_back[19], &mut_back[20],
126*cb14a3feSDimitry Andric       &mut_back[21], &mut_back[22], &mut_back[23], &mut_back[24], &mut_back[25], &mut_back[26], &mut_back[27],
127*cb14a3feSDimitry Andric       &mut_back[28], &mut_back[29], &mut_back[30], &mut_back[31]};
1280b57cec5SDimitry Andric   return muts[hash<const void*>()(p) & (__sp_mut_count - 1)];
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
131349cc55cSDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_THREADS)
1320b57cec5SDimitry Andric 
133*cb14a3feSDimitry Andric void* align(size_t alignment, size_t size, void*& ptr, size_t& space) {
1340b57cec5SDimitry Andric   void* r = nullptr;
135*cb14a3feSDimitry Andric   if (size <= space) {
1360b57cec5SDimitry Andric     char* p1 = static_cast<char*>(ptr);
137bdd1243dSDimitry Andric     char* p2 = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(p1 + (alignment - 1)) & -alignment);
1380b57cec5SDimitry Andric     size_t d = static_cast<size_t>(p2 - p1);
139*cb14a3feSDimitry Andric     if (d <= space - size) {
1400b57cec5SDimitry Andric       r   = p2;
1410b57cec5SDimitry Andric       ptr = r;
1420b57cec5SDimitry Andric       space -= d;
1430b57cec5SDimitry Andric     }
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric   return r;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
149