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