1 //===------------------------ memory.cpp ----------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "memory" 10 #ifndef _LIBCPP_HAS_NO_THREADS 11 #include "mutex" 12 #include "thread" 13 #endif 14 #include "include/atomic_support.h" 15 16 _LIBCPP_BEGIN_NAMESPACE_STD 17 18 const allocator_arg_t allocator_arg = allocator_arg_t(); 19 20 bad_weak_ptr::~bad_weak_ptr() _NOEXCEPT {} 21 22 const char* 23 bad_weak_ptr::what() const _NOEXCEPT 24 { 25 return "bad_weak_ptr"; 26 } 27 28 __shared_count::~__shared_count() 29 { 30 } 31 32 __shared_weak_count::~__shared_weak_count() 33 { 34 } 35 36 #if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS) 37 void 38 __shared_count::__add_shared() _NOEXCEPT 39 { 40 __libcpp_atomic_refcount_increment(__shared_owners_); 41 } 42 43 bool 44 __shared_count::__release_shared() _NOEXCEPT 45 { 46 if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1) 47 { 48 __on_zero_shared(); 49 return true; 50 } 51 return false; 52 } 53 54 void 55 __shared_weak_count::__add_shared() _NOEXCEPT 56 { 57 __shared_count::__add_shared(); 58 } 59 60 void 61 __shared_weak_count::__add_weak() _NOEXCEPT 62 { 63 __libcpp_atomic_refcount_increment(__shared_weak_owners_); 64 } 65 66 void 67 __shared_weak_count::__release_shared() _NOEXCEPT 68 { 69 if (__shared_count::__release_shared()) 70 __release_weak(); 71 } 72 73 #endif // _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS 74 75 void 76 __shared_weak_count::__release_weak() _NOEXCEPT 77 { 78 // NOTE: The acquire load here is an optimization of the very 79 // common case where a shared pointer is being destructed while 80 // having no other contended references. 81 // 82 // BENEFIT: We avoid expensive atomic stores like XADD and STREX 83 // in a common case. Those instructions are slow and do nasty 84 // things to caches. 85 // 86 // IS THIS SAFE? Yes. During weak destruction, if we see that we 87 // are the last reference, we know that no-one else is accessing 88 // us. If someone were accessing us, then they would be doing so 89 // while the last shared / weak_ptr was being destructed, and 90 // that's undefined anyway. 91 // 92 // If we see anything other than a 0, then we have possible 93 // contention, and need to use an atomicrmw primitive. 94 // The same arguments don't apply for increment, where it is legal 95 // (though inadvisable) to share shared_ptr references between 96 // threads, and have them all get copied at once. The argument 97 // also doesn't apply for __release_shared, because an outstanding 98 // weak_ptr::lock() could read / modify the shared count. 99 if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0) 100 { 101 // no need to do this store, because we are about 102 // to destroy everything. 103 //__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release); 104 __on_zero_shared_weak(); 105 } 106 else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1) 107 __on_zero_shared_weak(); 108 } 109 110 __shared_weak_count* 111 __shared_weak_count::lock() _NOEXCEPT 112 { 113 long object_owners = __libcpp_atomic_load(&__shared_owners_); 114 while (object_owners != -1) 115 { 116 if (__libcpp_atomic_compare_exchange(&__shared_owners_, 117 &object_owners, 118 object_owners+1)) 119 return this; 120 } 121 return nullptr; 122 } 123 124 #if !defined(_LIBCPP_NO_RTTI) || !defined(_LIBCPP_BUILD_STATIC) 125 126 const void* 127 __shared_weak_count::__get_deleter(const type_info&) const _NOEXCEPT 128 { 129 return nullptr; 130 } 131 132 #endif // _LIBCPP_NO_RTTI 133 134 #if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) 135 136 _LIBCPP_SAFE_STATIC static const std::size_t __sp_mut_count = 16; 137 _LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut_back[__sp_mut_count] = 138 { 139 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, 140 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, 141 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, 142 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER 143 }; 144 145 _LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) _NOEXCEPT 146 : __lx(p) 147 { 148 } 149 150 void 151 __sp_mut::lock() _NOEXCEPT 152 { 153 auto m = static_cast<__libcpp_mutex_t*>(__lx); 154 unsigned count = 0; 155 while (!__libcpp_mutex_trylock(m)) 156 { 157 if (++count > 16) 158 { 159 __libcpp_mutex_lock(m); 160 break; 161 } 162 this_thread::yield(); 163 } 164 } 165 166 void 167 __sp_mut::unlock() _NOEXCEPT 168 { 169 __libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx)); 170 } 171 172 __sp_mut& 173 __get_sp_mut(const void* p) 174 { 175 static __sp_mut muts[__sp_mut_count] 176 { 177 &mut_back[ 0], &mut_back[ 1], &mut_back[ 2], &mut_back[ 3], 178 &mut_back[ 4], &mut_back[ 5], &mut_back[ 6], &mut_back[ 7], 179 &mut_back[ 8], &mut_back[ 9], &mut_back[10], &mut_back[11], 180 &mut_back[12], &mut_back[13], &mut_back[14], &mut_back[15] 181 }; 182 return muts[hash<const void*>()(p) & (__sp_mut_count-1)]; 183 } 184 185 #endif // !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) 186 187 void 188 declare_reachable(void*) 189 { 190 } 191 192 void 193 declare_no_pointers(char*, size_t) 194 { 195 } 196 197 void 198 undeclare_no_pointers(char*, size_t) 199 { 200 } 201 202 #if !defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE) 203 pointer_safety get_pointer_safety() _NOEXCEPT 204 { 205 return pointer_safety::relaxed; 206 } 207 #endif 208 209 void* 210 __undeclare_reachable(void* p) 211 { 212 return p; 213 } 214 215 void* 216 align(size_t alignment, size_t size, void*& ptr, size_t& space) 217 { 218 void* r = nullptr; 219 if (size <= space) 220 { 221 char* p1 = static_cast<char*>(ptr); 222 char* p2 = reinterpret_cast<char*>(reinterpret_cast<size_t>(p1 + (alignment - 1)) & -alignment); 223 size_t d = static_cast<size_t>(p2 - p1); 224 if (d <= space - size) 225 { 226 r = p2; 227 ptr = r; 228 space -= d; 229 } 230 } 231 return r; 232 } 233 234 _LIBCPP_END_NAMESPACE_STD 235