1*4882a593Smuzhiyun=================================== 2*4882a593Smuzhiyunrefcount_t API compared to atomic_t 3*4882a593Smuzhiyun=================================== 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun.. contents:: :local: 6*4882a593Smuzhiyun 7*4882a593SmuzhiyunIntroduction 8*4882a593Smuzhiyun============ 9*4882a593Smuzhiyun 10*4882a593SmuzhiyunThe goal of refcount_t API is to provide a minimal API for implementing 11*4882a593Smuzhiyunan object's reference counters. While a generic architecture-independent 12*4882a593Smuzhiyunimplementation from lib/refcount.c uses atomic operations underneath, 13*4882a593Smuzhiyunthere are a number of differences between some of the ``refcount_*()`` and 14*4882a593Smuzhiyun``atomic_*()`` functions with regards to the memory ordering guarantees. 15*4882a593SmuzhiyunThis document outlines the differences and provides respective examples 16*4882a593Smuzhiyunin order to help maintainers validate their code against the change in 17*4882a593Smuzhiyunthese memory ordering guarantees. 18*4882a593Smuzhiyun 19*4882a593SmuzhiyunThe terms used through this document try to follow the formal LKMM defined in 20*4882a593Smuzhiyuntools/memory-model/Documentation/explanation.txt. 21*4882a593Smuzhiyun 22*4882a593Smuzhiyunmemory-barriers.txt and atomic_t.txt provide more background to the 23*4882a593Smuzhiyunmemory ordering in general and for atomic operations specifically. 24*4882a593Smuzhiyun 25*4882a593SmuzhiyunRelevant types of memory ordering 26*4882a593Smuzhiyun================================= 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun.. note:: The following section only covers some of the memory 29*4882a593Smuzhiyun ordering types that are relevant for the atomics and reference 30*4882a593Smuzhiyun counters and used through this document. For a much broader picture 31*4882a593Smuzhiyun please consult memory-barriers.txt document. 32*4882a593Smuzhiyun 33*4882a593SmuzhiyunIn the absence of any memory ordering guarantees (i.e. fully unordered) 34*4882a593Smuzhiyunatomics & refcounters only provide atomicity and 35*4882a593Smuzhiyunprogram order (po) relation (on the same CPU). It guarantees that 36*4882a593Smuzhiyuneach ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions 37*4882a593Smuzhiyunare executed in program order on a single CPU. 38*4882a593SmuzhiyunThis is implemented using READ_ONCE()/WRITE_ONCE() and 39*4882a593Smuzhiyuncompare-and-swap primitives. 40*4882a593Smuzhiyun 41*4882a593SmuzhiyunA strong (full) memory ordering guarantees that all prior loads and 42*4882a593Smuzhiyunstores (all po-earlier instructions) on the same CPU are completed 43*4882a593Smuzhiyunbefore any po-later instruction is executed on the same CPU. 44*4882a593SmuzhiyunIt also guarantees that all po-earlier stores on the same CPU 45*4882a593Smuzhiyunand all propagated stores from other CPUs must propagate to all 46*4882a593Smuzhiyunother CPUs before any po-later instruction is executed on the original 47*4882a593SmuzhiyunCPU (A-cumulative property). This is implemented using smp_mb(). 48*4882a593Smuzhiyun 49*4882a593SmuzhiyunA RELEASE memory ordering guarantees that all prior loads and 50*4882a593Smuzhiyunstores (all po-earlier instructions) on the same CPU are completed 51*4882a593Smuzhiyunbefore the operation. It also guarantees that all po-earlier 52*4882a593Smuzhiyunstores on the same CPU and all propagated stores from other CPUs 53*4882a593Smuzhiyunmust propagate to all other CPUs before the release operation 54*4882a593Smuzhiyun(A-cumulative property). This is implemented using 55*4882a593Smuzhiyunsmp_store_release(). 56*4882a593Smuzhiyun 57*4882a593SmuzhiyunAn ACQUIRE memory ordering guarantees that all post loads and 58*4882a593Smuzhiyunstores (all po-later instructions) on the same CPU are 59*4882a593Smuzhiyuncompleted after the acquire operation. It also guarantees that all 60*4882a593Smuzhiyunpo-later stores on the same CPU must propagate to all other CPUs 61*4882a593Smuzhiyunafter the acquire operation executes. This is implemented using 62*4882a593Smuzhiyunsmp_acquire__after_ctrl_dep(). 63*4882a593Smuzhiyun 64*4882a593SmuzhiyunA control dependency (on success) for refcounters guarantees that 65*4882a593Smuzhiyunif a reference for an object was successfully obtained (reference 66*4882a593Smuzhiyuncounter increment or addition happened, function returned true), 67*4882a593Smuzhiyunthen further stores are ordered against this operation. 68*4882a593SmuzhiyunControl dependency on stores are not implemented using any explicit 69*4882a593Smuzhiyunbarriers, but rely on CPU not to speculate on stores. This is only 70*4882a593Smuzhiyuna single CPU relation and provides no guarantees for other CPUs. 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun 73*4882a593SmuzhiyunComparison of functions 74*4882a593Smuzhiyun======================= 75*4882a593Smuzhiyun 76*4882a593Smuzhiyuncase 1) - non-"Read/Modify/Write" (RMW) ops 77*4882a593Smuzhiyun------------------------------------------- 78*4882a593Smuzhiyun 79*4882a593SmuzhiyunFunction changes: 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun * atomic_set() --> refcount_set() 82*4882a593Smuzhiyun * atomic_read() --> refcount_read() 83*4882a593Smuzhiyun 84*4882a593SmuzhiyunMemory ordering guarantee changes: 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun * none (both fully unordered) 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun 89*4882a593Smuzhiyuncase 2) - increment-based ops that return no value 90*4882a593Smuzhiyun-------------------------------------------------- 91*4882a593Smuzhiyun 92*4882a593SmuzhiyunFunction changes: 93*4882a593Smuzhiyun 94*4882a593Smuzhiyun * atomic_inc() --> refcount_inc() 95*4882a593Smuzhiyun * atomic_add() --> refcount_add() 96*4882a593Smuzhiyun 97*4882a593SmuzhiyunMemory ordering guarantee changes: 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun * none (both fully unordered) 100*4882a593Smuzhiyun 101*4882a593Smuzhiyuncase 3) - decrement-based RMW ops that return no value 102*4882a593Smuzhiyun------------------------------------------------------ 103*4882a593Smuzhiyun 104*4882a593SmuzhiyunFunction changes: 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun * atomic_dec() --> refcount_dec() 107*4882a593Smuzhiyun 108*4882a593SmuzhiyunMemory ordering guarantee changes: 109*4882a593Smuzhiyun 110*4882a593Smuzhiyun * fully unordered --> RELEASE ordering 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun 113*4882a593Smuzhiyuncase 4) - increment-based RMW ops that return a value 114*4882a593Smuzhiyun----------------------------------------------------- 115*4882a593Smuzhiyun 116*4882a593SmuzhiyunFunction changes: 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun * atomic_inc_not_zero() --> refcount_inc_not_zero() 119*4882a593Smuzhiyun * no atomic counterpart --> refcount_add_not_zero() 120*4882a593Smuzhiyun 121*4882a593SmuzhiyunMemory ordering guarantees changes: 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun * fully ordered --> control dependency on success for stores 124*4882a593Smuzhiyun 125*4882a593Smuzhiyun.. note:: We really assume here that necessary ordering is provided as a 126*4882a593Smuzhiyun result of obtaining pointer to the object! 127*4882a593Smuzhiyun 128*4882a593Smuzhiyun 129*4882a593Smuzhiyuncase 5) - generic dec/sub decrement-based RMW ops that return a value 130*4882a593Smuzhiyun--------------------------------------------------------------------- 131*4882a593Smuzhiyun 132*4882a593SmuzhiyunFunction changes: 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun * atomic_dec_and_test() --> refcount_dec_and_test() 135*4882a593Smuzhiyun * atomic_sub_and_test() --> refcount_sub_and_test() 136*4882a593Smuzhiyun 137*4882a593SmuzhiyunMemory ordering guarantees changes: 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun * fully ordered --> RELEASE ordering + ACQUIRE ordering on success 140*4882a593Smuzhiyun 141*4882a593Smuzhiyun 142*4882a593Smuzhiyuncase 6) other decrement-based RMW ops that return a value 143*4882a593Smuzhiyun--------------------------------------------------------- 144*4882a593Smuzhiyun 145*4882a593SmuzhiyunFunction changes: 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun * no atomic counterpart --> refcount_dec_if_one() 148*4882a593Smuzhiyun * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)`` 149*4882a593Smuzhiyun 150*4882a593SmuzhiyunMemory ordering guarantees changes: 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun * fully ordered --> RELEASE ordering + control dependency 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun.. note:: atomic_add_unless() only provides full order on success. 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun 157*4882a593Smuzhiyuncase 7) - lock-based RMW 158*4882a593Smuzhiyun------------------------ 159*4882a593Smuzhiyun 160*4882a593SmuzhiyunFunction changes: 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun * atomic_dec_and_lock() --> refcount_dec_and_lock() 163*4882a593Smuzhiyun * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock() 164*4882a593Smuzhiyun 165*4882a593SmuzhiyunMemory ordering guarantees changes: 166*4882a593Smuzhiyun 167*4882a593Smuzhiyun * fully ordered --> RELEASE ordering + control dependency + hold 168*4882a593Smuzhiyun spin_lock() on success 169