Lines Matching +full:cpu +full:- +full:2

2 This is a version of Documentation/memory-barriers.txt translated into Korean.
15 Documentation/memory-barriers.txt
39 일부 이상한 점들은 공식적인 메모리 일관성 모델과 tools/memory-model/ 에 있는
51 (2) 사용 가능한 배리어들에 대해 어떻게 사용해야 하는지에 대한 안내를 제공하기
60 해당 배리어의 명시적 사용이 불필요해서 no-op 이 될수도 있음을 알아두시기
76 - 디바이스 오퍼레이션.
77 - 보장사항.
81 - 메모리 배리어의 종류.
82 - 메모리 배리어에 대해 가정해선 안될 것.
83 - 주소 데이터 의존성 배리어 (역사적).
84 - 컨트롤 의존성.
85 - SMP 배리어 짝맞추기.
86 - 메모리 배리어 시퀀스의 예.
87 - 읽기 메모리 배리어 vs 로드 예측.
88 - Multicopy 원자성.
92 - 컴파일러 배리어.
93 - CPU 메모리 배리어.
97 - 락 Acquisition 함수.
98 - 인터럽트 비활성화 함수.
99 - 슬립과 웨이크업 함수.
100 - 그외의 함수들.
102 (*) CPU 간 ACQUIRING 배리어의 효과.
104 - Acquire vs 메모리 액세스.
108 - 프로세서간 상호 작용.
109 - 어토믹 오퍼레이션.
110 - 디바이스 액세스.
111 - 인터럽트.
117 (*) CPU 캐시의 영향.
119 - 캐시 일관성.
120 - 캐시 일관성 vs DMA.
121 - 캐시 일관성 vs MMIO.
123 (*) CPU 들이 저지르는 일들.
125 - 그리고, Alpha 가 있다.
126 - 가상 머신 게스트.
130 - 순환식 버퍼.
144 +-------+ : +--------+ : +-------+
147 | CPU 1 |<----->| Memory |<----->| CPU 2 |
150 +-------+ : +--------+ : +-------+
155 | : +--------+ : |
158 +---------->| Device |<----------+
161 : +--------+ :
164 프로그램은 여러 메모리 액세스 오퍼레이션을 발생시키고, 각각의 CPU 는 그런
165 프로그램들을 실행합니다. 추상화된 CPU 모델에서 메모리 오퍼레이션들의 순서는
166 매우 완화되어 있고, CPU 는 프로그램이 인과관계를 어기지 않는 상태로 관리된다고
173 변화는 해당 오퍼레이션이 CPU 와 시스템의 다른 부분들 사이의 인터페이스(점선)를
179 CPU 1 CPU 2
181 { A == 1; B == 2 }
188 STORE A=3, STORE B=4, y=LOAD A->3, x=LOAD B->4
189 STORE A=3, STORE B=4, x=LOAD B->4, y=LOAD A->3
190 STORE A=3, y=LOAD A->3, STORE B=4, x=LOAD B->4
191 STORE A=3, y=LOAD A->3, x=LOAD B->2, STORE B=4
192 STORE A=3, x=LOAD B->2, STORE B=4, y=LOAD A->3
193 STORE A=3, x=LOAD B->2, y=LOAD A->3, STORE B=4
194 STORE B=4, STORE A=3, y=LOAD A->3, x=LOAD B->4
200 x == 2, y == 1
201 x == 2, y == 3
206 한발 더 나아가서, 한 CPU 가 메모리 시스템에 반영한 스토어 오퍼레이션들의 결과는
207 다른 CPU 에서의 로드 오퍼레이션을 통해 인지되는데, 이 때 스토어가 반영된 순서와
213 CPU 1 CPU 2
215 { A == 1, B == 2, C == 3, P == &A, Q == &C }
219 D 로 읽혀지는 값은 CPU 2 에서 P 로부터 읽혀진 주소값에 의존적이기 때문에 여기엔
224 (Q == &B) and (D == 2)
227 CPU 2 는 *Q 의 로드를 요청하기 전에 P 를 Q 에 넣기 때문에 D 에 C 를 집어넣는
232 -------------------
252 --------
254 CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니다:
256 (*) 어떤 CPU 든, 의존성이 존재하는 메모리 액세스들은 해당 CPU 자신에게
261 CPU 는 다음과 같은 메모리 오퍼레이션 시퀀스를 수행 요청합니다:
266 READ_ONCE() 는 메모리 배리어 명령도 내게 되어 있어서, DEC Alpha CPU
274 (*) 특정 CPU 내에서 겹치는 영역의 메모리에 행해지는 로드와 스토어 들은 해당
275 CPU 안에서는 순서가 바뀌지 않은 것으로 보여집니다. 즉, 다음에 대해서:
279 CPU 는 다음의 메모리 오퍼레이션 시퀀스만을 메모리에 요청할 겁니다:
287 CPU 는 다음의 수행 요청만을 만들어 냅니다:
336 그리고 보장사항에 반대되는 것들(anti-guarantees)이 있습니다:
339 수정하는 코드를 생성할 때 원자성 없는(non-atomic) 읽고-수정하고-쓰는
346 읽고-수정하고-쓰는 인스트럭션 조합은 한 필드에의 업데이트가 근처의
353 "short" 에 대해서는 2바이트 정렬을, "int" 에는 4바이트 정렬을, 그리고
354 "long" 에 대해서는 32-bit 시스템인지 64-bit 시스템인지에 따라 4바이트 또는
363 of adjacent bit-fields all having nonzero width
369 NOTE 2: A bit-field and an adjacent non-bit-field member
371 to two bit-fields, if one is declared inside a nested
373 are separated by a zero-length bit-field declaration,
374 or if they are separated by a non-bit-field member
376 bit-fields in the same structure if all members declared
377 between them are also bit-fields, no matter what the
378 sizes of those intervening bit-fields happen to be.
386 순서로 수행될 수 있으며, 이는 CPUCPU 간의 상호작용이나 I/O 에 문제가 될 수
387 있습니다. 따라서 컴파일러와 CPU 가 순서를 바꾸는데 제약을 걸 수 있도록 개입할
393 시스템의 CPU 들과 여러 디바이스들은 성능을 올리기 위해 명령어 재배치, 실행
397 트릭들을 무효로 하거나 억제하는 목적으로 사용되어져서 코드가 여러 CPU
402 --------------------
415 CPU 는 시간의 흐름에 따라 메모리 시스템에 일련의 스토어 오퍼레이션들을
423 (2) 주소 의존성 배리어 (역사적).
435 (1) 에서 언급했듯이, 시스템의 CPU 들은 메모리 시스템에 일련의 스토어
436 오퍼레이션들을 던져 넣고 있으며, 거기에 관심이 있는 다른 CPU 는 그
438 다른 CPU 의 스토어 오퍼레이션의 결과에 관심을 두고 있는 CPU 가 수행 요청한
439 주소 의존성 배리어는, 배리어 앞의 어떤 로드 오퍼레이션이 다른 CPU 에서
521 동작할 것을 보장하지 -않습니다-. 하지만, 어떤 변수에 대한 RELEASE
537 메모리 배리어들은 두 CPU 간, 또는 CPU 와 디바이스 간에 상호작용의 가능성이 있을
548 -------------------------------------
553 완료 시점까지 _완료_ 될 것이란 보장은 없습니다; 배리어가 하는 일은 CPU
557 (*) 한 CPU 에서 메모리 배리어를 수행하는게 시스템의 다른 CPU 나 하드웨어에
559 만드는 간접적 영향은 두번째 CPU 가 첫번째 CPU 의 액세스들의 결과를
562 (*) 첫번째 CPU 가 두번째 CPU 의 메모리 액세스들의 결과를 바라볼 때, _설령_
563 두번째 CPU 가 메모리 배리어를 사용한다 해도, 첫번째 CPU _또한_ 그에 맞는
567 (*) CPU 바깥의 하드웨어[*] 가 메모리 액세스들의 순서를 바꾸지 않는다는 보장은
568 존재하지 않습니다. CPU 캐시 일관성 메커니즘은 메모리 배리어의 간접적
569 영향을 CPU 사이에 전파하긴 하지만, 순서대로 전파하지는 않을 수 있습니다.
573 Documentation/driver-api/pci/pci.rst
574 Documentation/core-api/dma-api-howto.rst
575 Documentation/core-api/dma-api.rst
579 ---------------------------
595 CPU 1 CPU 2
597 { A == 1, B == 2, C == 3, P == &A, Q == &C }
613 하지만! CPU 2 는 B 의 업데이트를 인식하기 전에 P 의 업데이트를 인식할 수 있고,
616 (Q == &B) and (D == 2) ????
619 그렇지 않습니다, 그리고 이 현상은 (DEC Alpha 와 같은) 여러 CPU 에서 실제로
625 CPU 1 CPU 2
627 { A == 1, B == 2, C == 3, P == &A, Q == &C }
643 저장되어 있을 수 있습니다. 여기서 값을 읽어오는 CPU 의 캐시의 홀수 번호 처리
645 중이라면 포인터 P (&B) 의 새로운 값과 변수 B 의 기존 값 (2) 를 볼 수 있습니다.
649 리눅스 커널이 지원하는 CPU 들은 (1) 쓰기가 정말로 일어날지, (2) 쓰기가 어디에
655 CPU 1 CPU 2
657 { A == 1, B == 2, C = 3, P == &A, Q == &C }
671 순서 규칙의 의도는 쓰기 작업을 -예방- 해서 그로 인해 발생하는 비싼 캐시 미스도
677 주소 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU
692 -------------
698 로드-로드 컨트롤 의존성은 (묵시적인) 주소 의존성 배리어만으로는 정확히 동작할
709 아니라 컨트롤 의존성이 존재하기 때문으로, 이런 상황에서 CPU 는 실행 속도를 더
711 CPU 는 b 로부터의 로드 오퍼레이션이 a 로부터의 로드 오퍼레이션보다 먼저 발생한
721 같이 로드-스토어 컨트롤 의존성이 존재하는 경우에는 순서가 -지켜진다-
740 b = 1; /* BUG: Compiler and CPU can both reorder!!! */
765 /* WRITE_ONCE(b, 1); -- moved up, BUG!!! */
768 /* WRITE_ONCE(b, 1); -- moved up, BUG!!! */
772 이제 'a' 에서의 로드와 'b' 로의 스토어 사이에는 조건적 관계가 없기 때문에 CPU
795 WRITE_ONCE(b, 2);
811 WRITE_ONCE(b, 2);
819 WRITE_ONCE(b, 2);
822 이렇게 되면, CPU 는 변수 'a' 로부터의 로드와 변수 'b' 로의 스토어 사이의 순서를
834 WRITE_ONCE(b, 2);
868 WRITE_ONCE(b, 2);
874 싶을 겁니다. 불행히도 이 경우에, 컴파일러는 다음의 가상의 pseudo-assembly 언어
875 코드처럼 'b' 로의 두개의 쓰기 오퍼레이션을 conditional-move 인스트럭션으로
881 cmov,eq r4,$2
885 완화된 순서 규칙의 CPU 는 'a' 로부터의 로드와 'c' 로의 스토어 사이에 어떤
892 컨트롤 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU
899 하지만, 그 외의 어떤 순서도 보장하지 -않습니다-: 앞의 로드와 뒤의 로드들
925 갖는 if 문을 뒤따르는 코드에는 적용되지 -않습니다-.
929 (*) 컨트롤 의존성은 multicopy 원자성을 제공하지 -않습니다-. 모든 CPU 들이
937 --------------------
939 CPU 간 상호작용을 다룰 때에 일부 타입의 메모리 배리어는 항상 짝을 맞춰
951 CPU 1 CPU 2
955 WRITE_ONCE(b, 2); x = READ_ONCE(b);
961 CPU 1 CPU 2
971 CPU 1 CPU 2
988 CPU 1 CPU 2
990 WRITE_ONCE(a, 1); }---- --->{ v = READ_ONCE(c);
991 WRITE_ONCE(b, 2); } \ / { w = READ_ONCE(d);
994 WRITE_ONCE(d, 4); }---- --->{ y = READ_ONCE(b);
998 -------------------------
1003 CPU 1
1006 STORE B = 2
1017 +-------+ : :
1018 | | +------+
1019 | |------>| C=3 | } /\
1020 | | : +------+ }----- \ -----> 시스템의 나머지 요소에
1022 | | : +------+ }
1023 | CPU 1 | : | B=2 | }
1024 | | +------+ }
1025 | | wwwwwwwwwwwwwwww } <--- 여기서 쓰기 배리어는 배리어 앞의
1026 | | +------+ } 모든 스토어가 배리어 뒤의 스토어
1028 | | : +------+ } 합니다
1029 | |------>| D=4 | }
1030 | | +------+
1031 +-------+ : :
1033 | CPU 1 에 의해 메모리 시스템에 전달되는
1041 CPU 1 CPU 2
1045 STORE B = 2
1051 여기에 별다른 개입이 없다면, CPU 1 의 쓰기 배리어에도 불구하고 CPU 2CPU 1
1054 +-------+ : : : :
1055 | | +------+ +-------+ | CPU 2 에 인지되는
1056 | |------>| B=2 |----- --->| Y->8 | | 업데이트 이벤트
1057 | | : +------+ \ +-------+ | 시퀀스
1058 | CPU 1 | : | A=1 | \ --->| C->&Y | V
1059 | | +------+ | +-------+
1061 | | +------+ | : :
1062 | | : | C=&B |--- | : : +-------+
1063 | | : +------+ \ | +-------+ | |
1064 | |------>| D=4 | ----------->| C->&B |------>| |
1065 | | +------+ | +-------+ | |
1066 +-------+ : : | : : | |
1068 | : : | CPU 2 |
1069 | +-------+ | |
1070 분명히 잘못된 ---> | | B->7 |------>| |
1071 B 의 값 인지 (!) | +-------+ | |
1073 | +-------+ | |
1074 X 의 로드가 B 의 ---> \ | X->9 |------>| |
1075 일관성 유지를 \ +-------+ | |
1076 지연시킴 ----->| B->2 | +-------+
1077 +-------+
1081 앞의 예에서, CPU 2 는 (B 의 값이 될) *C 의 값 읽기가 C 의 LOAD 뒤에 이어짐에도
1087 CPU 1 CPU 2
1091 STORE B = 2
1100 +-------+ : : : :
1101 | | +------+ +-------+
1102 | |------>| B=2 |----- --->| Y->8 |
1103 | | : +------+ \ +-------+
1104 | CPU 1 | : | A=1 | \ --->| C->&Y |
1105 | | +------+ | +-------+
1107 | | +------+ | : :
1108 | | : | C=&B |--- | : : +-------+
1109 | | : +------+ \ | +-------+ | |
1110 | |------>| D=4 | ----------->| C->&B |------>| |
1111 | | +------+ | +-------+ | |
1112 +-------+ : : | : : | |
1114 | : : | CPU 2 |
1115 | +-------+ | |
1116 | | X->9 |------>| |
1117 | +-------+ | |
1118 C 로의 스토어 앞의 ---> \ aaaaaaaaaaaaaaaaa | |
1119 모든 이벤트 결과가 \ +-------+ | |
1120 뒤의 로드에게 ----->| B->2 |------>| |
1121 보이게 강제한다 +-------+ | |
1122 : : +-------+
1128 CPU 1 CPU 2
1133 STORE B=2
1137 CPU 1 은 쓰기 배리어를 쳤지만, 별다른 개입이 없다면 CPU 2CPU 1 에서 행해진
1140 +-------+ : : : :
1141 | | +------+ +-------+
1142 | |------>| A=1 |------ --->| A->0 |
1143 | | +------+ \ +-------+
1144 | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
1145 | | +------+ | +-------+
1146 | |------>| B=2 |--- | : :
1147 | | +------+ \ | : : +-------+
1148 +-------+ : : \ | +-------+ | |
1149 ---------->| B->2 |------>| |
1150 | +-------+ | CPU 2 |
1151 | | A->0 |------>| |
1152 | +-------+ | |
1153 | : : +-------+
1155 \ +-------+
1156 ---->| A->1 |
1157 +-------+
1163 CPU 1 CPU 2
1168 STORE B=2
1173 CPU 1 에 의해 만들어진 부분적 순서가 CPU 2 에도 그대로 인지됩니다:
1175 +-------+ : : : :
1176 | | +------+ +-------+
1177 | |------>| A=1 |------ --->| A->0 |
1178 | | +------+ \ +-------+
1179 | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
1180 | | +------+ | +-------+
1181 | |------>| B=2 |--- | : :
1182 | | +------+ \ | : : +-------+
1183 +-------+ : : \ | +-------+ | |
1184 ---------->| B->2 |------>| |
1185 | +-------+ | CPU 2 |
1188 여기서 읽기 배리어는 ----> \ rrrrrrrrrrrrrrrrr | |
1189 B 로의 스토어 전의 \ +-------+ | |
1190 모든 결과를 CPU 2---->| A->1 |------>| |
1191 보이도록 한다 +-------+ | |
1192 : : +-------+
1198 CPU 1 CPU 2
1203 STORE B=2
1212 +-------+ : : : :
1213 | | +------+ +-------+
1214 | |------>| A=1 |------ --->| A->0 |
1215 | | +------+ \ +-------+
1216 | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
1217 | | +------+ | +-------+
1218 | |------>| B=2 |--- | : :
1219 | | +------+ \ | : : +-------+
1220 +-------+ : : \ | +-------+ | |
1221 ---------->| B->2 |------>| |
1222 | +-------+ | CPU 2 |
1225 | +-------+ | |
1226 | | A->0 |------>| 1st |
1227 | +-------+ | |
1228 여기서 읽기 배리어는 ----> \ rrrrrrrrrrrrrrrrr | |
1229 B 로의 스토어 전의 \ +-------+ | |
1230 모든 결과를 CPU 2---->| A->1 |------>| 2nd |
1231 보이도록 한다 +-------+ | |
1232 : : +-------+
1235 하지만 CPU 1 에서의 A 업데이트는 읽기 배리어가 완료되기 전에도 보일 수도
1238 +-------+ : : : :
1239 | | +------+ +-------+
1240 | |------>| A=1 |------ --->| A->0 |
1241 | | +------+ \ +-------+
1242 | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
1243 | | +------+ | +-------+
1244 | |------>| B=2 |--- | : :
1245 | | +------+ \ | : : +-------+
1246 +-------+ : : \ | +-------+ | |
1247 ---------->| B->2 |------>| |
1248 | +-------+ | CPU 2 |
1251 \ +-------+ | |
1252 ---->| A->1 |------>| 1st |
1253 +-------+ | |
1255 +-------+ | |
1256 | A->1 |------>| 2nd |
1257 +-------+ | |
1258 : : +-------+
1261 여기서 보장되는 건, 만약 B 의 로드가 B == 2 라는 결과를 봤다면, A 에의 두번째
1267 -------------------------------
1272 않다면, 그 데이터를 로드합니다. 이후에 실제 로드 인스트럭션이 실행되면 CPU
1275 해당 CPU 는 실제로는 그 값이 필요치 않았다는 사실이 나중에 드러날 수도 있는데 -
1276 해당 로드 인스트럭션이 브랜치로 우회되거나 했을 수 있겠죠 - , 그렇게 되면 앞서
1281 CPU 1 CPU 2
1290 : : +-------+
1291 +-------+ | |
1292 --->| B->2 |------>| |
1293 +-------+ | CPU 2 |
1295 +-------+ | |
1296 나누기 하느라 바쁜 ---> --->| A->0 |~~~~ | |
1297 CPU 는 A 의 LOAD 를 +-------+ ~ | |
1301 나누기가 끝나면 ---> ---> : : ~-->| |
1302 CPU 는 해당 LOAD 를 : : | |
1303 즉각 완료한다 : : +-------+
1308 CPU 1 CPU 2
1320 : : +-------+
1321 +-------+ | |
1322 --->| B->2 |------>| |
1323 +-------+ | CPU 2 |
1325 +-------+ | |
1326 나누기 하느라 바쁜 ---> --->| A->0 |~~~~ | |
1327 CPU 는 A 의 LOAD 를 +-------+ ~ | |
1334 : : ~-->| |
1336 : : +-------+
1339 하지만 다른 CPU 에서 업데이트나 무효화가 있었다면, 그 예측은 무효화되고 그 값은
1342 : : +-------+
1343 +-------+ | |
1344 --->| B->2 |------>| |
1345 +-------+ | CPU 2 |
1347 +-------+ | |
1348 나누기 하느라 바쁜 ---> --->| A->0 |~~~~ | |
1349 CPU 는 A 의 LOAD 를 +-------+ ~ | |
1355 +-------+ | |
1356 예측성 동작은 무효화 되고 ---> --->| A->1 |------>| |
1357 업데이트된 값이 다시 읽혀진다 +-------+ | |
1358 : : +-------+
1362 ----------------
1365 대한 상당히 직관적인 개념으로, 특정 스토어가 모든 CPU 들에게 동시에 보여지게
1366 됨을, 달리 말하자면 모든 CPU 들이 모든 스토어들이 보여지는 순서를 동의하게 되는
1369 원자성'' 라는 이름의, 특정 스토어가 모든 -다른- CPU 들에게는 동시에 보여지게
1375 CPU 1 CPU 2 CPU 3
1382 CPU 2 의 Y 로의 스토어에 사용되는 X 로드의 결과가 1 이었고 CPU 3 의 Y 로드가
1383 1을 리턴했다고 해봅시다. 이는 CPU 1 의 X 로의 스토어가 CPU 2 의 X 로부터의
1384 로드를 앞서고 CPU 2 의 Y 로의 스토어가 CPU 3 의 Y 로부터의 로드를 앞섬을
1385 의미합니다. 또한, 여기서의 메모리 배리어들은 CPU 2 가 자신의 로드를 자신의
1386 스토어 전에 수행하고, CPU 3 가 Y 로부터의 로드를 X 로부터의 로드 전에 수행함을
1387 보장합니다. 그럼 "CPU 3 의 X 로부터의 로드는 0 을 리턴할 수 있을까요?"
1389 CPU 3 의 X 로드가 CPU 2 의 로드보다 뒤에 이루어졌으므로, CPU 3 의 X 로부터의
1391 원자성으로부터 나옵니다: CPU B 에서 수행된 로드가 CPU A 의 같은 변수로부터의
1392 로드를 뒤따른다면 (그리고 CPU A 가 자신이 읽은 값으로 먼저 해당 변수에 스토어
1393 하지 않았다면) multicopy 원자성을 제공하는 시스템에서는, CPU B 의 로드가 CPU A
1398 앞의 예에서, CPU 2 의 X 로부터의 로드가 1 을 리턴했고 CPU 3 의 Y 로부터의
1399 로드가 1 을 리턴했다면, CPU 3 의 X 로부터의 로드는 1을 리턴해야만 합니다.
1401 하지만, 의존성, 읽기 배리어, 쓰기 배리어는 항상 non-multicopy 원자성을 보상해
1402 주지는 않습니다. 예를 들어, CPU 2 의 범용 배리어가 앞의 예에서 사라져서
1405 CPU 1 CPU 2 CPU 3
1412 이 변화는 non-multicopy 원자성이 만연하게 합니다: 이 예에서, CPU 2 의 X
1413 로부터의 로드가 1을 리턴하고, CPU 3 의 Y 로부터의 로드가 1 을 리턴하는데, CPU 3
1416 핵심은, CPU 2 의 데이터 의존성이 자신의 로드와 스토어를 순서짓지만, CPU 1 의
1417 스토어에 대한 순서는 보장하지 않는다는 것입니다. 따라서, 이 예제가 CPU 1 과
1418 CPU 2 가 스토어 버퍼나 한 수준의 캐시를 공유하는, multicopy 원자성을 제공하지
1419 않는 시스템에서 수행된다면 CPU 2CPU 1 의 쓰기에 이른 접근을 할 수도
1420 있습니다. 따라서, 모든 CPU 들이 여러 접근들의 조합된 순서에 대해서 동의하게
1423 범용 배리어는 non-multicopy 원자성만 보상할 수 있는게 아니라, -모든- CPU 들이
1424 -모든- 오퍼레이션들의 순서를 동일하게 인식하게 하는 추가적인 순서 보장을
1425 만들어냅니다. 반대로, release-acquire 짝의 연결은 이런 추가적인 순서는
1426 제공하지 않는데, 해당 연결에 들어있는 CPU 들만이 메모리 접근의 조합된 순서에
1465 더 나아가서, cpu0() 와 cpu1() 사이의 release-acquire 관계로 인해, cpu1() 은
1470 하지만, release-acquire 에 의해 제공되는 순서는 해당 연결에 동참한 CPU 들에만
1481 release-acquire 체인에 관여되지 않은 CPU 들은 그 순서에 이견을 가질 수
1491 어떤 특정한 값이 읽힐 것인지는 보장하지 -않습니다-. 따라서, 다음과 같은 결과도
1511 (*) CPU 메모리 배리어.
1515 ---------------
1522 이건 범용 배리어입니다 -- barrier() 의 읽기-읽기 나 쓰기-쓰기 변종은 없습니다.
1552 즉, READ_ONCE() 와 WRITE_ONCE() 는 여러 CPU 에서 하나의 변수에 가해지는
1586 예를 들어, 최적화된 이 코드는 변수 a 가 다른 CPU 에 의해 "while" 문과
1612 때문입니다. 문제는 컴파일러가 'a' 의 값을 업데이트 하는건 현재의 CPU 하나
1634 알면 스토어 자체를 제거할 수 있습니다. 이번에도, 컴파일러는 현재의 CPU
1644 삭제할 겁니다. 만약 다른 CPU 가 그 사이 변수 'a' 에 다른 값을 썼다면
1713 READ_ONCE() 와 WRITE_ONCE() 가 일어난 순서도 지켜줍니다, CPU 는 당연히
1731 CPU 가 'b' 를 로드할 때, -- 'a' 가 0이 아닌데도 -- 가짜인 값, 42를 보게
1747 방지합니다. 예를 들어, 주어진 아키텍쳐가 7-bit imeediate field 를 갖는
1748 16-bit 스토어 인스트럭션을 제공한다면, 컴파일러는 다음의 32-bit 스토어를
1749 구현하는데에 두개의 16-bit store-immediate 명령을 사용하려 할겁니다:
1778 컴파일러는 이 세개의 대입문을 두개의 32-bit 로드와 두개의 32-bit 스토어로
1793 이 컴파일러 배리어들은 CPU 에는 직접적 효과를 전혀 만들지 않기 때문에, 결국은
1797 CPU 메모리 배리어
1798 -----------------
1800 리눅스 커널은 다음의 일곱개 기본 CPU 메모리 배리어를 가지고 있습니다:
1823 바뀌는데, 하나의 CPU 는 스스로 일관성을 유지하고, 겹치는 액세스들 역시 올바른
1835 컴파일러와 CPU 모두 재배치를 못하도록 함으로써 메모리 오퍼레이션들이 디바이스에
1864 obj->dead = 1;
1866 atomic_dec(&obj->ref_count);
1879 이것들은 CPU 와 DMA 가능한 디바이스에서 모두 액세스 가능한 공유 메모리의
1884 디스크립터가 디바이스에 속해 있는지 아니면 CPU 에 속해 있는지 표시하고,
1888 if (desc->status != DEVICE_OWN) {
1893 read_data = desc->data;
1894 desc->data = write_data;
1900 desc->status = DEVICE_OWN;
1918 위해선 Documentation/core-api/dma-api.rst 문서를 참고하세요.
1937 리턴되는 것들), CPU 는 앞의 액세스들이 뒤따르는 것들과 병합되게끔 기다릴
1939 이 매크로 앞의 쓰기-결합된 메모리 액세스들이 매크로 뒤의 것들과 병합되는
1955 -------------------
1976 (2) RELEASE 오퍼레이션의 영향:
2019 같은 락 변수에 대한 것이라면, 해당 락을 쥐고 있지 않은 다른 CPU 의 시야에는
2022 생각되어선 -안됩니다-.
2026 규정되는 크리티컬 섹션의 CPU 수행은 RELEASE 와 ACQUIRE 를 가로지를 수 있으므로,
2044 우리가 이야기 하고 있는건 재배치를 하는 CPU 에 대한 이야기이지,
2046 가 오퍼레이션들을 이렇게 재배치하면, 데드락이 일어날 수 -있습-니다.
2048 하지만 CPU 가 오퍼레이션들을 재배치 했다는걸 생각해 보세요. 이 예에서,
2049 어셈블리 코드 상으로는 언락이 락을 앞서게 되어 있습니다. CPU 가 이를
2052 시도합니다 (또는, 한참 후에겠지만, 잠듭니다). CPU 는 언젠가는
2065 그런 상황에서 인터럽트 비활성화 오퍼레이션과 함께가 아니라면 어떤 일에도 - 특히
2066 I/O 액세스와 관련해서는 - 제대로 사용될 수 없을 겁니다.
2068 "CPU 간 ACQUIRING 배리어 효과" 섹션도 참고하시기 바랍니다.
2098 ----------------------
2107 --------------------
2127 CPU 1
2131 STORE current->state
2170 CPU 1 (Sleeper) CPU 2 (Waker)
2174 STORE current->state ...
2176 LOAD event_indicated if ((LOAD task->state) & TASK_NORMAL)
2177 STORE task->state
2179 여기서 "task" 는 깨어나지는 쓰레드이고 CPU 1 의 "current" 와 같습니다.
2186 CPU 1 CPU 2
2257 -------------
2265 CPU 간 ACQUIRING 배리어의 효과
2269 배리어는 동일한 락을 사용하는 다른 CPU 들의 메모리 액세스 순서에도 영향을
2274 ------------------------
2276 다음의 예를 생각해 봅시다: 시스템은 두개의 스핀락 (M) 과 (Q), 그리고 세개의 CPU
2279 CPU 1 CPU 2
2288 *A 로의 액세스부터 *H 로의 액세스까지가 어떤 순서로 CPU 3 에게 보여질지에
2289 대해서는 각 CPU 에서의 락 사용에 의해 내포되어 있는 제약을 제외하고는 어떤
2290 보장도 존재하지 않습니다. 예를 들어, CPU 3 에게 다음과 같은 순서로 보여지는
2322 --------------------
2324 두개 이상의 프로세서를 가진 시스템이 있다면, 시스템의 두개 이상의 CPU 는 동시에
2328 경우, 두 CPU 모두에 영향을 끼치는 오퍼레이션들은 오동작을 막기 위해 신중하게
2352 (2) 이 대기 상태 프로세스의 task 구조체로의 포인터를 읽습니다;
2363 LOAD waiter->list.next;
2364 LOAD waiter->task;
2365 STORE waiter->task;
2374 _전에_ task 포인터가 지워진다면, 다른 CPU 는 해당 대기 프로세스를 시작해 버리고
2380 CPU 1 CPU 2
2386 LOAD waiter->task;
2387 STORE waiter->task;
2395 LOAD waiter->list.next;
2396 --- OOPS ---
2403 LOAD waiter->list.next;
2404 LOAD waiter->task;
2406 STORE waiter->task;
2410 이 경우에, 배리어는 시스템의 나머지 CPU 들에게 모든 배리어 앞의 메모리 액세스가
2416 컴파일러가 CPU 안에서의 순서를 바꾸거나 하지 않고 주어진 순서대로 명령을
2417 내리도록 하는 컴파일러 배리어일 뿐입니다. 오직 하나의 CPU 만 있으니, CPU
2422 -----------------
2432 ---------------
2435 디바이스는 CPU 에는 단지 특정 메모리 영역의 집합처럼 보이게 됩니다. 드라이버는
2440 영리한 CPU 나 컴파일러들을 사용하면 드라이버 코드의 조심스럽게 순서 맞춰진
2441 액세스들이 디바이스에는 요청된 순서대로 도착하지 못하게 할 수 있는 - 디바이스가
2442 오동작을 하게 할 - 잠재적 문제가 생길 수 있습니다.
2445 알고 있는, - inb() 나 writel() 과 같은 - 적절한 액세스 루틴을 통해 이루어져야만
2451 더 많은 정보를 위해선 Documentation/driver-api/device-io.rst 를 참고하십시오.
2455 --------
2463 한 형태) 으로 이런 상호 간섭을 - 최소한 부분적으로라도 - 줄일 수 있습니다.
2464 드라이버의 인터럽트 루틴이 실행 중인 동안, 해당 드라이버의 코어는 같은 CPU 에서
2490 인터럽트 내에서 일어난 액세스와 섞일 수 있다고 - 그리고 그 반대도 - 가정해야만
2498 하나의 인터럽트 루틴과 별도의 CPU 에서 수행중이며 서로 통신을 하는 두 루틴
2520 순서지어집니다. 이는 같은 CPU 쓰레드에 의한 특정 디바이스로의 MMIO
2523 2. 한 스핀락을 잡은 CPU 쓰레드에 의한 writeX() 는 같은 스핀락을 나중에
2524 잡은 다른 CPU 쓰레드에 의해 같은 주변장치를 향해 호출된 writeX()
2529 3. 특정 주변장치를 향한 특정 CPU 쓰레드의 writeX() 는 먼저 해당
2532 를 통해 할당된 전송용 DMA 버퍼로의 해당 CPU 의 쓰기가 이 CPU 가 이
2536 4. 특정 CPU 쓰레드에 의한 주변장치로의 readX() 는 같은 쓰레드에 의한
2538 dma_alloc_coherent() 를 통해 할당된 수신용 DMA 버퍼로부터의 CPU
2542 5. CPU 에 의한 주변장치로의 readX() 는 모든 뒤따르는 delay() 루프가
2543 수행을 시작하기 전에 완료됩니다. 이는 CPU 의 특정
2562 루프 (예:앞의 2-5 항목) 에 대해 순서를 보장하지 않습니다만 디폴트 I/O
2563 기능으로 매핑된 __iomem 포인터에 대해 동작할 때, 같은 CPU 쓰레드에 의한
2579 많은 CPU 아키텍쳐가 결국은 이런 주변장치를 내부의 가상 메모리 매핑을
2601 제외하고는, 앞의 모든 것이 아랫단의 주변장치가 little-endian 이라 가정하며,
2602 따라서 big-endian 아키텍쳐에서는 byte-swapping 오퍼레이션을 수행합니다.
2609 컨셉적으로 CPU 는 주어진 프로그램에 대해 프로그램 그 자체에는 인과성 (program
2611 않는다고 가정되어야만 합니다. (i386 이나 x86_64 같은) 일부 CPU 들은 코드
2616 이 말은, CPU 에게 주어지는 인스트럭션 스트림 내의 한 인스트럭션이 앞의
2619 보이게 함) 외에는 자신이 원하는 순서대로 - 심지어 병렬적으로도 - 그 스트림을
2622 [*] 일부 인스트럭션은 하나 이상의 영향 - 조건 코드를 바꾼다던지, 레지스터나
2623 메모리를 바꾼다던지 - 을 만들어내며, 다른 인스트럭션은 다른 효과에
2626 CPU 는 최종적으로 아무 효과도 만들지 않는 인스트럭션 시퀀스는 없애버릴 수도
2637 CPU 캐시의 영향
2640 캐시된 메모리 오퍼레이션들이 시스템 전체에 어떻게 인지되는지는 CPU 와 메모리
2644CPU 가 시스템의 다른 부분들과 캐시를 통해 상호작용한다면, 메모리 시스템은
2645 CPU 의 캐시들을 포함해야 하며, CPUCPU 자신의 캐시 사이에서의 동작을 위한
2649 <--- CPU ---> : <----------- Memory ----------->
2651 +--------+ +--------+ : +--------+ +-----------+
2652 | | | | : | | | | +--------+
2653 | CPU | | Memory | : | CPU | | | | |
2654 | Core |--->| Access |----->| Cache |<-->| | | |
2655 | | | Queue | : | | | |--->| Memory |
2657 +--------+ +--------+ : +--------+ | | | |
2658 : | Cache | +--------+
2660 : | Mechanism | +--------+
2661 +--------+ +--------+ : +--------+ | | | |
2663 | CPU | | Memory | : | CPU | | |--->| Device |
2664 | Core |--->| Access |----->| Cache |<-->| | | |
2666 | | | | : | | | | +--------+
2667 +--------+ +--------+ : +--------+ +-----------+
2671 특정 로드나 스토어는 해당 오퍼레이션을 요청한 CPU 의 캐시 내에서 동작을 완료할
2672 수도 있기 때문에 해당 CPU 의 바깥에는 보이지 않을 수 있지만, 다른 CPU 가 관심을
2673 갖는다면 캐시 일관성 메커니즘이 해당 캐시라인을 해당 CPU 에게 전달하고, 해당
2677 CPU 코어는 프로그램의 인과성이 유지된다고만 여겨진다면 인스트럭션들을 어떤
2683 메모리 배리어가 하는 일은 CPU 쪽에서 메모리 쪽으로 넘어가는 액세스들의 순서,
2687 [!] CPU 들은 항상 그들 자신의 로드와 스토어는 프로그램 순서대로 일어난 것으로
2688 보기 때문에, 주어진 CPU 내에서는 메모리 배리어를 사용할 필요가 _없습니다_.
2691 여부는 디바이스가 액세스 되는 메모리 윈도우의 특성에 의해 결정될 수도 있고, CPU
2697 ------------------
2701 읽을 수 있는데, 더티 캐시 라인이 CPU 의 캐시에 머무르고 있고, 바뀐 값이 아직
2703 적절한 부분에서 각 CPU 캐시의 문제되는 비트들을 플러시 (flush) 시켜야만 합니다
2704 (그리고 그것들을 무효화 - invalidation - 시킬 수도 있겠죠).
2707 CPU 의 캐시에서 RAM 으로 쓰여지는 더티 캐시 라인에 의해 덮어써질 수도 있고, CPU
2710 문제를 해결하기 위해선, 커널의 적절한 부분에서 각 CPU 의 캐시 안의 문제가 되는
2713 캐시 관리에 대한 더 많은 정보를 위해선 Documentation/core-api/cachetlb.rst 를
2718 -------------------
2720 Memory mapped I/O 는 일반적으로 CPU 의 메모리 공간 내의 한 윈도우의 특정 부분
2733 CPU 들이 저지르는 일들
2736 프로그래머는 CPU 가 메모리 오퍼레이션들을 정확히 요청한대로 수행해 줄 것이라고
2737 생각하는데, 예를 들어 다음과 같은 코드를 CPU 에게 넘긴다면:
2745 CPU 는 다음 인스트럭션을 처리하기 전에 현재의 인스트럭션을 위한 메모리
2752 당연하지만, 실제로는 훨씬 엉망입니다. 많은 CPU 와 컴파일러에서 앞의 가정은
2765 (*) 메모리 액세스 순서는 CPU 버스와 캐시를 좀 더 잘 사용할 수 있도록 재배치
2773 (*) 해당 CPU 의 데이터 캐시가 순서에 영향을 끼칠 수도 있고, 캐시 일관성
2774 메커니즘이 - 스토어가 실제로 캐시에 도달한다면 - 이 문제를 완화시킬 수는
2775 있지만 이 일관성 관리가 다른 CPU 들에도 같은 순서로 전달된다는 보장은
2778 따라서, 앞의 코드에 대해 다른 CPU 가 보는 결과는 다음과 같을 수 있습니다:
2785 하지만, CPU 는 스스로는 일관적일 것을 보장합니다: CPU _자신_ 의 액세스들은
2804 앞의 코드는 CPU 가 다음의 메모리 액세스 시퀀스를 만들도록 할겁니다:
2810 액세스들은 합쳐지거나 버려질 수 있습니다. 일부 아키텍쳐에서 CPU 는 같은 위치에
2818 컴파일러 역시 이 시퀀스의 액세스들을 CPU 가 보기도 전에 합치거나 버리거나 뒤로
2842 그리고 이 LOAD 오퍼레이션은 CPU 바깥에는 아예 보이지 않습니다.
2846 ---------------------
2848 DEC Alpha CPU 는 가장 완화된 메모리 순서의 CPU 중 하나입니다. 뿐만 아니라,
2849 Alpha CPU 의 일부 버전은 분할된 데이터 캐시를 가지고 있어서, 의미적으로
2861 ----------------
2884 -----------
2890 Documentation/core-api/circular-buffers.rst
2904 AMD64 Architecture Programmer's Manual Volume 2: System Programming
2905 Chapter 7.1: Memory-Access Ordering
2908 ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
2911 IA-32 Intel Architecture Software Developer's Manual, Volume 3:
2926 Chapter 15: Sparc-V9 Memory Models
2942 Solaris Internals, Core Kernel Architecture, p63-68: