162306a36Sopenharmony_ci=================================== 262306a36Sopenharmony_cirefcount_t API compared to atomic_t 362306a36Sopenharmony_ci=================================== 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci.. contents:: :local: 662306a36Sopenharmony_ci 762306a36Sopenharmony_ciIntroduction 862306a36Sopenharmony_ci============ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciThe goal of refcount_t API is to provide a minimal API for implementing 1162306a36Sopenharmony_cian object's reference counters. While a generic architecture-independent 1262306a36Sopenharmony_ciimplementation from lib/refcount.c uses atomic operations underneath, 1362306a36Sopenharmony_cithere are a number of differences between some of the ``refcount_*()`` and 1462306a36Sopenharmony_ci``atomic_*()`` functions with regards to the memory ordering guarantees. 1562306a36Sopenharmony_ciThis document outlines the differences and provides respective examples 1662306a36Sopenharmony_ciin order to help maintainers validate their code against the change in 1762306a36Sopenharmony_cithese memory ordering guarantees. 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciThe terms used through this document try to follow the formal LKMM defined in 2062306a36Sopenharmony_citools/memory-model/Documentation/explanation.txt. 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cimemory-barriers.txt and atomic_t.txt provide more background to the 2362306a36Sopenharmony_cimemory ordering in general and for atomic operations specifically. 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciRelevant types of memory ordering 2662306a36Sopenharmony_ci================================= 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci.. note:: The following section only covers some of the memory 2962306a36Sopenharmony_ci ordering types that are relevant for the atomics and reference 3062306a36Sopenharmony_ci counters and used through this document. For a much broader picture 3162306a36Sopenharmony_ci please consult memory-barriers.txt document. 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciIn the absence of any memory ordering guarantees (i.e. fully unordered) 3462306a36Sopenharmony_ciatomics & refcounters only provide atomicity and 3562306a36Sopenharmony_ciprogram order (po) relation (on the same CPU). It guarantees that 3662306a36Sopenharmony_cieach ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions 3762306a36Sopenharmony_ciare executed in program order on a single CPU. 3862306a36Sopenharmony_ciThis is implemented using READ_ONCE()/WRITE_ONCE() and 3962306a36Sopenharmony_cicompare-and-swap primitives. 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciA strong (full) memory ordering guarantees that all prior loads and 4262306a36Sopenharmony_cistores (all po-earlier instructions) on the same CPU are completed 4362306a36Sopenharmony_cibefore any po-later instruction is executed on the same CPU. 4462306a36Sopenharmony_ciIt also guarantees that all po-earlier stores on the same CPU 4562306a36Sopenharmony_ciand all propagated stores from other CPUs must propagate to all 4662306a36Sopenharmony_ciother CPUs before any po-later instruction is executed on the original 4762306a36Sopenharmony_ciCPU (A-cumulative property). This is implemented using smp_mb(). 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciA RELEASE memory ordering guarantees that all prior loads and 5062306a36Sopenharmony_cistores (all po-earlier instructions) on the same CPU are completed 5162306a36Sopenharmony_cibefore the operation. It also guarantees that all po-earlier 5262306a36Sopenharmony_cistores on the same CPU and all propagated stores from other CPUs 5362306a36Sopenharmony_cimust propagate to all other CPUs before the release operation 5462306a36Sopenharmony_ci(A-cumulative property). This is implemented using 5562306a36Sopenharmony_cismp_store_release(). 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciAn ACQUIRE memory ordering guarantees that all post loads and 5862306a36Sopenharmony_cistores (all po-later instructions) on the same CPU are 5962306a36Sopenharmony_cicompleted after the acquire operation. It also guarantees that all 6062306a36Sopenharmony_cipo-later stores on the same CPU must propagate to all other CPUs 6162306a36Sopenharmony_ciafter the acquire operation executes. This is implemented using 6262306a36Sopenharmony_cismp_acquire__after_ctrl_dep(). 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciA control dependency (on success) for refcounters guarantees that 6562306a36Sopenharmony_ciif a reference for an object was successfully obtained (reference 6662306a36Sopenharmony_cicounter increment or addition happened, function returned true), 6762306a36Sopenharmony_cithen further stores are ordered against this operation. 6862306a36Sopenharmony_ciControl dependency on stores are not implemented using any explicit 6962306a36Sopenharmony_cibarriers, but rely on CPU not to speculate on stores. This is only 7062306a36Sopenharmony_cia single CPU relation and provides no guarantees for other CPUs. 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciComparison of functions 7462306a36Sopenharmony_ci======================= 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cicase 1) - non-"Read/Modify/Write" (RMW) ops 7762306a36Sopenharmony_ci------------------------------------------- 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciFunction changes: 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci * atomic_set() --> refcount_set() 8262306a36Sopenharmony_ci * atomic_read() --> refcount_read() 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciMemory ordering guarantee changes: 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci * none (both fully unordered) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cicase 2) - increment-based ops that return no value 9062306a36Sopenharmony_ci-------------------------------------------------- 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciFunction changes: 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci * atomic_inc() --> refcount_inc() 9562306a36Sopenharmony_ci * atomic_add() --> refcount_add() 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciMemory ordering guarantee changes: 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci * none (both fully unordered) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cicase 3) - decrement-based RMW ops that return no value 10262306a36Sopenharmony_ci------------------------------------------------------ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciFunction changes: 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci * atomic_dec() --> refcount_dec() 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciMemory ordering guarantee changes: 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci * fully unordered --> RELEASE ordering 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cicase 4) - increment-based RMW ops that return a value 11462306a36Sopenharmony_ci----------------------------------------------------- 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciFunction changes: 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci * atomic_inc_not_zero() --> refcount_inc_not_zero() 11962306a36Sopenharmony_ci * no atomic counterpart --> refcount_add_not_zero() 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciMemory ordering guarantees changes: 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci * fully ordered --> control dependency on success for stores 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci.. note:: We really assume here that necessary ordering is provided as a 12662306a36Sopenharmony_ci result of obtaining pointer to the object! 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cicase 5) - generic dec/sub decrement-based RMW ops that return a value 13062306a36Sopenharmony_ci--------------------------------------------------------------------- 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ciFunction changes: 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci * atomic_dec_and_test() --> refcount_dec_and_test() 13562306a36Sopenharmony_ci * atomic_sub_and_test() --> refcount_sub_and_test() 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciMemory ordering guarantees changes: 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci * fully ordered --> RELEASE ordering + ACQUIRE ordering on success 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cicase 6) other decrement-based RMW ops that return a value 14362306a36Sopenharmony_ci--------------------------------------------------------- 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ciFunction changes: 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci * no atomic counterpart --> refcount_dec_if_one() 14862306a36Sopenharmony_ci * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)`` 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciMemory ordering guarantees changes: 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci * fully ordered --> RELEASE ordering + control dependency 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci.. note:: atomic_add_unless() only provides full order on success. 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cicase 7) - lock-based RMW 15862306a36Sopenharmony_ci------------------------ 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciFunction changes: 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci * atomic_dec_and_lock() --> refcount_dec_and_lock() 16362306a36Sopenharmony_ci * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock() 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ciMemory ordering guarantees changes: 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci * fully ordered --> RELEASE ordering + control dependency + hold 16862306a36Sopenharmony_ci spin_lock() on success 169