17a984708SDavid Chisnall //===------------------------ memory.cpp ----------------------------------===//
27a984708SDavid Chisnall //
37a984708SDavid Chisnall // The LLVM Compiler Infrastructure
47a984708SDavid Chisnall //
57a984708SDavid Chisnall // This file is dual licensed under the MIT and the University of Illinois Open
67a984708SDavid Chisnall // Source Licenses. See LICENSE.TXT for details.
77a984708SDavid Chisnall //
87a984708SDavid Chisnall //===----------------------------------------------------------------------===//
97a984708SDavid Chisnall
107a984708SDavid Chisnall #include "memory"
11d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
12936e9439SDimitry Andric #include "mutex"
13936e9439SDimitry Andric #include "thread"
14d72607e9SDimitry Andric #endif
159729cf09SDimitry Andric #include "include/atomic_support.h"
167a984708SDavid Chisnall
177a984708SDavid Chisnall _LIBCPP_BEGIN_NAMESPACE_STD
187a984708SDavid Chisnall
197a984708SDavid Chisnall const allocator_arg_t allocator_arg = allocator_arg_t();
207a984708SDavid Chisnall
~bad_weak_ptr()217a984708SDavid Chisnall bad_weak_ptr::~bad_weak_ptr() _NOEXCEPT {}
227a984708SDavid Chisnall
237a984708SDavid Chisnall const char*
what() const247a984708SDavid Chisnall bad_weak_ptr::what() const _NOEXCEPT
257a984708SDavid Chisnall {
267a984708SDavid Chisnall return "bad_weak_ptr";
277a984708SDavid Chisnall }
287a984708SDavid Chisnall
~__shared_count()297a984708SDavid Chisnall __shared_count::~__shared_count()
307a984708SDavid Chisnall {
317a984708SDavid Chisnall }
327a984708SDavid Chisnall
~__shared_weak_count()33540d2a8bSDimitry Andric __shared_weak_count::~__shared_weak_count()
34540d2a8bSDimitry Andric {
35540d2a8bSDimitry Andric }
36540d2a8bSDimitry Andric
37540d2a8bSDimitry Andric #if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
387a984708SDavid Chisnall void
__add_shared()397a984708SDavid Chisnall __shared_count::__add_shared() _NOEXCEPT
407a984708SDavid Chisnall {
41540d2a8bSDimitry Andric __libcpp_atomic_refcount_increment(__shared_owners_);
427a984708SDavid Chisnall }
437a984708SDavid Chisnall
447a984708SDavid Chisnall bool
__release_shared()457a984708SDavid Chisnall __shared_count::__release_shared() _NOEXCEPT
467a984708SDavid Chisnall {
47540d2a8bSDimitry Andric if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1)
487a984708SDavid Chisnall {
497a984708SDavid Chisnall __on_zero_shared();
507a984708SDavid Chisnall return true;
517a984708SDavid Chisnall }
527a984708SDavid Chisnall return false;
537a984708SDavid Chisnall }
547a984708SDavid Chisnall
557a984708SDavid Chisnall void
__add_shared()567a984708SDavid Chisnall __shared_weak_count::__add_shared() _NOEXCEPT
577a984708SDavid Chisnall {
587a984708SDavid Chisnall __shared_count::__add_shared();
597a984708SDavid Chisnall }
607a984708SDavid Chisnall
617a984708SDavid Chisnall void
__add_weak()627a984708SDavid Chisnall __shared_weak_count::__add_weak() _NOEXCEPT
637a984708SDavid Chisnall {
64540d2a8bSDimitry Andric __libcpp_atomic_refcount_increment(__shared_weak_owners_);
657a984708SDavid Chisnall }
667a984708SDavid Chisnall
677a984708SDavid Chisnall void
__release_shared()687a984708SDavid Chisnall __shared_weak_count::__release_shared() _NOEXCEPT
697a984708SDavid Chisnall {
707a984708SDavid Chisnall if (__shared_count::__release_shared())
717a984708SDavid Chisnall __release_weak();
727a984708SDavid Chisnall }
737a984708SDavid Chisnall
74540d2a8bSDimitry Andric #endif // _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
75540d2a8bSDimitry Andric
767a984708SDavid Chisnall void
__release_weak()777a984708SDavid Chisnall __shared_weak_count::__release_weak() _NOEXCEPT
787a984708SDavid Chisnall {
79aed8d94eSDimitry Andric // NOTE: The acquire load here is an optimization of the very
80aed8d94eSDimitry Andric // common case where a shared pointer is being destructed while
81aed8d94eSDimitry Andric // having no other contended references.
82aed8d94eSDimitry Andric //
83aed8d94eSDimitry Andric // BENEFIT: We avoid expensive atomic stores like XADD and STREX
84aed8d94eSDimitry Andric // in a common case. Those instructions are slow and do nasty
85aed8d94eSDimitry Andric // things to caches.
86aed8d94eSDimitry Andric //
87aed8d94eSDimitry Andric // IS THIS SAFE? Yes. During weak destruction, if we see that we
88aed8d94eSDimitry Andric // are the last reference, we know that no-one else is accessing
89aed8d94eSDimitry Andric // us. If someone were accessing us, then they would be doing so
90aed8d94eSDimitry Andric // while the last shared / weak_ptr was being destructed, and
91aed8d94eSDimitry Andric // that's undefined anyway.
92aed8d94eSDimitry Andric //
93aed8d94eSDimitry Andric // If we see anything other than a 0, then we have possible
94aed8d94eSDimitry Andric // contention, and need to use an atomicrmw primitive.
95aed8d94eSDimitry Andric // The same arguments don't apply for increment, where it is legal
96aed8d94eSDimitry Andric // (though inadvisable) to share shared_ptr references between
97aed8d94eSDimitry Andric // threads, and have them all get copied at once. The argument
98aed8d94eSDimitry Andric // also doesn't apply for __release_shared, because an outstanding
99aed8d94eSDimitry Andric // weak_ptr::lock() could read / modify the shared count.
100aed8d94eSDimitry Andric if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0)
101aed8d94eSDimitry Andric {
102aed8d94eSDimitry Andric // no need to do this store, because we are about
103aed8d94eSDimitry Andric // to destroy everything.
104aed8d94eSDimitry Andric //__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release);
105aed8d94eSDimitry Andric __on_zero_shared_weak();
106aed8d94eSDimitry Andric }
107540d2a8bSDimitry Andric else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1)
1087a984708SDavid Chisnall __on_zero_shared_weak();
1097a984708SDavid Chisnall }
1107a984708SDavid Chisnall
1117a984708SDavid Chisnall __shared_weak_count*
lock()1127a984708SDavid Chisnall __shared_weak_count::lock() _NOEXCEPT
1137a984708SDavid Chisnall {
114854fa44bSDimitry Andric long object_owners = __libcpp_atomic_load(&__shared_owners_);
1157a984708SDavid Chisnall while (object_owners != -1)
1167a984708SDavid Chisnall {
117854fa44bSDimitry Andric if (__libcpp_atomic_compare_exchange(&__shared_owners_,
118854fa44bSDimitry Andric &object_owners,
1197a984708SDavid Chisnall object_owners+1))
1207a984708SDavid Chisnall return this;
1217a984708SDavid Chisnall }
1220f5676f4SDimitry Andric return nullptr;
1237a984708SDavid Chisnall }
1247a984708SDavid Chisnall
125d72607e9SDimitry Andric #if !defined(_LIBCPP_NO_RTTI) || !defined(_LIBCPP_BUILD_STATIC)
1267a984708SDavid Chisnall
1277a984708SDavid Chisnall const void*
__get_deleter(const type_info &) const1287a984708SDavid Chisnall __shared_weak_count::__get_deleter(const type_info&) const _NOEXCEPT
1297a984708SDavid Chisnall {
1300f5676f4SDimitry Andric return nullptr;
1317a984708SDavid Chisnall }
1327a984708SDavid Chisnall
1337a984708SDavid Chisnall #endif // _LIBCPP_NO_RTTI
1347a984708SDavid Chisnall
1357c82a1ecSDimitry Andric #if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
136936e9439SDimitry Andric
137aed8d94eSDimitry Andric _LIBCPP_SAFE_STATIC static const std::size_t __sp_mut_count = 16;
138aed8d94eSDimitry Andric _LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut_back[__sp_mut_count] =
1391bf9f7c1SDimitry Andric {
1407c82a1ecSDimitry Andric _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
1417c82a1ecSDimitry Andric _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
1427c82a1ecSDimitry Andric _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
1437c82a1ecSDimitry Andric _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER
1441bf9f7c1SDimitry Andric };
1451bf9f7c1SDimitry Andric
__sp_mut(void * p)146936e9439SDimitry Andric _LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) _NOEXCEPT
1471e0896acSDavid Chisnall : __lx(p)
148936e9439SDimitry Andric {
149936e9439SDimitry Andric }
150936e9439SDimitry Andric
151936e9439SDimitry Andric void
lock()152936e9439SDimitry Andric __sp_mut::lock() _NOEXCEPT
153936e9439SDimitry Andric {
154aed8d94eSDimitry Andric auto m = static_cast<__libcpp_mutex_t*>(__lx);
155936e9439SDimitry Andric unsigned count = 0;
1560f5676f4SDimitry Andric while (!__libcpp_mutex_trylock(m))
157936e9439SDimitry Andric {
158936e9439SDimitry Andric if (++count > 16)
159936e9439SDimitry Andric {
160aed8d94eSDimitry Andric __libcpp_mutex_lock(m);
161936e9439SDimitry Andric break;
162936e9439SDimitry Andric }
163936e9439SDimitry Andric this_thread::yield();
164936e9439SDimitry Andric }
165936e9439SDimitry Andric }
166936e9439SDimitry Andric
167936e9439SDimitry Andric void
unlock()168936e9439SDimitry Andric __sp_mut::unlock() _NOEXCEPT
169936e9439SDimitry Andric {
170aed8d94eSDimitry Andric __libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx));
171936e9439SDimitry Andric }
172936e9439SDimitry Andric
173936e9439SDimitry Andric __sp_mut&
__get_sp_mut(const void * p)174936e9439SDimitry Andric __get_sp_mut(const void* p)
175936e9439SDimitry Andric {
176936e9439SDimitry Andric static __sp_mut muts[__sp_mut_count]
177936e9439SDimitry Andric {
178936e9439SDimitry Andric &mut_back[ 0], &mut_back[ 1], &mut_back[ 2], &mut_back[ 3],
179936e9439SDimitry Andric &mut_back[ 4], &mut_back[ 5], &mut_back[ 6], &mut_back[ 7],
180936e9439SDimitry Andric &mut_back[ 8], &mut_back[ 9], &mut_back[10], &mut_back[11],
181936e9439SDimitry Andric &mut_back[12], &mut_back[13], &mut_back[14], &mut_back[15]
182936e9439SDimitry Andric };
183936e9439SDimitry Andric return muts[hash<const void*>()(p) & (__sp_mut_count-1)];
184936e9439SDimitry Andric }
185936e9439SDimitry Andric
1867c82a1ecSDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
187936e9439SDimitry Andric
1887a984708SDavid Chisnall void
declare_reachable(void *)1897a984708SDavid Chisnall declare_reachable(void*)
1907a984708SDavid Chisnall {
1917a984708SDavid Chisnall }
1927a984708SDavid Chisnall
1937a984708SDavid Chisnall void
declare_no_pointers(char *,size_t)1947a984708SDavid Chisnall declare_no_pointers(char*, size_t)
1957a984708SDavid Chisnall {
1967a984708SDavid Chisnall }
1977a984708SDavid Chisnall
1987a984708SDavid Chisnall void
undeclare_no_pointers(char *,size_t)1997a984708SDavid Chisnall undeclare_no_pointers(char*, size_t)
2007a984708SDavid Chisnall {
2017a984708SDavid Chisnall }
2027a984708SDavid Chisnall
203aed8d94eSDimitry Andric #if !defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE)
get_pointer_safety()204aed8d94eSDimitry Andric pointer_safety get_pointer_safety() _NOEXCEPT
2057a984708SDavid Chisnall {
2067a984708SDavid Chisnall return pointer_safety::relaxed;
2077a984708SDavid Chisnall }
208aed8d94eSDimitry Andric #endif
2097a984708SDavid Chisnall
2107a984708SDavid Chisnall void*
__undeclare_reachable(void * p)2117a984708SDavid Chisnall __undeclare_reachable(void* p)
2127a984708SDavid Chisnall {
2137a984708SDavid Chisnall return p;
2147a984708SDavid Chisnall }
2157a984708SDavid Chisnall
2167a984708SDavid Chisnall void*
align(size_t alignment,size_t size,void * & ptr,size_t & space)2177a984708SDavid Chisnall align(size_t alignment, size_t size, void*& ptr, size_t& space)
2187a984708SDavid Chisnall {
2197a984708SDavid Chisnall void* r = nullptr;
2207a984708SDavid Chisnall if (size <= space)
2217a984708SDavid Chisnall {
2227a984708SDavid Chisnall char* p1 = static_cast<char*>(ptr);
223d72607e9SDimitry Andric char* p2 = reinterpret_cast<char*>(reinterpret_cast<size_t>(p1 + (alignment - 1)) & -alignment);
22494e3ee44SDavid Chisnall size_t d = static_cast<size_t>(p2 - p1);
2257a984708SDavid Chisnall if (d <= space - size)
2267a984708SDavid Chisnall {
2277a984708SDavid Chisnall r = p2;
2287a984708SDavid Chisnall ptr = r;
2297a984708SDavid Chisnall space -= d;
2307a984708SDavid Chisnall }
2317a984708SDavid Chisnall }
2327a984708SDavid Chisnall return r;
2337a984708SDavid Chisnall }
2347a984708SDavid Chisnall
2357a984708SDavid Chisnall _LIBCPP_END_NAMESPACE_STD
236