capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

refcount.c++ (3461B)


      1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #include "refcount.h"
     23 #include "debug.h"
     24 
     25 #if _MSC_VER && !defined(__clang__)
     26 // Annoyingly, MSVC only implements the C++ atomic libs, not the C libs, so the only useful
     27 // thing we can get from <atomic> seems to be atomic_thread_fence... but that one function is
     28 // indeed not implemented by the intrinsics, so...
     29 #include <atomic>
     30 #endif
     31 
     32 namespace kj {
     33 
     34 // =======================================================================================
     35 // Non-atomic (thread-unsafe) refcounting
     36 
     37 Refcounted::~Refcounted() noexcept(false) {
     38   KJ_ASSERT(refcount == 0, "Refcounted object deleted with non-zero refcount.");
     39 }
     40 
     41 void Refcounted::disposeImpl(void* pointer) const {
     42   if (--refcount == 0) {
     43     delete this;
     44   }
     45 }
     46 
     47 // =======================================================================================
     48 // Atomic (thread-safe) refcounting
     49 
     50 AtomicRefcounted::~AtomicRefcounted() noexcept(false) {
     51   KJ_ASSERT(refcount == 0, "Refcounted object deleted with non-zero refcount.");
     52 }
     53 
     54 void AtomicRefcounted::disposeImpl(void* pointer) const {
     55 #if _MSC_VER && !defined(__clang__)
     56   if (KJ_MSVC_INTERLOCKED(Decrement, rel)(&refcount) == 0) {
     57     std::atomic_thread_fence(std::memory_order_acquire);
     58     delete this;
     59   }
     60 #else
     61   if (__atomic_sub_fetch(&refcount, 1, __ATOMIC_RELEASE) == 0) {
     62     __atomic_thread_fence(__ATOMIC_ACQUIRE);
     63     delete this;
     64   }
     65 #endif
     66 }
     67 
     68 bool AtomicRefcounted::addRefWeakInternal() const {
     69 #if _MSC_VER && !defined(__clang__)
     70   long orig = refcount;
     71 
     72   for (;;) {
     73     if (orig == 0) {
     74       // Refcount already hit zero. Destructor is already running so we can't revive the object.
     75       return false;
     76     }
     77 
     78     unsigned long old = KJ_MSVC_INTERLOCKED(CompareExchange, nf)(&refcount, orig + 1, orig);
     79     if (old == orig) {
     80       return true;
     81     }
     82     orig = old;
     83   }
     84 #else
     85   uint orig = __atomic_load_n(&refcount, __ATOMIC_RELAXED);
     86 
     87   for (;;) {
     88     if (orig == 0) {
     89       // Refcount already hit zero. Destructor is already running so we can't revive the object.
     90       return false;
     91     }
     92 
     93     if (__atomic_compare_exchange_n(&refcount, &orig, orig + 1, true,
     94         __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
     95       // Successfully incremented refcount without letting it hit zero.
     96       return true;
     97     }
     98   }
     99 #endif
    100 }
    101 
    102 }  // namespace kj