← Documents Documentation/core-api/refcount-vs-atomic.rst GitHub 원문 ↗

Linux 6.18.37 · Core API

refcount_t API compared to atomic_t

refcount_t로 atomic_t reference counter를 교체할 때 각 API의 unordered, RELEASE, ACQUIRE와 control dependency 보장 차이를 설명합니다.

Source pathDocumentation/core-api/refcount-vs-atomic.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

refcount-vs-atomic.rst:1-193

`refcount_t`는 object lifetime 관리에 필요한 최소 operation과 overflow 방어를 제공하지만, 대응하는 `atomic_t` function과 memory ordering이 항상 같지는 않습니다.

단순 set/read와 일부 increment는 unordered 상태를 유지하는 반면 decrement는 RELEASE ordering을 제공하고, 성공 여부를 반환하는 operation은 ACQUIRE 또는 control dependency를 추가할 수 있습니다.

변환할 때는 function 이름만 바꾸지 말고 기존 code가 full barrier에 의존했는지 확인해야 합니다. 특히 성공 경로의 pointer 접근, 마지막 reference 해제, lock 획득 경로에서 요구하는 ordering을 LKMM 기준으로 검토해야 합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

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

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

refcount_t와 atomic_t 비교 개요

1-24

`refcount_t` API와 `atomic_t` 비교

이 페이지는 local contents 목차를 제공합니다.

소개

`refcount_t` API의 목표는 object의 reference counter를 구현하는 최소 API를 제공하는 것입니다. `lib/refcount.c`의 generic architecture-independent 구현은 내부적으로 atomic operation을 사용하지만, 일부 `refcount_*()`와 `atomic_*()` function은 memory ordering 보장에서 여러 차이가 있습니다.

이 문서는 이러한 차이와 해당 예제를 정리하여 maintainer가 memory ordering 보장 변경에 맞춰 code를 검증할 수 있도록 돕습니다.

문서의 용어는 `tools/memory-model/Documentation/explanation.txt`에 정의된 formal LKMM을 따르려고 합니다.

일반적인 memory ordering 배경은 `memory-barriers.txt`, atomic operation에 특화된 배경은 `atomic_t.txt`를 참고하십시오.

관련 memory ordering 유형

25-71

관련 memory ordering 유형

이 절은 atomic과 reference counter에 관련되어 문서에서 사용하는 일부 memory ordering 유형만 다룹니다. 더 넓은 내용은 `memory-barriers.txt`를 참고하십시오.

Memory ordering 보장이 전혀 없는 fully unordered 상태에서 atomic과 refcounter는 atomicity와 같은 CPU 안의 program order(po) relation만 제공합니다. 각 `atomic_*()`와 `refcount_*()` operation이 atomic이며 instruction이 한 CPU에서 program order로 실행됨을 보장합니다. 이는 `READ_ONCE()/WRITE_ONCE()`와 compare-and-swap primitive로 구현합니다.

Strong 또는 full memory ordering은 같은 CPU의 모든 이전 load와 store, 즉 모든 po-earlier instruction이 완료된 뒤에야 po-later instruction을 실행하도록 보장합니다.

또한 같은 CPU의 모든 po-earlier store와 다른 CPU에서 전파된 모든 store가 원래 CPU의 po-later instruction 실행 전에 다른 모든 CPU로 전파되어야 함을 보장합니다. 이것이 A-cumulative property이며 `smp_mb()`로 구현합니다.

RELEASE memory ordering은 같은 CPU의 모든 이전 load와 store가 release operation보다 먼저 완료됨을 보장합니다. 같은 CPU의 po-earlier store와 다른 CPU에서 전파된 store도 release operation 전에 다른 모든 CPU로 전파되어야 합니다. 이 A-cumulative property는 `smp_store_release()`로 구현합니다.

ACQUIRE memory ordering은 같은 CPU의 모든 이후 load와 store, 즉 po-later instruction이 acquire operation 뒤에 완료됨을 보장합니다. 같은 CPU의 모든 po-later store도 acquire operation 실행 뒤에 다른 모든 CPU로 전파되어야 합니다. 이는 `smp_acquire__after_ctrl_dep()`로 구현합니다.

Refcounter의 성공 시 control dependency는 object reference를 성공적으로 얻은 경우, 즉 reference counter increment 또는 addition이 발생하고 function이 true를 반환한 경우 이후 store가 이 operation에 대해 ordering됨을 보장합니다.

Store에 대한 control dependency는 명시적인 barrier로 구현하지 않고 CPU가 store를 speculate하지 않는다는 성질에 의존합니다. 이는 한 CPU 안의 relation일 뿐이며 다른 CPU에는 아무 보장도 제공하지 않습니다.

Case 1과 2: non-RMW operation

72-100

Function 비교

Case 1: non-Read/Modify/Write(RMW) operation

Function 변경:

  • `atomic_set()` -> `refcount_set()`
  • `atomic_read()` -> `refcount_read()`

Memory ordering 보장 변경:

  • 변경 없음. 둘 다 fully unordered입니다.

Case 2: release ordering을 사용하는 non-Read/Modify/Write(RMW) operation

Function 변경:

  • `atomic_set_release()` -> `refcount_set_release()`

Memory ordering 보장 변경:

  • 변경 없음. 둘 다 RELEASE ordering을 제공합니다.

Case 3과 4: 반환값 없는 increment와 decrement

101-124

Case 3: 값을 반환하지 않는 increment 기반 operation

Function 변경:

  • `atomic_inc()` -> `refcount_inc()`
  • `atomic_add()` -> `refcount_add()`

Memory ordering 보장 변경:

  • 변경 없음. 둘 다 fully unordered입니다.

Case 4: 값을 반환하지 않는 decrement 기반 RMW operation

Function 변경:

  • `atomic_dec()` -> `refcount_dec()`

Memory ordering 보장 변경:

  • Fully unordered에서 RELEASE ordering으로 변경됩니다.

Case 5: 값을 반환하는 increment operation

125-140

Case 5: 값을 반환하는 increment 기반 RMW operation

Function 변경:

  • `atomic_inc_not_zero()` -> `refcount_inc_not_zero()`
  • 대응하는 atomic function 없음 -> `refcount_add_not_zero()`

Memory ordering 보장 변경:

  • Fully ordered에서 store에 대한 성공 시 control dependency로 변경됩니다.

여기서는 object pointer를 얻은 결과로 필요한 ordering이 제공된다고 전제합니다.

Case 6: acquire increment operation

141-153

Case 6: acquire ordering을 사용하고 값을 반환하는 increment 기반 RMW operation

Function 변경:

  • `atomic_inc_not_zero()` -> `refcount_inc_not_zero_acquire()`
  • 대응하는 atomic function 없음 -> `refcount_add_not_zero_acquire()`

Memory ordering 보장 변경:

  • Fully ordered에서 성공 시 ACQUIRE ordering으로 변경됩니다.

Case 7: generic decrement operation

154-166

Case 7: 값을 반환하는 generic dec/sub decrement 기반 RMW operation

Function 변경:

  • `atomic_dec_and_test()` -> `refcount_dec_and_test()`
  • `atomic_sub_and_test()` -> `refcount_sub_and_test()`

Memory ordering 보장 변경:

  • Fully ordered에서 RELEASE ordering과 성공 시 ACQUIRE ordering의 조합으로 변경됩니다.

Case 8: 기타 decrement operation

167-181

Case 8: 값을 반환하는 기타 decrement 기반 RMW operation

Function 변경:

  • 대응하는 atomic function 없음 -> `refcount_dec_if_one()`
  • `atomic_add_unless(&var, -1, 1)` -> `refcount_dec_not_one(&var)`

Memory ordering 보장 변경:

  • Fully ordered에서 RELEASE ordering과 control dependency의 조합으로 변경됩니다.

`atomic_add_unless()`는 성공한 경우에만 full ordering을 제공합니다.

Case 9: lock 기반 RMW

182-193

Case 9: lock 기반 RMW

Function 변경:

  • `atomic_dec_and_lock()` -> `refcount_dec_and_lock()`
  • `atomic_dec_and_mutex_lock()` -> `refcount_dec_and_mutex_lock()`

Memory ordering 보장 변경:

  • Fully ordered에서 RELEASE ordering, control dependency, 성공 시 `spin_lock()` 보유의 조합으로 변경됩니다.