Blame view

Documentation/core-api/refcount-vs-atomic.rst 5.57 KB
b6e859f6c   Elena Reshetova   docs: refcount_t ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  ===================================
  refcount_t API compared to atomic_t
  ===================================
  
  .. contents:: :local:
  
  Introduction
  ============
  
  The goal of refcount_t API is to provide a minimal API for implementing
  an object's reference counters. While a generic architecture-independent
  implementation from lib/refcount.c uses atomic operations underneath,
  there are a number of differences between some of the ``refcount_*()`` and
  ``atomic_*()`` functions with regards to the memory ordering guarantees.
  This document outlines the differences and provides respective examples
  in order to help maintainers validate their code against the change in
  these memory ordering guarantees.
  
  The terms used through this document try to follow the formal LKMM defined in
a9251553c   Andrea Parri   Documentation: re...
20
  tools/memory-model/Documentation/explanation.txt.
b6e859f6c   Elena Reshetova   docs: refcount_t ...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  
  memory-barriers.txt and atomic_t.txt provide more background to the
  memory ordering in general and for atomic operations specifically.
  
  Relevant types of memory ordering
  =================================
  
  .. note:: The following section only covers some of the memory
     ordering types that are relevant for the atomics and reference
     counters and used through this document. For a much broader picture
     please consult memory-barriers.txt document.
  
  In the absence of any memory ordering guarantees (i.e. fully unordered)
  atomics & refcounters only provide atomicity and
  program order (po) relation (on the same CPU). It guarantees that
  each ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions
  are executed in program order on a single CPU.
81584a6a7   Jonathan Corbet   docs: remove :c:f...
38
  This is implemented using READ_ONCE()/WRITE_ONCE() and
b6e859f6c   Elena Reshetova   docs: refcount_t ...
39
40
41
42
43
44
45
46
  compare-and-swap primitives.
  
  A strong (full) memory ordering guarantees that all prior loads and
  stores (all po-earlier instructions) on the same CPU are completed
  before any po-later instruction is executed on the same CPU.
  It also guarantees that all po-earlier stores on the same CPU
  and all propagated stores from other CPUs must propagate to all
  other CPUs before any po-later instruction is executed on the original
81584a6a7   Jonathan Corbet   docs: remove :c:f...
47
  CPU (A-cumulative property). This is implemented using smp_mb().
b6e859f6c   Elena Reshetova   docs: refcount_t ...
48
49
50
51
52
53
54
  
  A RELEASE memory ordering guarantees that all prior loads and
  stores (all po-earlier instructions) on the same CPU are completed
  before the operation. It also guarantees that all po-earlier
  stores on the same CPU and all propagated stores from other CPUs
  must propagate to all other CPUs before the release operation
  (A-cumulative property). This is implemented using
81584a6a7   Jonathan Corbet   docs: remove :c:f...
55
  smp_store_release().
b6e859f6c   Elena Reshetova   docs: refcount_t ...
56

47b8f3ab9   Elena Reshetova   refcount_t: Add A...
57
58
59
60
61
  An ACQUIRE memory ordering guarantees that all post loads and
  stores (all po-later instructions) on the same CPU are
  completed after the acquire operation. It also guarantees that all
  po-later stores on the same CPU must propagate to all other CPUs
  after the acquire operation executes. This is implemented using
81584a6a7   Jonathan Corbet   docs: remove :c:f...
62
  smp_acquire__after_ctrl_dep().
47b8f3ab9   Elena Reshetova   refcount_t: Add A...
63

b6e859f6c   Elena Reshetova   docs: refcount_t ...
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  A control dependency (on success) for refcounters guarantees that
  if a reference for an object was successfully obtained (reference
  counter increment or addition happened, function returned true),
  then further stores are ordered against this operation.
  Control dependency on stores are not implemented using any explicit
  barriers, but rely on CPU not to speculate on stores. This is only
  a single CPU relation and provides no guarantees for other CPUs.
  
  
  Comparison of functions
  =======================
  
  case 1) - non-"Read/Modify/Write" (RMW) ops
  -------------------------------------------
  
  Function changes:
81584a6a7   Jonathan Corbet   docs: remove :c:f...
80
81
   * atomic_set() --> refcount_set()
   * atomic_read() --> refcount_read()
b6e859f6c   Elena Reshetova   docs: refcount_t ...
82
83
84
85
86
87
88
89
90
91
  
  Memory ordering guarantee changes:
  
   * none (both fully unordered)
  
  
  case 2) - increment-based ops that return no value
  --------------------------------------------------
  
  Function changes:
81584a6a7   Jonathan Corbet   docs: remove :c:f...
92
93
   * atomic_inc() --> refcount_inc()
   * atomic_add() --> refcount_add()
b6e859f6c   Elena Reshetova   docs: refcount_t ...
94
95
96
97
98
99
100
101
102
  
  Memory ordering guarantee changes:
  
   * none (both fully unordered)
  
  case 3) - decrement-based RMW ops that return no value
  ------------------------------------------------------
  
  Function changes:
81584a6a7   Jonathan Corbet   docs: remove :c:f...
103
   * atomic_dec() --> refcount_dec()
b6e859f6c   Elena Reshetova   docs: refcount_t ...
104
105
106
107
108
109
110
111
112
113
  
  Memory ordering guarantee changes:
  
   * fully unordered --> RELEASE ordering
  
  
  case 4) - increment-based RMW ops that return a value
  -----------------------------------------------------
  
  Function changes:
81584a6a7   Jonathan Corbet   docs: remove :c:f...
114
115
   * atomic_inc_not_zero() --> refcount_inc_not_zero()
   * no atomic counterpart --> refcount_add_not_zero()
b6e859f6c   Elena Reshetova   docs: refcount_t ...
116
117
118
119
120
121
122
  
  Memory ordering guarantees changes:
  
   * fully ordered --> control dependency on success for stores
  
  .. note:: We really assume here that necessary ordering is provided as a
     result of obtaining pointer to the object!
47b8f3ab9   Elena Reshetova   refcount_t: Add A...
123
124
  case 5) - generic dec/sub decrement-based RMW ops that return a value
  ---------------------------------------------------------------------
b6e859f6c   Elena Reshetova   docs: refcount_t ...
125
126
  
  Function changes:
81584a6a7   Jonathan Corbet   docs: remove :c:f...
127
128
   * atomic_dec_and_test() --> refcount_dec_and_test()
   * atomic_sub_and_test() --> refcount_sub_and_test()
47b8f3ab9   Elena Reshetova   refcount_t: Add A...
129
130
131
132
133
134
135
136
137
138
  
  Memory ordering guarantees changes:
  
   * fully ordered --> RELEASE ordering + ACQUIRE ordering on success
  
  
  case 6) other decrement-based RMW ops that return a value
  ---------------------------------------------------------
  
  Function changes:
81584a6a7   Jonathan Corbet   docs: remove :c:f...
139
   * no atomic counterpart --> refcount_dec_if_one()
b6e859f6c   Elena Reshetova   docs: refcount_t ...
140
141
142
143
144
   * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)``
  
  Memory ordering guarantees changes:
  
   * fully ordered --> RELEASE ordering + control dependency
81584a6a7   Jonathan Corbet   docs: remove :c:f...
145
  .. note:: atomic_add_unless() only provides full order on success.
b6e859f6c   Elena Reshetova   docs: refcount_t ...
146

47b8f3ab9   Elena Reshetova   refcount_t: Add A...
147
  case 7) - lock-based RMW
b6e859f6c   Elena Reshetova   docs: refcount_t ...
148
149
150
  ------------------------
  
  Function changes:
81584a6a7   Jonathan Corbet   docs: remove :c:f...
151
152
   * atomic_dec_and_lock() --> refcount_dec_and_lock()
   * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock()
b6e859f6c   Elena Reshetova   docs: refcount_t ...
153
154
155
156
  
  Memory ordering guarantees changes:
  
   * fully ordered --> RELEASE ordering + control dependency + hold
81584a6a7   Jonathan Corbet   docs: remove :c:f...
157
     spin_lock() on success