| 57 | #endif // _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS |
| 58 | |
| 59 | void __shared_weak_count::__release_weak() noexcept { |
| 60 | // NOTE: The acquire load here is an optimization of the very |
| 61 | // common case where a shared pointer is being destructed while |
| 62 | // having no other contended references. |
| 63 | // |
| 64 | // BENEFIT: We avoid expensive atomic stores like XADD and STREX |
| 65 | // in a common case. Those instructions are slow and do nasty |
| 66 | // things to caches. |
| 67 | // |
| 68 | // IS THIS SAFE? Yes. During weak destruction, if we see that we |
| 69 | // are the last reference, we know that no-one else is accessing |
| 70 | // us. If someone were accessing us, then they would be doing so |
| 71 | // while the last shared / weak_ptr was being destructed, and |
| 72 | // that's undefined anyway. |
| 73 | // |
| 74 | // If we see anything other than a 0, then we have possible |
| 75 | // contention, and need to use an atomicrmw primitive. |
| 76 | // The same arguments don't apply for increment, where it is legal |
| 77 | // (though inadvisable) to share shared_ptr references between |
| 78 | // threads, and have them all get copied at once. The argument |
| 79 | // also doesn't apply for __release_shared, because an outstanding |
| 80 | // weak_ptr::lock() could read / modify the shared count. |
| 81 | if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0) { |
| 82 | // no need to do this store, because we are about |
| 83 | // to destroy everything. |
| 84 | //__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release); |
| 85 | __on_zero_shared_weak(); |
| 86 | } else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1) |
| 87 | __on_zero_shared_weak(); |
| 88 | } |
| 89 | |
| 90 | __shared_weak_count* __shared_weak_count::lock() noexcept { |
| 91 | long object_owners = __libcpp_atomic_load(&__shared_owners_); |
no test coverage detected