18c2ecf20Sopenharmony_ci=================================== 28c2ecf20Sopenharmony_cirefcount_t API compared to atomic_t 38c2ecf20Sopenharmony_ci=================================== 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci.. contents:: :local: 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ciIntroduction 88c2ecf20Sopenharmony_ci============ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ciThe goal of refcount_t API is to provide a minimal API for implementing 118c2ecf20Sopenharmony_cian object's reference counters. While a generic architecture-independent 128c2ecf20Sopenharmony_ciimplementation from lib/refcount.c uses atomic operations underneath, 138c2ecf20Sopenharmony_cithere are a number of differences between some of the ``refcount_*()`` and 148c2ecf20Sopenharmony_ci``atomic_*()`` functions with regards to the memory ordering guarantees. 158c2ecf20Sopenharmony_ciThis document outlines the differences and provides respective examples 168c2ecf20Sopenharmony_ciin order to help maintainers validate their code against the change in 178c2ecf20Sopenharmony_cithese memory ordering guarantees. 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciThe terms used through this document try to follow the formal LKMM defined in 208c2ecf20Sopenharmony_citools/memory-model/Documentation/explanation.txt. 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cimemory-barriers.txt and atomic_t.txt provide more background to the 238c2ecf20Sopenharmony_cimemory ordering in general and for atomic operations specifically. 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciRelevant types of memory ordering 268c2ecf20Sopenharmony_ci================================= 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci.. note:: The following section only covers some of the memory 298c2ecf20Sopenharmony_ci ordering types that are relevant for the atomics and reference 308c2ecf20Sopenharmony_ci counters and used through this document. For a much broader picture 318c2ecf20Sopenharmony_ci please consult memory-barriers.txt document. 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciIn the absence of any memory ordering guarantees (i.e. fully unordered) 348c2ecf20Sopenharmony_ciatomics & refcounters only provide atomicity and 358c2ecf20Sopenharmony_ciprogram order (po) relation (on the same CPU). It guarantees that 368c2ecf20Sopenharmony_cieach ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions 378c2ecf20Sopenharmony_ciare executed in program order on a single CPU. 388c2ecf20Sopenharmony_ciThis is implemented using READ_ONCE()/WRITE_ONCE() and 398c2ecf20Sopenharmony_cicompare-and-swap primitives. 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciA strong (full) memory ordering guarantees that all prior loads and 428c2ecf20Sopenharmony_cistores (all po-earlier instructions) on the same CPU are completed 438c2ecf20Sopenharmony_cibefore any po-later instruction is executed on the same CPU. 448c2ecf20Sopenharmony_ciIt also guarantees that all po-earlier stores on the same CPU 458c2ecf20Sopenharmony_ciand all propagated stores from other CPUs must propagate to all 468c2ecf20Sopenharmony_ciother CPUs before any po-later instruction is executed on the original 478c2ecf20Sopenharmony_ciCPU (A-cumulative property). This is implemented using smp_mb(). 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciA RELEASE memory ordering guarantees that all prior loads and 508c2ecf20Sopenharmony_cistores (all po-earlier instructions) on the same CPU are completed 518c2ecf20Sopenharmony_cibefore the operation. It also guarantees that all po-earlier 528c2ecf20Sopenharmony_cistores on the same CPU and all propagated stores from other CPUs 538c2ecf20Sopenharmony_cimust propagate to all other CPUs before the release operation 548c2ecf20Sopenharmony_ci(A-cumulative property). This is implemented using 558c2ecf20Sopenharmony_cismp_store_release(). 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciAn ACQUIRE memory ordering guarantees that all post loads and 588c2ecf20Sopenharmony_cistores (all po-later instructions) on the same CPU are 598c2ecf20Sopenharmony_cicompleted after the acquire operation. It also guarantees that all 608c2ecf20Sopenharmony_cipo-later stores on the same CPU must propagate to all other CPUs 618c2ecf20Sopenharmony_ciafter the acquire operation executes. This is implemented using 628c2ecf20Sopenharmony_cismp_acquire__after_ctrl_dep(). 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciA control dependency (on success) for refcounters guarantees that 658c2ecf20Sopenharmony_ciif a reference for an object was successfully obtained (reference 668c2ecf20Sopenharmony_cicounter increment or addition happened, function returned true), 678c2ecf20Sopenharmony_cithen further stores are ordered against this operation. 688c2ecf20Sopenharmony_ciControl dependency on stores are not implemented using any explicit 698c2ecf20Sopenharmony_cibarriers, but rely on CPU not to speculate on stores. This is only 708c2ecf20Sopenharmony_cia single CPU relation and provides no guarantees for other CPUs. 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciComparison of functions 748c2ecf20Sopenharmony_ci======================= 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cicase 1) - non-"Read/Modify/Write" (RMW) ops 778c2ecf20Sopenharmony_ci------------------------------------------- 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciFunction changes: 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci * atomic_set() --> refcount_set() 828c2ecf20Sopenharmony_ci * atomic_read() --> refcount_read() 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciMemory ordering guarantee changes: 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci * none (both fully unordered) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cicase 2) - increment-based ops that return no value 908c2ecf20Sopenharmony_ci-------------------------------------------------- 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciFunction changes: 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci * atomic_inc() --> refcount_inc() 958c2ecf20Sopenharmony_ci * atomic_add() --> refcount_add() 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciMemory ordering guarantee changes: 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci * none (both fully unordered) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cicase 3) - decrement-based RMW ops that return no value 1028c2ecf20Sopenharmony_ci------------------------------------------------------ 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciFunction changes: 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci * atomic_dec() --> refcount_dec() 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciMemory ordering guarantee changes: 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci * fully unordered --> RELEASE ordering 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cicase 4) - increment-based RMW ops that return a value 1148c2ecf20Sopenharmony_ci----------------------------------------------------- 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciFunction changes: 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci * atomic_inc_not_zero() --> refcount_inc_not_zero() 1198c2ecf20Sopenharmony_ci * no atomic counterpart --> refcount_add_not_zero() 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciMemory ordering guarantees changes: 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci * fully ordered --> control dependency on success for stores 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci.. note:: We really assume here that necessary ordering is provided as a 1268c2ecf20Sopenharmony_ci result of obtaining pointer to the object! 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cicase 5) - generic dec/sub decrement-based RMW ops that return a value 1308c2ecf20Sopenharmony_ci--------------------------------------------------------------------- 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciFunction changes: 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci * atomic_dec_and_test() --> refcount_dec_and_test() 1358c2ecf20Sopenharmony_ci * atomic_sub_and_test() --> refcount_sub_and_test() 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciMemory ordering guarantees changes: 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci * fully ordered --> RELEASE ordering + ACQUIRE ordering on success 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cicase 6) other decrement-based RMW ops that return a value 1438c2ecf20Sopenharmony_ci--------------------------------------------------------- 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ciFunction changes: 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci * no atomic counterpart --> refcount_dec_if_one() 1488c2ecf20Sopenharmony_ci * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)`` 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ciMemory ordering guarantees changes: 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci * fully ordered --> RELEASE ordering + control dependency 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci.. note:: atomic_add_unless() only provides full order on success. 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cicase 7) - lock-based RMW 1588c2ecf20Sopenharmony_ci------------------------ 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ciFunction changes: 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci * atomic_dec_and_lock() --> refcount_dec_and_lock() 1638c2ecf20Sopenharmony_ci * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock() 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciMemory ordering guarantees changes: 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci * fully ordered --> RELEASE ordering + control dependency + hold 1688c2ecf20Sopenharmony_ci spin_lock() on success 169