NOTE:
This is a version of Documentation/memory-barriers.txt translated into Korean.
This document is maintained by SeongJae Park sj38.park@gmail.com.
If you find any difference between this document and the original file or
a problem with the translation, please contact the maintainer of this file.
Please also note that the purpose of this file is to be easier to
read for non English (read: Korean) speakers and is not intended as
a fork. So if you have any comments or updates for this file please
update the original English file first. The English version is
definitive, and readers should look there if they have any doubt.
===================================
ì´ ë¬¸ìë
Documentation/memory-barriers.txt
ì íê¸ ë²ìì
ëë¤.
ììï¼ ë°ì±ì¬ sj38.park@gmail.com
=========================
리ë
ì¤ ì»¤ë ë©ëª¨ë¦¬ 배리ì´
=========================
ì ì: David Howells dhowells@redhat.com
Paul E. McKenney paulmck@linux.vnet.ibm.com
Will Deacon will.deacon@arm.com
Peter Zijlstra peterz@infradead.org
========
ë©´ì±
ì¡°í
========
ì´ ë¬¸ìë ëª
ì¸ìê° ìëëë¤; ì´ ë¬¸ìë ìë²½íì§ ììë°, ê°ê²°ì±ì ìí´ ìëë
ë¶ë¶ë ìê³ , ìëíì§ ììì§ë§ ì¬ëì ìí´ ì°ìë¤ë³´ë ë¶ìì í ë¶ë¶ë ììµëë¤.
ì´ ë¬¸ìë 리ë
ì¤ìì ì ê³µíë ë¤ìí ë©ëª¨ë¦¬ 배리ì´ë¤ì ì¬ì©í기 ìí
ìë´ìì
ëë¤ë§, ëê° ì´ìíë¤ ì¶ì¼ë©´ (ê·¸ë°ê² ë§ì ê²ëë¤) ì§ë¬¸ì ë¶íë립ëë¤.
ì¼ë¶ ì´ìí ì ë¤ì ê³µìì ì¸ ë©ëª¨ë¦¬ ì¼ê´ì± 모ë¸ê³¼ tools/memory-model/ ì ìë
ê´ë ¨ 문ì를 ì°¸ê³ í´ì í´ê²°ë ì ìì ê²ëë¤. ê·¸ë¬ë, ì´ ë©ëª¨ë¦¬ 모ë¸ì¡°ì°¨ë ê·¸
ê´ë¦¬ìë¤ì ì견ì ì§í©ì¼ë¡ ë´ì¼ì§, ì ë ì³ì ìì¸ìë¡ ì ë´í´ì ìë ê²ëë¤.
ë¤ì ë§íì§ë§, ì´ ë¬¸ìë 리ë
ì¤ê° íëì¨ì´ì 기ëíë ì¬íì ëí ëª
ì¸ìê°
ìëëë¤.
ì´ ë¬¸ìì 목ì ì ëê°ì§ì ëë¤:
(1) ì´ë¤ í¹ì 배리ì´ì ëí´ ê¸°ëí ì ìë ìµìíì 기ë¥ì ëª
ì¸í기 ìí´ì,
그리ê³
(2) ì¬ì© ê°ë¥í 배리ì´ë¤ì ëí´ ì´ë»ê² ì¬ì©í´ì¼ íëì§ì ëí ìë´ë¥¼ ì ê³µí기
ìí´ì.
ì´ë¤ ìí¤í
ì³ë í¹ì í 배리ì´ë¤ì ëí´ìë ì¬ê¸°ì ì´ì¼ê¸°íë ìµìíì
ì구ì¬íë¤ë³´ë¤ ë§ì 기ë¥ì ì ê³µí ìë ììµëë¤ë§, ì¬ê¸°ì ì´ì¼ê¸°íë
ì구ì¬íë¤ì 충족íì§ ìë ìí¤í
ì³ê° ìë¤ë©´ ê·¸ ìí¤í
ì³ê° ì못ë ê²ì´ë ì ì
ììëì기 ë°ëëë¤.
ëí, í¹ì ìí¤í
ì³ìì ì¼ë¶ 배리ì´ë í´ë¹ ìí¤í
ì³ì í¹ìí ëì ë°©ìì¼ë¡ ì¸í´
í´ë¹ 배리ì´ì ëª
ìì ì¬ì©ì´ ë¶íìí´ì no-op ì´ ë ìë ììì ììëì기
ë°ëëë¤.
ìì: 본 ë²ì ìì ìë²½íì§ ììë°, ì´ ìì ë¶ë¶ì ì¼ë¡ë ìëë ê²ì´ê¸°ë
í©ëë¤. ì¬í 기ì 문ìë¤ì´ ê·¸ë ë¯ ìë²½í ì´í´ë¥¼ ìí´ìë ë²ì문과 ì문ì í¨ê»
ì½ì¼ìë ë²ì문ì íëì ê°ì´ëë¡ íì©íì길 ì¶ì²ë리며, ë°ê²¬ëë ì¤ì ë±ì
ëí´ìë ì¸ì ë ì견ì ë¶íë립ëë¤. ê³¼í ë²ìì¼ë¡ ì¸í ì¤í´ë¥¼ ìµìíí기 ìí´
ì 매í ë¶ë¶ì´ ìì ê²½ì°ìë ì´ìí¨ì´ ìëë¼ë ìëì ì©ì´ë¥¼ ì°¨ì©í©ëë¤.
=====
목차:
=====
(*) ì¶ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ 모ë¸.
- ëë°ì´ì¤ ì¤í¼ë ì´ì
.
- ë³´ì¥ì¬í.
(*) ë©ëª¨ë¦¬ 배리ì´ë 무ìì¸ê°?
- ë©ëª¨ë¦¬ 배리ì´ì ì¢
ë¥.
- ë©ëª¨ë¦¬ 배리ì´ì ëí´ ê°ì í´ì ìë ê².
- ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ (ìì¬ì ).
- 컨í¸ë¡¤ ìì¡´ì±.
- SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°.
- ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ìíì¤ì ì.
- ì½ê¸° ë©ëª¨ë¦¬ ë°°ë¦¬ì´ vs ë¡ë ì측.
- Multicopy ììì±.
(*) ëª ìì 커ë 배리ì´.
- ì»´íì¼ë¬ 배리ì´.
- CPU ë©ëª¨ë¦¬ 배리ì´.
- MMIO ì°ê¸° 배리ì´.
(*) ì묵ì 커ë ë©ëª¨ë¦¬ 배리ì´.
- ë½ Acquisition í¨ì.
- ì¸í°ë½í¸ ë¹íì±í í¨ì.
- ì¬ë¦½ê³¼ ì¨ì´í¬ì
í¨ì.
- ê·¸ì¸ì í¨ìë¤.
(*) CPU ê° ACQUIRING 배리ì´ì í¨ê³¼.
- Acquire vs ë©ëª¨ë¦¬ ì¡ì¸ì¤.
- Acquire vs I/O ì¡ì¸ì¤.
(*) ë©ëª¨ë¦¬ 배리ì´ê° íìí ê³³
- íë¡ì¸ìê° ìí¸ ìì©.
- ì´í 믹 ì¤í¼ë ì´ì
.
- ëë°ì´ì¤ ì¡ì¸ì¤.
- ì¸í°ë½í¸.
(*) 커ë I/O 배리ì´ì í¨ê³¼.
(*) ê°ì ëë ê°ì¥ ìíë ì¤í ìì 모ë¸.
(*) CPU ìºìì ìí¥.
- ìºì ì¼ê´ì±.
- ìºì ì¼ê´ì± vs DMA.
- ìºì ì¼ê´ì± vs MMIO.
(*) CPU ë¤ì´ ì ì§ë¥´ë ì¼ë¤.
- ê·¸ë¦¬ê³ , Alpha ê° ìë¤.
- ê°ì 머ì ê²ì¤í¸.
(*) ì¬ì© ì.
- ìíì ë²í¼.
(*) ì°¸ê³ ë¬¸í.
=======================
ì¶ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ 모ë¸
=======================
ë¤ìê³¼ ê°ì´ ì¶ìíë ìì¤í 모ë¸ì ìê°í´ ë´ ìë¤:
: :
: :
: :
+-------+ : +--------+ : +-------+
| | : | | : | |
| | : | | : | |
| CPU 1 |<----->| Memory |<----->| CPU 2 |
| | : | | : | |
| | : | | : | |
+-------+ : +--------+ : +-------+
^ : ^ : ^
| : | : |
| : | : |
| : v : |
| : +--------+ : |
| : | | : |
| : | | : |
+---------->| Device |<----------+
: | | :
: | | :
: +--------+ :
: :
íë¡ê·¸ë¨ì ì¬ë¬ ë©ëª¨ë¦¬ ì¡ì¸ì¤ ì¤í¼ë ì´ì
ì ë°ììí¤ê³ , ê°ê°ì CPU ë ê·¸ë°
íë¡ê·¸ë¨ë¤ì ì¤íí©ëë¤. ì¶ìíë CPU 모ë¸ìì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì ììë
ë§¤ì° ìíëì´ ìê³ , CPU ë íë¡ê·¸ë¨ì´ ì¸ê³¼ê´ê³ë¥¼ ì´ê¸°ì§ ìë ìíë¡ ê´ë¦¬ëë¤ê³
ë³´ì¼ ìë§ ìë¤ë©´ ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ì ìì ì´ ìíë ì´ë¤ ììëë¡ë ì¬ë°°ì¹í´
ëììí¬ ì ììµëë¤. ë¹ì·íê², ì»´íì¼ë¬ ëí íë¡ê·¸ë¨ì ì ìì ëìì í´ì¹ì§
ìë íë ë´ììë ì´ë¤ ììë¡ë ìì ì´ ìíë ëë¡ ì¸ì¤í¸ëì
ì ì¬ë°°ì¹ í ì
ììµëë¤.
ë°ë¼ì ìì ë¤ì´ì´ê·¸ë¨ìì í CPUê° ëììí¤ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ì´ ë§ë¤ì´ë´ë
ë³íë í´ë¹ ì¤í¼ë ì´ì
ì´ CPU ì ìì¤í
ì ë¤ë¥¸ ë¶ë¶ë¤ ì¬ì´ì ì¸í°íì´ì¤(ì ì )를
ì§ëê°ë©´ì ìì¤í
ì ëë¨¸ì§ ë¶ë¶ë¤ì ì¸ì§ë©ëë¤.
ì를 ë¤ì´, ë¤ìì ì¼ë ¨ì ì´ë²¤í¸ë¤ì ìê°í´ ë´ ìë¤:
CPU 1 CPU 2
=============== ===============
{ A == 1; B == 2 }
A = 3; x = B;
B = 4; y = A;
ë¤ì´ì´ê·¸ë¨ì ê°ì´ë°ì ìì¹í ë©ëª¨ë¦¬ ìì¤í
ì ë³´ì¬ì§ê² ëë ì¡ì¸ì¤ë¤ì ë¤ìì ì´
24ê°ì ì¡°í©ì¼ë¡ ì¬êµ¬ì±ë ì ììµëë¤:
STORE A=3, STORE B=4, y=LOAD A->3, x=LOAD B->4
STORE A=3, STORE B=4, x=LOAD B->4, y=LOAD A->3
STORE A=3, y=LOAD A->3, STORE B=4, x=LOAD B->4
STORE A=3, y=LOAD A->3, x=LOAD B->2, STORE B=4
STORE A=3, x=LOAD B->2, STORE B=4, y=LOAD A->3
STORE A=3, x=LOAD B->2, y=LOAD A->3, STORE B=4
STORE B=4, STORE A=3, y=LOAD A->3, x=LOAD B->4
STORE B=4, ...
...
ë°ë¼ì ë¤ìì ë¤ê°ì§ ì¡°í©ì ê°ë¤ì´ ëì¬ ì ììµëë¤:
x == 2, y == 1
x == 2, y == 3
x == 4, y == 1
x == 4, y == 3
íë° ë ëìê°ì, í CPU ê° ë©ëª¨ë¦¬ ìì¤í
ì ë°ìí ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì ê²°ê³¼ë
ë¤ë¥¸ CPU ììì ë¡ë ì¤í¼ë ì´ì
ì íµí´ ì¸ì§ëëë°, ì´ ë ì¤í ì´ê° ë°ìë ììì
ë¤ë¥¸ ììë¡ ì¸ì§ë ìë ììµëë¤.
ìë¡, ìëì ì¼ë ¨ì ì´ë²¤í¸ë¤ì ìê°í´ ë´ ìë¤:
CPU 1 CPU 2
=============== ===============
{ A == 1, B == 2, C == 3, P == &A, Q == &C }
B = 4; Q = P;
P = &B D = *Q;
D ë¡ ì½íì§ë ê°ì CPU 2 ìì P ë¡ë¶í° ì½íì§ ì£¼ìê°ì ìì¡´ì ì´ê¸° ë문ì ì¬ê¸°ì
ë¶ëª
í ë°ì´í° ìì¡´ì±ì´ ììµëë¤. íì§ë§ ì´ ì´ë²¤í¸ë¤ì ì¤í ê²°ê³¼ë¡ë ìëì
ê²°ê³¼ë¤ì´ 모ë ëíë ì ììµëë¤:
(Q == &A) and (D == 1)
(Q == &B) and (D == 2)
(Q == &B) and (D == 4)
CPU 2 ë *Q ì ë¡ë를 ìì²í기 ì ì P 를 Q ì ë£ê¸° ë문ì D ì C 를 ì§ì´ë£ë
ì¼ì ììì ììëì¸ì.
ëë°ì´ì¤ ì¤í¼ë ì´ì
ì¼ë¶ ëë°ì´ì¤ë ìì ì 컨í¸ë¡¤ ì¸í°íì´ì¤ë¥¼ ë©ëª¨ë¦¬ì í¹ì ììì¼ë¡ 매íí´ì
ì ê³µíëë°(Memory mapped I/O), í´ë¹ 컨í¸ë¡¤ ë ì§ì¤í°ì ì ê·¼íë ììë 매ì°
ì¤ìí©ëë¤. ì를 ë¤ì´, ì´ëë ì¤ í¬í¸ ë ì§ì¤í° (A) ì ë°ì´í° í¬í¸ ë ì§ì¤í° (D)
를 íµí´ ì ê·¼ëë ë´ë¶ ë ì§ì¤í° ì§í©ì ê°ë ì´ëë· ì¹´ë를 ìê°í´ ë´
ìë¤. ë´ë¶ì
5ë² ë ì§ì¤í°ë¥¼ ì½ê¸° ìí´ ë¤ìì ì½ëê° ì¬ì©ë ì ììµëë¤:
*A = 5;
x = *D;
íì§ë§, ì´ê±´ ë¤ìì ë ì¡°í© ì¤ íëë¡ ë§ë¤ì´ì§ ì ììµëë¤:
STORE *A = 5, x = LOAD *D
x = LOAD *D, STORE *A = 5
ëë²ì§¸ ì¡°í©ì ë°ì´í°ë¥¼ ì½ì´ì¨ íì 주ì를 ì¤ì íë¯ë¡, ì¤ëìì ì¼ì¼í¬ ê²ëë¤.
ë³´ì¥ì¬í
CPU ìê² ê¸°ëí ì ìë ìµìíì ë³´ì¥ì¬í ëªê°ì§ê° ììµëë¤:
(*) ì´ë¤ CPU ë , ìì¡´ì±ì´ ì¡´ì¬íë ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¤ì í´ë¹ CPU ìì ìê²
ìì´ìë ììëë¡ ë©ëª¨ë¦¬ ìì¤í
ì ìí ìì²ë©ëë¤. ì¦, ë¤ìì ëí´ì:
Q = READ_ONCE(P); D = READ_ONCE(*Q);
CPU ë ë¤ìê³¼ ê°ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ìíì¤ë¥¼ ìí ìì²í©ëë¤:
Q = LOAD P, D = LOAD *Q
ê·¸ë¦¬ê³ ê·¸ ìíì¤ ë´ììì ììë íì ì§ì¼ì§ëë¤. íì§ë§, DEC Alpha ìì
READ_ONCE() ë ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ëª
ë ¹ë ë´ê² ëì´ ìì´ì, DEC Alpha CPU ë
ë¤ìê³¼ ê°ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì ë´ëê² ë©ëë¤:
Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER
DEC Alpha ìì ìíëë ìëë , READ_ONCE() ë ì»´íì¼ë¬ë¡ë¶í°ì ì
ìí¥
ëí ì ê±°í©ëë¤.
(*) í¹ì CPU ë´ìì ê²¹ì¹ë ììì ë©ëª¨ë¦¬ì íí´ì§ë ë¡ëì ì¤í ì´ ë¤ì í´ë¹
CPU ìììë ììê° ë°ëì§ ìì ê²ì¼ë¡ ë³´ì¬ì§ëë¤. ì¦, ë¤ìì ëí´ì:
a = READ_ONCE(*X); WRITE_ONCE(*X, b);
CPU ë ë¤ìì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ìíì¤ë§ì ë©ëª¨ë¦¬ì ìì²í ê²ëë¤:
a = LOAD *X, STORE *X = b
ê·¸ë¦¬ê³ ë¤ìì ëí´ìë:
WRITE_ONCE(*X, c); d = READ_ONCE(*X);
CPU ë ë¤ìì ìí ìì²ë§ì ë§ë¤ì´ ë
ëë¤:
STORE *X = c, d = LOAD *X
(ë¡ë ì¤í¼ë ì´ì
ê³¼ ì¤í ì´ ì¤í¼ë ì´ì
ì´ ê²¹ì¹ë ë©ëª¨ë¦¬ ììì ëí´
ìíëë¤ë©´ í´ë¹ ì¤í¼ë ì´ì
ë¤ì ê²¹ì¹ë¤ê³ ííë©ëë¤).
ê·¸ë¦¬ê³ ë°ëì ëë ì ëë¡ ê°ì íê±°ë ê°ì íì§ ë§ìì¼ íë ê²ë¤ì´ ììµëë¤:
(*) ì»´íì¼ë¬ê° READ_ONCE() ë WRITE_ONCE() ë¡ ë³´í¸ëì§ ìì ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¥¼
ë¹ì ì´ ìíë ëë¡ í ê²ì´ë¼ë ê°ì ì ì ëë¡ í´ì ìë©ëë¤. ê·¸ê²ë¤ì´
ìë¤ë©´, ì»´íì¼ë¬ë ì»´íì¼ë¬ ë°°ë¦¬ì´ ì¹ì
ìì ë¤ë£¨ê² ë , ëª¨ë “ì°½ìì 츔
ë³ê²½ë¤ì ë§ë¤ì´ë¼ ê¶íì ê°ê² ë©ëë¤.
(*) ê°ë³ì ì¸ ë¡ëì ì¤í ì´ë¤ì´ 주ì´ì§ ììëë¡ ìì²ë ê²ì´ë¼ë ê°ì ì ì ëë¡
íì§ ë§ìì¼ í©ëë¤. ì´ ë§ì 곧:
X = *A; Y = *B; *D = Z;
ë ë¤ìì ê²ë¤ ì¤ ì´ë ê²ì¼ë¡ë ë§ë¤ì´ì§ ì ìë¤ë ì미ì
ëë¤:
X = LOAD *A, Y = LOAD *B, STORE *D = Z
X = LOAD *A, STORE *D = Z, Y = LOAD *B
Y = LOAD *B, X = LOAD *A, STORE *D = Z
Y = LOAD *B, STORE *D = Z, X = LOAD *A
STORE *D = Z, X = LOAD *A, Y = LOAD *B
STORE *D = Z, Y = LOAD *B, X = LOAD *A
(*) ê²¹ì¹ë ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¤ì í©ì³ì§ê±°ë ë²ë ¤ì§ ì ììì ë°ëì ê°ì í´ì¼
í©ëë¤. ë¤ìì ì½ëë:
X = *A; Y = *(A + 4);
ë¤ìì ê²ë¤ ì¤ ëë ë ì ììµëë¤:
X = LOAD *A; Y = LOAD *(A + 4);
Y = LOAD *(A + 4); X = LOAD *A;
{X, Y} = LOAD {*A, *(A + 4) };
ê·¸ë¦¬ê³ :
*A = X; *(A + 4) = Y;
ë ë¤ì ì¤ ëë ë ì ììµëë¤:
STORE *A = X; STORE *(A + 4) = Y;
STORE *(A + 4) = Y; STORE *A = X;
STORE {*A, *(A + 4) } = {X, Y};
ê·¸ë¦¬ê³ ë³´ì¥ì¬íì ë°ëëë ê²ë¤(anti-guarantees)ì´ ììµëë¤:
(*) ì´ ë³´ì¥ì¬íë¤ì bitfield ìë ì ì©ëì§ ìëë°, ì»´íì¼ë¬ë¤ì bitfield 를
ìì íë ì½ë를 ìì±í ë ììì± ìë(non-atomic) ì½ê³ -ìì íê³ -ì°ë
ì¸ì¤í¸ëì
ë¤ì ì¡°í©ì ë§ëë ê²½ì°ê° ë§ê¸° ë문ì
ëë¤. ë³ë ¬ ìê³ ë¦¬ì¦ì
ë기íì bitfield 를 ì¬ì©íë ¤ íì§ ë§ììì¤.
(*) bitfield ë¤ì´ ì¬ë¬ ë½ì¼ë¡ ë³´í¸ëë ê²½ì°ë¼ íëë¼ë, íëì bitfield ì
모ë íëë¤ì íëì ë½ì¼ë¡ ë³´í¸ëì´ì¼ í©ëë¤. ë§ì½ í bitfield ì ë
íëê° ìë¡ ë¤ë¥¸ ë½ì¼ë¡ ë³´í¸ëë¤ë©´, ì»´íì¼ë¬ì ììì± ìë
ì½ê³ -ìì íê³ -ì°ë ì¸ì¤í¸ëì
ì¡°í©ì í íëìì ì
ë°ì´í¸ê° ê·¼ì²ì
íëìë ìí¥ì ë¼ì¹ê² í ì ììµëë¤.
(*) ì´ ë³´ì¥ì¬íë¤ì ì ì íê² ì ë ¬ëê³ í¬ê¸°ê° ì¡í ì¤ì¹¼ë¼ ë³ìë¤ì ëí´ìë§
ì ì©ë©ëë¤. “ì ì íê² í¬ê¸°ê° ì¡í” ì´ë¼í¨ì íì¬ë¡ì¨ë “char”, “short”,
“int” ê·¸ë¦¬ê³ “long” ê³¼ ê°ì í¬ê¸°ì ë³ìë¤ì ì미í©ëë¤. “ì ì íê² ì ë ¬ë”
ì ìì°ì¤ë° ì ë ¬ì ì미íëë°, ë°ë¼ì “char” ì ëí´ìë ì무 ì ì½ì´ ìê³ ,
“short” ì ëí´ìë 2ë°ì´í¸ ì ë ¬ì, “int” ìë 4ë°ì´í¸ ì ë ¬ì, 그리ê³
“long” ì ëí´ìë 32-bit ìì¤í
ì¸ì§ 64-bit ìì¤í
ì¸ì§ì ë°ë¼ 4ë°ì´í¸ ëë
8ë°ì´í¸ ì ë ¬ì ì미í©ëë¤. ì´ ë³´ì¥ì¬íë¤ì C11 íì¤ìì ìê°ëìì¼ë¯ë¡,
C11 ì ì ì¤ëë ì»´íì¼ë¬(ì를 ë¤ì´, gcc 4.6) 를 ì¬ì©í ëì 주ìíì기
ë°ëëë¤. íì¤ì ì´ ë³´ì¥ì¬íë¤ì “memory location” ì ì ìíë 3.14
ì¹ì
ì ë¤ìê³¼ ê°ì´ ì¤ëª
ëì´ ììµëë¤:
(ìì: ì¸ì©ë¬¸ì´ë¯ë¡ ë²ìíì§ ììµëë¤)
memory location
either an object of scalar type, or a maximal sequence
of adjacent bit-fields all having nonzero width
NOTE 1: Two threads of execution can update and access
separate memory locations without interfering with
each other.
NOTE 2: A bit-field and an adjacent non-bit-field member
are in separate memory locations. The same applies
to two bit-fields, if one is declared inside a nested
structure declaration and the other is not, or if the two
are separated by a zero-length bit-field declaration,
or if they are separated by a non-bit-field member
declaration. It is not safe to concurrently update two
bit-fields in the same structure if all members declared
between them are also bit-fields, no matter what the
sizes of those intervening bit-fields happen to be.
=========================
ë©ëª¨ë¦¬ 배리ì´ë 무ìì¸ê°?
=========================
ììì ë´¤ë¯ì´, ìí¸ê° ìì¡´ì±ì´ ìë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì ì¤ì ë¡ë 무ììì
ììë¡ ìíë ì ìì¼ë©°, ì´ë CPU ì CPU ê°ì ìí¸ìì©ì´ë I/O ì 문ì ê° ë ì
ììµëë¤. ë°ë¼ì ì»´íì¼ë¬ì CPU ê° ìì를 ë°ê¾¸ëë° ì ì½ì 걸 ì ìëë¡ ê°ì
í
ì ìë ì´ë¤ ë°©ë²ì´ íìí©ëë¤.
ë©ëª¨ë¦¬ 배리ì´ë ê·¸ë° ê°ì
ìë¨ì
ëë¤. ë©ëª¨ë¦¬ 배리ì´ë 배리ì´ë¥¼ ì¬ì´ì ë ìê³¼
ë¤ ì측ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ ê°ì ë¶ë¶ì ììê° ì¡´ì¬íëë¡ íë í¨ê³¼ë¥¼ ì¤ëë¤.
ìì¤í
ì CPU ë¤ê³¼ ì¬ë¬ ëë°ì´ì¤ë¤ì ì±ë¥ì ì¬ë¦¬ê¸° ìí´ ëª
ë ¹ì´ ì¬ë°°ì¹, ì¤í
ì ì, ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì ì¡°í©, ì측ì ë¡ë(speculative load), ë¸ëì¹
ì측(speculative branch prediction), ë¤ìí ì¢
ë¥ì ìºì±(caching) ë±ì ë¤ìí
í¸ë¦ì ì¬ì©í ì ì기 ë문ì ì´ë° ê°ì ë ¥ì ì¤ìí©ëë¤. ë©ëª¨ë¦¬ 배리ì´ë¤ì ì´ë°
í¸ë¦ë¤ì 무í¨ë¡ íê±°ë ìµì íë 목ì ì¼ë¡ ì¬ì©ëì´ì ¸ì ì½ëê° ì¬ë¬ CPU ì
ëë°ì´ì¤ë¤ ê°ì ìí¸ìì©ì ì ìì ì¼ë¡ ì ì´í ì ìê² í´ì¤ëë¤.
ë©ëª¨ë¦¬ 배리ì´ì ì¢ ë¥
ë©ëª¨ë¦¬ 배리ì´ë ë¤ê°ì 기본 íì ì¼ë¡ ë¶ë¥ë©ëë¤:
(1) ì°ê¸° (ëë ì¤í ì´) ë©ëª¨ë¦¬ 배리ì´.
ì°ê¸° ë©ëª¨ë¦¬ 배리ì´ë ìì¤í
ì ë¤ë¥¸ ì»´í¬ëí¸ë¤ì í´ë¹ 배리ì´ë³´ë¤ ìì
ëª
ìë 모ë STORE ì¤í¼ë ì´ì
ë¤ì´ í´ë¹ ë°°ë¦¬ì´ ë¤ì ëª
ìë 모ë STORE
ì¤í¼ë ì´ì
ë¤ë³´ë¤ 먼ì ìíë ê²ì¼ë¡ ë³´ì¼ ê²ì ë³´ì¥í©ëë¤.
ì°ê¸° 배리ì´ë ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì ëí ë¶ë¶ì ìì ì¸ì°ê¸°ì
ëë¤; ë¡ë
ì¤í¼ë ì´ì
ë¤ì ëí´ìë ì´ë¤ ìí¥ë ë¼ì¹ì§ ììµëë¤.
CPU ë ìê°ì íë¦ì ë°ë¼ ë©ëª¨ë¦¬ ìì¤í
ì ì¼ë ¨ì ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì
íëì© ìì²í´ ì§ì´ë£ìµëë¤. ì°ê¸° ë°°ë¦¬ì´ ìì 모ë ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì
ì°ê¸° ë°°ë¦¬ì´ ë¤ì 모ë ì¤í ì´ ì¤í¼ë ì´ì
ë¤ë³´ë¤ _ìì_ ìíë ê²ëë¤.
[!] ì°ê¸° 배리ì´ë¤ì ì½ê¸° ëë ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ì í¨ê» ì§ì ë§ì¶°
ì¬ì©ëì´ì¼ë§ í¨ì ììëì¸ì; "SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°" ìë¸ì¹ì
ì ì°¸ê³ íì¸ì.
(2) ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´.
ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ì½ê¸° 배리ì´ì ë³´ë¤ ìíë ííì
ëë¤. ëê°ì ë¡ë
ì¤í¼ë ì´ì
ì´ ìê³ ëë²ì§¸ ê²ì´ 첫ë²ì§¸ ê²ì ê²°ê³¼ì ìì¡´íê³ ìì ë(ì:
ëë²ì§¸ ë¡ëê° ì°¸ì¡°í 주ì를 첫ë²ì§¸ ë¡ëê° ì½ë ê²½ì°), ëë²ì§¸ ë¡ëê° ì½ì´ì¬
ë°ì´í°ë 첫ë²ì§¸ ë¡ëì ìí´ ê·¸ 주ìê° ì»ì´ì§ ë¤ì ì
ë°ì´í¸ ë¨ì ë³´ì¥í기
ìí´ì ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ê° íìí ì ììµëë¤.
ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ìí¸ ìì¡´ì ì¸ ë¡ë ì¤í¼ë ì´ì
ë¤ ì¬ì´ì ë¶ë¶ì ìì
ì¸ì°ê¸°ì
ëë¤; ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì´ë ë
립ì ì¸ ë¡ëë¤, ëë ì¤ë³µëë
ë¡ëë¤ì ëí´ìë ì´ë¤ ìí¥ë ë¼ì¹ì§ ììµëë¤.
(1) ìì ì¸ê¸íë¯ì´, ìì¤í
ì CPU ë¤ì ë©ëª¨ë¦¬ ìì¤í
ì ì¼ë ¨ì ì¤í ì´
ì¤í¼ë ì´ì
ë¤ì ëì ¸ ë£ê³ ìì¼ë©°, 거기ì ê´ì¬ì´ ìë ë¤ë¥¸ CPU ë ê·¸
ì¤í¼ë ì´ì
ë¤ì ë©ëª¨ë¦¬ ìì¤í
ì´ ì¤íí 결과를 ì¸ì§í ì ììµëë¤. ì´ì²ë¼
ë¤ë¥¸ CPU ì ì¤í ì´ ì¤í¼ë ì´ì
ì ê²°ê³¼ì ê´ì¬ì ëê³ ìë CPU ê° ìí ìì²í
ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë, ë°°ë¦¬ì´ ìì ì´ë¤ ë¡ë ì¤í¼ë ì´ì
ì´ ë¤ë¥¸ CPU ìì
ëì ¸ ë£ì ì¤í ì´ ì¤í¼ë ì´ì
ê³¼ ê°ì ììì í¥íë¤ë©´, ê·¸ë° ì¤í ì´
ì¤í¼ë ì´ì
ë¤ì´ ë§ë¤ì´ë´ë ê²°ê³¼ê° ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ ë¤ì ë¡ë
ì¤í¼ë ì´ì
ë¤ìê²ë ë³´ì¼ ê²ì ë³´ì¥í©ëë¤.
ì´ ìì ì¸ì°ê¸° ì ì½ì ëí 그림ì 보기 ìí´ì "ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ìíì¤ì ì"
ìë¸ì¹ì
ì ì°¸ê³ íì기 ë°ëëë¤.
[!] 첫ë²ì§¸ ë¡ëë ë°ëì _ë°ì´í°_ ìì¡´ì±ì ê°ì ¸ì¼ì§ 컨í¸ë¡¤ ìì¡´ì±ì ê°ì ¸ì¼
íëê² ìëì ììëììì¤. ë§ì½ ëë²ì§¸ ë¡ë를 ìí 주ìê° ì²«ë²ì§¸ ë¡ëì
ìì¡´ì ì´ì§ë§ ê·¸ ìì¡´ì±ì ì¡°ê±´ì ì´ì§ ê·¸ 주ì ì체를 ê°ì ¸ì¤ëê² ìëë¼ë©´,
ê·¸ê²ì _컨í¸ë¡¤_ ìì¡´ì±ì´ê³ , ì´ ê²½ì°ìë ì½ê¸° 배리ì´ë ê·¸ë³´ë¤ ê°ë ¥í
무ì¸ê°ê° íìí©ëë¤. ë ìì¸í ë´ì©ì ìí´ìë "컨í¸ë¡¤ ìì¡´ì±" ìë¸ì¹ì
ì
ì°¸ê³ íì기 ë°ëëë¤.
[!] ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ë³´íµ ì°ê¸° 배리ì´ë¤ê³¼ í¨ê» ì§ì ë§ì¶° ì¬ì©ëì´ì¼
í©ëë¤; "SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°" ìë¸ì¹ì
ì ì°¸ê³ íì¸ì.
(3) ì½ê¸° (ëë ë¡ë) ë©ëª¨ë¦¬ 배리ì´.
ì½ê¸° 배리ì´ë ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ ê¸°ë¥ì ë³´ì¥ì¬íì ëí´ì 배리ì´ë³´ë¤
ìì ëª
ìë 모ë LOAD ì¤í¼ë ì´ì
ë¤ì´ ë°°ë¦¬ì´ ë¤ì ëª
ìëë 모ë LOAD
ì¤í¼ë ì´ì
ë¤ë³´ë¤ 먼ì íí´ì§ ê²ì¼ë¡ ìì¤í
ì ë¤ë¥¸ ì»´í¬ëí¸ë¤ì ë³´ì¬ì§ ê²ì
ë³´ì¥í©ëë¤.
ì½ê¸° 배리ì´ë ë¡ë ì¤í¼ë ì´ì
ì íí´ì§ë ë¶ë¶ì ìì ì¸ì°ê¸°ì
ëë¤; ì¤í ì´
ì¤í¼ë ì´ì
ì ëí´ìë ì´ë¤ ìí¥ë ë¼ì¹ì§ ììµëë¤.
ì½ê¸° ë©ëª¨ë¦¬ 배리ì´ë ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë¥¼ ë´ì¥íë¯ë¡ ë°ì´í° ìì¡´ì±
배리ì´ë¥¼ ëì í ì ììµëë¤.
[!] ì½ê¸° 배리ì´ë ì¼ë°ì ì¼ë¡ ì°ê¸° 배리ì´ë¤ê³¼ í¨ê» ì§ì ë§ì¶° ì¬ì©ëì´ì¼
í©ëë¤; "SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°" ìë¸ì¹ì
ì ì°¸ê³ íì¸ì.
(4) ë²ì© ë©ëª¨ë¦¬ 배리ì´.
ë²ì©(general) ë©ëª¨ë¦¬ 배리ì´ë 배리ì´ë³´ë¤ ìì ëª
ìë 모ë LOAD ì STORE
ì¤í¼ë ì´ì
ë¤ì´ ë°°ë¦¬ì´ ë¤ì ëª
ìë 모ë LOAD ì STORE ì¤í¼ë ì´ì
ë¤ë³´ë¤
먼ì ìíë ê²ì¼ë¡ ìì¤í
ì ëë¨¸ì§ ì»´í¬ëí¸ë¤ì ë³´ì´ê² ë¨ì ë³´ì¥í©ëë¤.
ë²ì© ë©ëª¨ë¦¬ 배리ì´ë ë¡ëì ì¤í ì´ ëª¨ëì ëí ë¶ë¶ì ìì ì¸ì°ê¸°ì
ëë¤.
ë²ì© ë©ëª¨ë¦¬ 배리ì´ë ì½ê¸° ë©ëª¨ë¦¬ 배리ì´, ì°ê¸° ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ëª¨ë를
ë´ì¥íë¯ë¡, ë 배리ì´ë¥¼ 모ë ëì í ì ììµëë¤.
ê·¸ë¦¬ê³ ëê°ì ëª ìì ì´ì§ ìì íì ì´ ììµëë¤:
(5) ACQUIRE ì¤í¼ë ì´ì .
ì´ íì
ì ì¤í¼ë ì´ì
ì ë¨ë°©í¥ì í¬ê³¼ì± 배리ì´ì²ë¼ ëìí©ëë¤. ACQUIRE
ì¤í¼ë ì´ì
ë¤ì 모ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì´ ACQUIRE ì¤í¼ë ì´ì
íì
ì¼ì´ë ê²ì¼ë¡ ìì¤í
ì ëë¨¸ì§ ì»´í¬ëí¸ë¤ì ë³´ì´ê² ë ê²ì´ ë³´ì¥ë©ëë¤.
LOCK ì¤í¼ë ì´ì
ê³¼ smp_load_acquire(), smp_cond_acquire() ì¤í¼ë ì´ì
ë
ACQUIRE ì¤í¼ë ì´ì
ì í¬í¨ë©ëë¤. smp_cond_acquire() ì¤í¼ë ì´ì
ì 컨í¸ë¡¤
ìì¡´ì±ê³¼ smp_rmb() 를 ì¬ì©í´ì ACQUIRE ì ì미ì ì구ì¬í(semantic)ì
충족ìíµëë¤.
ACQUIRE ì¤í¼ë ì´ì
ìì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì ACQUIRE ì¤í¼ë ì´ì
ìë£ íì
ìíë ê²ì²ë¼ ë³´ì¼ ì ììµëë¤.
ACQUIRE ì¤í¼ë ì´ì
ì ê±°ì íì RELEASE ì¤í¼ë ì´ì
ê³¼ ì§ì ì§ì´ ì¬ì©ëì´ì¼
í©ëë¤.
(6) RELEASE ì¤í¼ë ì´ì .
ì´ íì
ì ì¤í¼ë ì´ì
ë¤ë ë¨ë°©í¥ í¬ê³¼ì± 배리ì´ì²ë¼ ëìí©ëë¤. RELEASE
ì¤í¼ë ì´ì
ìì 모ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì RELEASE ì¤í¼ë ì´ì
ì ì ìë£ë
ê²ì¼ë¡ ìì¤í
ì ë¤ë¥¸ ì»´í¬ëí¸ë¤ì ë³´ì¬ì§ ê²ì´ ë³´ì¥ë©ëë¤. UNLOCK ë¥ì
ì¤í¼ë ì´ì
ë¤ê³¼ smp_store_release() ì¤í¼ë ì´ì
ë RELEASE ì¤í¼ë ì´ì
ì
ì¼ì¢
ì
ëë¤.
RELEASE ì¤í¼ë ì´ì
ë¤ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì RELEASE ì¤í¼ë ì´ì
ì´
ìë£ë기 ì ì íí´ì§ ê²ì²ë¼ ë³´ì¼ ì ììµëë¤.
ACQUIRE ì RELEASE ì¤í¼ë ì´ì
ì ì¬ì©ì ì¼ë°ì ì¼ë¡ ë¤ë¥¸ ë©ëª¨ë¦¬ 배리ì´ì
íìì±ì ìì±ëë¤ (íì§ë§ "MMIO ì°ê¸° 배리ì´" ìë¸ì¹ì
ìì ì¤ëª
ëë ìì¸ë¥¼
ììëì¸ì). ëí, RELEASE+ACQUIRE ì¡°í©ì ë²ì© ë©ëª¨ë¦¬ 배리ì´ì²ë¼ ëìí
ê²ì ë³´ì¥íì§ -ììµëë¤-. íì§ë§, ì´ë¤ ë³ìì ëí RELEASE ì¤í¼ë ì´ì
ì
ììë ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¤ì ìí ê²°ê³¼ë ì´ RELEASE ì¤í¼ë ì´ì
ì ë¤ì´ì´ ê°ì
ë³ìì ëí´ ìíë ACQUIRE ì¤í¼ë ì´ì
ì ë¤ë°ë¥´ë ë©ëª¨ë¦¬ ì¡ì¸ì¤ìë ë³´ì¬ì§
ê²ì´ ë³´ì¥ë©ëë¤. ë¤ë¥´ê² ë§íìë©´, 주ì´ì§ ë³ìì í¬ë¦¬í°ì»¬ ì¹ì
ììë, í´ë¹
ë³ìì ëí ìì í¬ë¦¬í°ì»¬ ì¹ì
ììì 모ë ì¡ì¸ì¤ë¤ì´ ìë£ëìì ê²ì
ë³´ì¥í©ëë¤.
ì¦, ACQUIRE ë ìµìíì "ì·¨ë" ëìì²ë¼, ê·¸ë¦¬ê³ RELEASE ë ìµìíì "ê³µê°"
ì²ë¼ ëìíë¤ë ì미ì
ëë¤.
atomic_t.txt ì ì¤ëª
ë ì´í 믹 ì¤í¼ë ì´ì
ë¤ ì¤ ì¼ë¶ë ìì í ììì¡í ê²ë¤ê³¼
(배리ì´ë¥¼ ì¬ì©íì§ ìë) ìíë ììì ê²ë¤ ì¸ì ACQUIRE ì RELEASE ë¶ë¥ì
ê²ë¤ë ì¡´ì¬í©ëë¤. ë¡ëì ì¤í ì´ë¥¼ 모ë ìííë ì¡°í©ë ì´í 믹 ì¤í¼ë ì´ì
ìì,
ACQUIRE ë í´ë¹ ì¤í¼ë ì´ì
ì ë¡ë ë¶ë¶ìë§ ì ì©ëê³ RELEASE ë í´ë¹
ì¤í¼ë ì´ì
ì ì¤í ì´ ë¶ë¶ìë§ ì ì©ë©ëë¤.
ë©ëª¨ë¦¬ 배리ì´ë¤ì ë CPU ê°, ëë CPU ì ëë°ì´ì¤ ê°ì ìí¸ìì©ì ê°ë¥ì±ì´ ìì
ëìë§ íìí©ëë¤. ë§ì½ ì´ë¤ ì½ëì ê·¸ë° ìí¸ìì©ì´ ìì ê²ì´ ë³´ì¥ëë¤ë©´, í´ë¹
ì½ëììë ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì¬ì©í íìê° ììµëë¤.
ì´ê²ë¤ì ìµìíì ë³´ì¥ì¬íë¤ìì ììëì¸ì. ë¤ë¥¸ ìí¤í
ì³ììë ë ê°ë ¥í
ë³´ì¥ì¬íì ì ê³µí ìë ììµëë¤ë§, ê·¸ë° ë³´ì¥ì¬íì ìí¤í
ì³ ì¢
ìì ì½ë ì´ì¸ì
ë¶ë¶ììë ì 뢰ëì§ ìì ê²ëë¤.
ë©ëª¨ë¦¬ 배리ì´ì ëí´ ê°ì í´ì ìë ê²
리ë ì¤ ì»¤ë ë©ëª¨ë¦¬ 배리ì´ë¤ì´ ë³´ì¥íì§ ìë ê²ë¤ì´ ììµëë¤:
(*) ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ììì ëª
ìë ì´ë¤ ë©ëª¨ë¦¬ ì¡ì¸ì¤ë ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ëª
ë ¹ì ìí
ìë£ ìì ê¹ì§ ìë£ ë ê²ì´ë ë³´ì¥ì ììµëë¤; 배리ì´ê° íë ì¼ì CPU ì
ì¡ì¸ì¤ íì í¹ì íì
ì ì¡ì¸ì¤ë¤ì ëì ì ìë ì ì ê¸ë ê²ì¼ë¡ ìê°ë ì
ììµëë¤.
(*) í CPU ìì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ìííëê² ìì¤í
ì ë¤ë¥¸ CPU ë íëì¨ì´ì
ì´ë¤ ì§ì ì ì¸ ìí¥ì ë¼ì¹ë¤ë ë³´ì¥ì ì¡´ì¬íì§ ììµëë¤. ë°°ë¦¬ì´ ìíì´
ë§ëë ê°ì ì ìí¥ì ëë²ì§¸ CPU ê° ì²«ë²ì§¸ CPU ì ì¡ì¸ì¤ë¤ì 결과를
ë°ë¼ë³´ë ììê° ë©ëë¤ë§, ë¤ì í목ì ë³´ì¸ì:
(*) 첫ë²ì§¸ CPU ê° ëë²ì§¸ CPU ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¤ì 결과를 ë°ë¼ë³¼ ë, ì¤ë ¹
ëë²ì§¸ CPU ê° ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì¬ì©íë¤ í´ë, 첫ë²ì§¸ CPU ëí ê·¸ì ë§ë
ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì¬ì©íì§ ìëë¤ë©´ (“SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°” ìë¸ì¹ì
ì
ì°¸ê³ íì¸ì) ê·¸ ê²°ê³¼ê° ì¬ë°ë¥¸ ììë¡ ë³´ì¬ì§ë¤ë ë³´ì¥ì ììµëë¤.
() CPU ë°ê¹¥ì íëì¨ì´[] ê° ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¤ì ìì를 ë°ê¾¸ì§ ìëë¤ë ë³´ì¥ì
ì¡´ì¬íì§ ììµëë¤. CPU ìºì ì¼ê´ì± ë©ì»¤ëì¦ì ë©ëª¨ë¦¬ 배리ì´ì ê°ì ì
ìí¥ì CPU ì¬ì´ì ì íí긴 íì§ë§, ììëë¡ ì ííì§ë ìì ì ììµëë¤.
[*] ë²ì¤ ë§ì¤í°ë§ DMA ì ì¼ê´ì±ì ëí´ìë ë¤ìì ì°¸ê³ íì기 ë°ëëë¤:
Documentation/PCI/pci.txt
Documentation/DMA-API-HOWTO.txt
Documentation/DMA-API.txt
ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ (ìì¬ì )
리ë
ì¤ ì»¤ë v4.15 기ì¤ì¼ë¡, smp_read_barrier_depends() ê° READ_ONCE() ì
ì¶ê°ëìëë°, ì´ë ì´ ì¹ì
ì 주ì를 기ì¸ì¬ì¼ íë ì¬ëë¤ì DEC Alpha ìí¤í
ì³
ì ì© ì½ë를 ë§ëë ì¬ëë¤ê³¼ READ_ONCE() ì체를 ë§ëë ì¬ëë¤ ë¿ìì ì미í©ëë¤.
ê·¸ë° ë¶ë¤ì ìí´, ê·¸ë¦¬ê³ ìì¬ì ê´ì¬ ìë ë¶ë¤ì ìí´, ì¬ê¸° ë°ì´í° ìì¡´ì±
배리ì´ì ëí ì´ì¼ê¸°ë¥¼ ì ìµëë¤.
ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ì ì¬ì©ì ìì´ ì§ì¼ì¼ íë ì¬íë¤ì ì½ê° 미ë¬íê³ , ë°ì´í°
ìì¡´ì± ë°°ë¦¬ì´ê° ì¬ì©ëì´ì¼ íë ìí©ë íì ëª
ë°±íì§ë ììµëë¤. ì¤ëª
ì ìí´
ë¤ìì ì´ë²¤í¸ ìíì¤ë¥¼ ìê°í´ ë´
ìë¤:
CPU 1 CPU 2
=============== ===============
{ A == 1, B == 2, C == 3, P == &A, Q == &C }
B = 4;
<ì°ê¸° 배리ì´>
WRITE_ONCE(P, &B)
Q = READ_ONCE(P);
D = *Q;
ì¬ê¸°ì ë¶ëª
í ë°ì´í° ìì¡´ì±ì´ ì¡´ì¬íë¯ë¡, ì´ ìíì¤ê° ëë¬ì ë Q ë &A ëë &B
ì¼ ê²ì´ê³ , ë°ë¼ì:
(Q == &A) ë (D == 1) 를,
(Q == &B) ë (D == 4) 를 ì미í©ëë¤.
íì§ë§! CPU 2 ë B ì ì
ë°ì´í¸ë¥¼ ì¸ìí기 ì ì P ì ì
ë°ì´í¸ë¥¼ ì¸ìí ì ìê³ ,
ë°ë¼ì ë¤ìì ê²°ê³¼ê° ê°ë¥í©ëë¤:
(Q == &B) and (D == 2) ????
ì´ë° ê²°ê³¼ë ì¼ê´ì±ì´ë ì¸ê³¼ ê´ê³ ì ì§ê° ì¤í¨í ê²ì²ë¼ ë³´ì¼ ìë ìê² ì§ë§,
ê·¸ë ì§ ììµëë¤, ê·¸ë¦¬ê³ ì´ íìì (DEC Alpha ì ê°ì) ì¬ë¬ CPU ìì ì¤ì ë¡
ë°ê²¬ë ì ììµëë¤.
ì´ ë¬¸ì ìí©ì ì ëë¡ í´ê²°í기 ìí´, ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ê·¸ë³´ë¤ ê°íë
무ì¸ê°ê° 주ì를 ì½ì´ì¬ ëì ë°ì´í°ë¥¼ ì½ì´ì¬ ë ì¬ì´ì ì¶ê°ëì´ì¼ë§ í©ëë¤:
CPU 1 CPU 2
=============== ===============
{ A == 1, B == 2, C == 3, P == &A, Q == &C }
B = 4;
<ì°ê¸° 배리ì´>
WRITE_ONCE(P, &B);
Q = READ_ONCE(P);
<ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´>
D = *Q;
ì´ ë³ê²½ì ìì ì²ì ëê°ì§ ê²°ê³¼ ì¤ íëë§ì´ ë°ìí ì ìê³ , ì¸ë²ì§¸ì ê²°ê³¼ë
ë°ìí ì ìëë¡ í©ëë¤.
[!] ì´ ìë¹í ë°ì§ê´ì ì¸ ìí©ì ë¶ë¦¬ë ìºì를 ê°ì§ë 기ê³ë¤ìì ê°ì¥ ì
ë°ìíëë°, ì를 ë¤ë©´ í ìºì ë±
í¬ë ì§ì ë²í¸ì ìºì ë¼ì¸ë¤ì ì²ë¦¬íê³ , ë¤ë¥¸
ë±
í¬ë íì ë²í¸ì ìºì ë¼ì¸ë¤ì ì²ë¦¬íë ê²½ì°ìì ììëì기 ë°ëëë¤. í¬ì¸í°
P ë ì§ì ë²í¸ ìºì ë¼ì¸ì ì ì¥ëì´ ìê³ , ë³ì B ë íì ë²í¸ ìºì ë¼ì¸ì
ì ì¥ëì´ ìì ì ììµëë¤. ì¬ê¸°ì ê°ì ì½ì´ì¤ë CPU ì ìºìì íì ë²í¸ ì²ë¦¬
ë±
í¬ë ì´ì¬í ì¼ê°ì ì²ë¦¬ì¤ì¸ ë°ë©´ íì ë²í¸ ì²ë¦¬ ë±
í¬ë í ì¼ ìì´ íê°í
ì¤ì´ë¼ë©´ í¬ì¸í° P (&B) ì ìë¡ì´ ê°ê³¼ ë³ì B ì 기존 ê° (2) 를 ë³¼ ì ììµëë¤.
ìì¡´ì ì°ê¸°ë¤ì ìì를 ë§ì¶ëë°ìë ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ê° íìì¹ ììë°, ì´ë
리ë
ì¤ ì»¤ëì´ ì§ìíë CPU ë¤ì (1) ì°ê¸°ê° ì ë§ë¡ ì¼ì´ë ì§, (2) ì°ê¸°ê° ì´ëì
ì´ë£¨ì´ì§ì§, ê·¸ë¦¬ê³ (3) ì°ì¬ì§ ê°ì íì¤í ì기 ì ê¹ì§ë ì°ê¸°ë¥¼ ìííì§ ì기
ë문ì
ëë¤. íì§ë§ “컨í¸ë¡¤ ìì¡´ì±” ì¹ì
ê³¼
Documentation/RCU/rcu_dereference.txt íì¼ì 주ì ê¹ê² ì½ì´ 주ì기 ë°ëëë¤:
ì»´íì¼ë¬ë ë§¤ì° ì°½ìì ì¸ ë§ì ë°©ë²ì¼ë¡ ì¢
ìì±ì ê¹° ì ììµëë¤.
CPU 1 CPU 2
=============== ===============
{ A == 1, B == 2, C = 3, P == &A, Q == &C }
B = 4;
<ì°ê¸° 배리ì´>
WRITE_ONCE(P, &B);
Q = READ_ONCE(P);
WRITE_ONCE(*Q, 5);
ë°ë¼ì, Q ë¡ì ì½ê¸°ì *Q ë¡ì ì°ê¸° ì¬ì´ìë ë°ì´í° ì¢
ìì± ë°°ë¦¬ì´ê° íìì¹
ììµëë¤. ë¬ë¦¬ ë§íë©´, ë°ì´í° ì¢
ìì± ë°°ë¦¬ì´ê° ìëë¼ë ë¤ì ê²°ê³¼ë ì기ì§
ììµëë¤:
(Q == &B) && (B == 4)
ì´ë° í¨í´ì ëë¬¼ê² ì¬ì©ëì´ì¼ í¨ì ìì ëì기 ë°ëëë¤. 무ìë³´ë¤ë, ìì¡´ì±
ìì ê·ì¹ì ìëë ì°ê¸° ìì
ì -ìë°©- í´ì ê·¸ë¡ ì¸í´ ë°ìíë ë¹ì¼ ìºì 미ì¤ë
ìì ë ¤ë ê²ì
ëë¤. ì´ í¨í´ì ëë¬¼ê² ë°ìíë ìë¬ ì¡°ê±´ ê°ìê²ë¤ì 기ë¡íëë°
ì¬ì©ë ì ìì¼ë©°, CPUì ìì°ì ì¸ ìì ë³´ì¥ì´ ê·¸ë° ê¸°ë¡ë¤ì ì¬ë¼ì§ì§ ìê²
í´ì¤ëë¤.
ë°ì´í° ìì¡´ì±ì ìí´ ì ê³µëë ì´ ììê·ì¹ì ì´ë¥¼ í¬í¨íê³ ìë CPU ì
ì§ìì ìì ììëì기 ë°ëëë¤. ë ë§ì ì 보를 ìí´ì “Multicopy ììì±”
ì¹ì
ì ì°¸ê³ íì¸ì.
ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ë§¤ì° ì¤ìíë°, ì를 ë¤ì´ RCU ìì¤í
ìì ê·¸ë ìµëë¤.
include/linux/rcupdate.h ì rcu_assign_pointer() ì rcu_dereference() 를
ì°¸ê³ íì¸ì. ì¬ê¸°ì ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë RCU ë¡ ê´ë¦¬ëë í¬ì¸í°ì íê²ì íì¬
íê²ìì ìì ë ìë¡ì´ íê²ì¼ë¡ ë°ê¾¸ë ìì
ìì ìë¡ ìì ë íê²ì´ ì´ê¸°íê°
ìë£ëì§ ìì ì±ë¡ ë³´ì¬ì§ë ì¼ì´ ì¼ì´ëì§ ìê² í´ì¤ëë¤.
ë ë§ì ì를 ìí´ì “ìºì ì¼ê´ì±” ìë¸ì¹ì ì ì°¸ê³ íì¸ì.
컨í¸ë¡¤ ìì¡´ì±
íì¬ì ì»´íì¼ë¬ë¤ì 컨í¸ë¡¤ ìì¡´ì±ì ì´í´íê³ ìì§ ì기 ë문ì 컨í¸ë¡¤ ìì¡´ì±ì
ì½ê° ë¤ë£¨ê¸° ì´ë ¤ì¸ ì ììµëë¤. ì´ ì¹ì
ì 목ì ì ì¬ë¬ë¶ì´ ì»´íì¼ë¬ì 무ìë¡
ì¸í´ ì¬ë¬ë¶ì ì½ëê° ë§ê°ì§ë 걸 ë§ì ì ìëë¡ ëëê²ëë¤.
ë¡ë-ë¡ë 컨í¸ë¡¤ ìì¡´ì±ì ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë§ì¼ë¡ë ì íí ëìí ìê°
ìì´ì ì½ê¸° ë©ëª¨ë¦¬ 배리ì´ë¥¼ íìë¡ í©ëë¤. ìëì ì½ë를 ë´
ìë¤:
q = READ_ONCE(a);
if (q) {
<ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´> /* BUG: No data dependency!!! */
p = READ_ONCE(b);
}
ì´ ì½ëë ìíë ëë¡ì í¨ê³¼ë¥¼ ë´ì§ 못í ì ìëë°, ì´ ì½ëìë ë°ì´í° ìì¡´ì±ì´
ìëë¼ ì»¨í¸ë¡¤ ìì¡´ì±ì´ ì¡´ì¬í기 ë문ì¼ë¡, ì´ë° ìí©ìì CPU ë ì¤í ìë를 ë
ë¹ ë¥´ê² í기 ìí´ ë¶ê¸° ì¡°ê±´ì 결과를 ì측íê³ ì½ë를 ì¬ë°°ì¹ í ì ìì´ì ë¤ë¥¸
CPU ë b ë¡ë¶í°ì ë¡ë ì¤í¼ë ì´ì
ì´ a ë¡ë¶í°ì ë¡ë ì¤í¼ë ì´ì
ë³´ë¤ ë¨¼ì ë°ìí
ê±¸ë¡ ì¸ìí ì ììµëë¤. ì¬ê¸°ì ì ë§ë¡ íìíë ê±´ ë¤ìê³¼ ê°ìµëë¤:
q = READ_ONCE(a);
if (q) {
<ì½ê¸° 배리ì´>
p = READ_ONCE(b);
}
íì§ë§, ì¤í ì´ ì¤í¼ë ì´ì
ì ì측ì ì¼ë¡ ìíëì§ ììµëë¤. ì¦, ë¤ì ìììì
ê°ì´ ë¡ë-ì¤í ì´ ì»¨í¸ë¡¤ ìì¡´ì±ì´ ì¡´ì¬íë ê²½ì°ìë ììê° -ì§ì¼ì§ë¤-ë
ì미ì
ëë¤.
q = READ_ONCE(a);
if (q) {
WRITE_ONCE(b, 1);
}
컨í¸ë¡¤ ìì¡´ì±ì ë³´íµ ë¤ë¥¸ íì
ì 배리ì´ë¤ê³¼ ì§ì ë§ì¶° ì¬ì©ë©ëë¤. ê·¸ë ë¤ê³¤
íë, READ_ONCE() ë WRITE_ONCE() ë ì íì¬íì´ ìëë¼ íìì¬íìì ë¶ë
ëª
ì¬íì¸ì! READ_ONCE() ê° ìë¤ë©´, ì»´íì¼ë¬ë ‘a’ ë¡ë¶í°ì ë¡ë를 ‘a’ ë¡ë¶í°ì
ëë¤ë¥¸ ë¡ëì ì¡°í©í ì ììµëë¤. WRITE_ONCE() ê° ìë¤ë©´, ì»´íì¼ë¬ë ‘b’ ë¡ì
ì¤í ì´ë¥¼ ‘b’ ë¡ì ëë¼ë ì¤í ì´ë¤ê³¼ ì¡°í©í ì ììµëë¤. ë ê²½ì° ëª¨ë ììì
ìì´ ìë¹í ë¹ì§ê´ì ì¸ ê²°ê³¼ë¥¼ ì´ëí ì ììµëë¤.
ì´ê±¸ë¡ ëì´ ìëê², ì»´íì¼ë¬ê° ë³ì ‘a’ ì ê°ì´ íì 0ì´ ìëë¼ê³ ì¦ëª
í ì
ìë¤ë©´, ìì ììì “if” 문ì ìì ì ë¤ìê³¼ ê°ì´ ìµì í í ìë ììµëë¤:
q = a;
b = 1; /* BUG: Compiler and CPU can both reorder!!! */
ê·¸ë¬ë READ_ONCE() 를 ë°ëì ì¬ì©íì¸ì.
ë¤ìê³¼ ê°ì´ “if” 문ì ìê°ë ë¸ëì¹ì 모ë ì¡´ì¬íë ëì¼í ì¤í ì´ì ëí´ ìì를
ê°ì íê³ ì¶ì ê²½ì°ê° ìì ì ììµëë¤:
q = READ_ONCE(a);
if (q) {
barrier();
WRITE_ONCE(b, 1);
do_something();
} else {
barrier();
WRITE_ONCE(b, 1);
do_something_else();
}
ìíê¹ê²ë, íì¬ì ì»´íì¼ë¬ë¤ì ëì ìµì í ë 벨ììë ì´ê±¸ ë¤ìê³¼ ê°ì´
ë°ê¿ë²ë¦½ëë¤:
q = READ_ONCE(a);
barrier();
WRITE_ONCE(b, 1); /* BUG: No ordering vs. load from a!!! */
if (q) {
/* WRITE_ONCE(b, 1); -- moved up, BUG!!! */
do_something();
} else {
/* WRITE_ONCE(b, 1); -- moved up, BUG!!! */
do_something_else();
}
ì´ì ‘a’ ììì ë¡ëì ‘b’ ë¡ì ì¤í ì´ ì¬ì´ìë ì¡°ê±´ì ê´ê³ê° ì기 ë문ì CPU
ë ì´ë¤ì ìì를 ë°ê¿ ì ìê² ë©ëë¤: ì´ë° ê²½ì°ì ì¡°ê±´ì ê´ê³ë ë°ëì
íìíë°, 모ë ì»´íì¼ë¬ ìµì íê° ì´ë£¨ì´ì§ê³ ë íì ì´ì
ë¸ë¦¬ ì½ëììë
ë§ì°¬ê°ì§ì
ëë¤. ë°ë¼ì, ì´ ììì ìì를 ì§í¤ê¸° ìí´ìë smp_store_release()
ì ê°ì ëª
ìì ë©ëª¨ë¦¬ 배리ì´ê° íìí©ëë¤:
q = READ_ONCE(a);
if (q) {
smp_store_release(&b, 1);
do_something();
} else {
smp_store_release(&b, 1);
do_something_else();
}
ë°ë©´ì ëª
ìì ë©ëª¨ë¦¬ 배리ì´ê° ìë¤ë©´, ì´ë° ê²½ì°ì ììë ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì´
ìë¡ ë¤ë¥¼ ëìë§ ë³´ì¥ëëë°, ì를 ë¤ë©´ ë¤ìê³¼ ê°ì ê²½ì°ì
ëë¤:
q = READ_ONCE(a);
if (q) {
WRITE_ONCE(b, 1);
do_something();
} else {
WRITE_ONCE(b, 2);
do_something_else();
}
ì²ìì READ_ONCE() ë ì»´íì¼ë¬ê° ‘a’ ì ê°ì ì¦ëª
í´ë´ë ê²ì ë§ê¸° ìí´ ì¬ì í
íìí©ëë¤.
ëí, ë¡ì»¬ ë³ì ‘q’ 를 ê°ì§ê³ íë ì¼ì ëí´ ì£¼ìí´ì¼ íëë°, ê·¸ë¬ì§ ìì¼ë©´
ì»´íì¼ë¬ë ê·¸ ê°ì ì¶ì¸¡íê³ ëë¤ì íìí ì¡°ê±´ê´ê³ë¥¼ ìì ë²ë¦´ ì ììµëë¤.
ì를 ë¤ë©´:
q = READ_ONCE(a);
if (q % MAX) {
WRITE_ONCE(b, 1);
do_something();
} else {
WRITE_ONCE(b, 2);
do_something_else();
}
ë§ì½ MAX ê° 1 ë¡ ì ìë ììë¼ë©´, ì»´íì¼ë¬ë (q % MAX) ë 0ì´ë ê²ì ììì±ê³ ,
ìì ì½ë를 ìëì ê°ì´ ë°ê¿ë²ë¦´ ì ììµëë¤:
q = READ_ONCE(a);
WRITE_ONCE(b, 2);
do_something_else();
ì´ë ê² ëë©´, CPU ë ë³ì ‘a’ ë¡ë¶í°ì ë¡ëì ë³ì ‘b’ ë¡ì ì¤í ì´ ì¬ì´ì ìì를
ì§ì¼ì¤ íìê° ìì´ì§ëë¤. barrier() 를 ì¶ê°í´ í´ê²°í´ ë³´ê³ ì¶ê² ì§ë§, 그건
ëìì´ ìë©ëë¤. ì¡°ê±´ ê´ê³ë ì¬ë¼ì¡ê³ , barrier() ë ì´ë¥¼ ëëë¦¬ì§ ëª»í©ëë¤.
ë°ë¼ì, ì´ ìì를 ì§ì¼ì¼ íë¤ë©´, MAX ê° 1 ë³´ë¤ í¬ë¤ë ê²ì, ë¤ìê³¼ ê°ì ë°©ë²ì
ì¬ì©í´ ë¶ëª
í í´ì¼ í©ëë¤:
q = READ_ONCE(a);
BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */
if (q % MAX) {
WRITE_ONCE(b, 1);
do_something();
} else {
WRITE_ONCE(b, 2);
do_something_else();
}
‘b’ ë¡ì ì¤í ì´ë¤ì ì¬ì í ìë¡ ë¤ë¦ì ììëì¸ì. ë§ì½ ê·¸ê²ë¤ì´ ëì¼íë©´,
ììì ì´ì¼ê¸°íë¯, ì»´íì¼ë¬ê° ê·¸ ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì ‘if’ 문 ë°ê¹¥ì¼ë¡
ëì§ì´ë¼ ì ììµëë¤.
ëí ì´ì§ 조건문 íê°ì ë무 ìì¡´íì§ ìëë¡ ì¡°ì¬í´ì¼ í©ëë¤. ë¤ìì ì를
ë´
ìë¤:
q = READ_ONCE(a);
if (q || 1 > 0)
WRITE_ONCE(b, 1);
첫ë²ì§¸ ì¡°ê±´ë§ì¼ë¡ë ë¸ëì¹ ì¡°ê±´ ì 체를 ê±°ì§ì¼ë¡ ë§ë¤ ì ìê³ ëë²ì§¸ ì¡°ê±´ì íì
ì°¸ì´ê¸° ë문ì, ì»´íì¼ë¬ë ì´ ì를 ë¤ìê³¼ ê°ì´ ë°ê¿ì 컨í¸ë¡¤ ìì¡´ì±ì ìì ë²ë¦´
ì ììµëë¤:
q = READ_ONCE(a);
WRITE_ONCE(b, 1);
ì´ ìë ì»´íì¼ë¬ê° ì½ë를 ì¶ì¸¡ì¼ë¡ ìì í ì ìëë¡ ë¶ëª
í í´ì¼ íë¤ë ì ì
ê°ì¡°í©ëë¤. ì¡°ê¸ ë ì¼ë°ì ì¼ë¡ ë§í´ì, READ_ONCE() ë ì»´íì¼ë¬ìê² ì£¼ì´ì§ ë¡ë
ì¤í¼ë ì´ì
ì ìí ì½ë를 ì ë§ë¡ ë§ë¤ëë¡ íì§ë§, ì»´íì¼ë¬ê° ê·¸ë ê² ë§ë¤ì´ì§
ì½ëì ìí 결과를 ì¬ì©íëë¡ ê°ì íì§ë ììµëë¤.
ëí, 컨í¸ë¡¤ ìì¡´ì±ì if 문ì then ì ê³¼ else ì ì ëí´ìë§ ì ì©ë©ëë¤. ìì¸í
ë§í´ì, 컨í¸ë¡¤ ìì¡´ì±ì if 문ì ë¤ë°ë¥´ë ì½ëìë ì ì©ëì§ ììµëë¤:
q = READ_ONCE(a);
if (q) {
WRITE_ONCE(b, 1);
} else {
WRITE_ONCE(b, 2);
}
WRITE_ONCE(c, 1); /* BUG: No ordering against the read from 'a'. */
ì»´íì¼ë¬ë volatile íì
ì ëí ì¡ì¸ì¤ë¥¼ ì¬ë°°ì¹ í ì ìê³ ì´ ì¡°ê±´ íì ‘b’
ë¡ì ì°ê¸°ë¥¼ ì¬ë°°ì¹ í ì ì기 ë문ì ì¬ê¸°ì ìì ê·ì¹ì´ ì¡´ì¬íë¤ê³ 주ì¥íê³
ì¶ì ê²ëë¤. ë¶ííë ì´ ê²½ì°ì, ì»´íì¼ë¬ë ë¤ìì ê°ìì pseudo-assembly ì¸ì´
ì½ëì²ë¼ ‘b’ ë¡ì ëê°ì ì°ê¸° ì¤í¼ë ì´ì
ì conditional-move ì¸ì¤í¸ëì
ì¼ë¡
ë²ìí ì ììµëë¤:
ld r1,a
cmp r1,$0
cmov,ne r4,$1
cmov,eq r4,$2
st r4,b
st $1,c
ìíë ìì ê·ì¹ì CPU ë ‘a’ ë¡ë¶í°ì ë¡ëì ‘c’ ë¡ì ì¤í ì´ ì¬ì´ì ì´ë¤
ì¢
ë¥ì ìì¡´ì±ë ê°ì§ ìì ê²ëë¤. ì´ ì»¨í¸ë¡¤ ìì¡´ì±ì ëê°ì cmov ì¸ì¤í¸ëì
ê³¼
거기ì ìì¡´íë ì¤í ì´ ìê²ë§ ì ì©ë ê²ëë¤. ì§§ê² ë§íìë©´, 컨í¸ë¡¤ ìì¡´ì±ì
주ì´ì§ if 문ì then ì ê³¼ else ì ìê²ë§ (ê·¸ë¦¬ê³ ì´ ë ì ë´ìì í¸ì¶ëë
í¨ìë¤ìê²ê¹ì§) ì ì©ëì§, ì´ if 문ì ë¤ë°ë¥´ë ì½ëìë ì ì©ëì§ ììµëë¤.
컨í¸ë¡¤ ìì¡´ì±ì ìí´ ì ê³µëë ì´ ììê·ì¹ì ì´ë¥¼ í¬í¨íê³ ìë CPU ì
ì§ìì ì
ëë¤. ë ë§ì ì 보를 ìí´ì “Multicopy ììì±” ì¹ì
ì ì°¸ê³ íì¸ì.
ìì½íìë©´:
(*) 컨í¸ë¡¤ ìì¡´ì±ì ìì ë¡ëë¤ì ë¤ì ì¤í ì´ë¤ì ëí´ ìì를 ë§ì¶°ì¤ëë¤.
íì§ë§, ê·¸ ì¸ì ì´ë¤ ììë ë³´ì¥íì§ -ììµëë¤-: ìì ë¡ëì ë¤ì ë¡ëë¤
ì¬ì´ìë, ìì ì¤í ì´ì ë¤ì ì¤í ì´ë¤ ì¬ì´ìëì. ì´ë° ë¤ë¥¸ ííì
ììê° íìíë¤ë©´ smp_rmb() ë smp_wmb()를, ëë, ìì ì¤í ì´ë¤ê³¼ ë¤ì
ë¡ëë¤ ì¬ì´ì ìì를 ìí´ìë smp_mb() 를 ì¬ì©íì¸ì.
(*) “if” 문ì ìê°ë ë¸ëì¹ê° ê°ì ë³ììì ëì¼í ì¤í ì´ë¡ ììíë¤ë©´, ê·¸
ì¤í ì´ë¤ì ê° ì¤í ì´ ìì smp_mb() 를 ë£ê±°ë smp_store_release() 를
ì¬ì©í´ì ì¤í ì´ë¥¼ íë ìì¼ë¡ ìì를 ë§ì¶°ì¤ì¼ í©ëë¤. ì´ ë¬¸ì 를 í´ê²°í기
ìí´ “if” 문ì ìê°ë ë¸ëì¹ì ìì ì§ì ì barrier() 를 ë£ë ê²ë§ì¼ë¡ë
충ë¶í í´ê²°ì´ ëì§ ìëë°, ì´ë ìì ììì 본ê²ê³¼ ê°ì´, ì»´íì¼ë¬ì
ìµì íë barrier() ê° ì미íë ë°ë¥¼ ì§í¤ë©´ìë 컨í¸ë¡¤ ìì¡´ì±ì ìììí¬
ì ì기 ë문ì´ë¼ë ì ì ë¶ë ììëì기 ë°ëëë¤.
(*) 컨í¸ë¡¤ ìì¡´ì±ì ìì ë¡ëì ë¤ì ì¤í ì´ ì¬ì´ì ìµì íëì, ì¤í
ìì ììì ì¡°ê±´ê´ê³ë¥¼ íìë¡ íë©°, ì´ ì¡°ê±´ê´ê³ë ìì ë¡ëì ê´ê³ëì´ì¼
í©ëë¤. ë§ì½ ì»´íì¼ë¬ê° ì¡°ê±´ ê´ê³ë¥¼ ìµì íë¡ ìì¨ì ìë¤ë©´, ììë
ìµì íë¡ ìì ë²ë ¸ì ê²ëë¤. READ_ONCE() ì WRITE_ONCE() ì 주ì ê¹ì
ì¬ì©ì 주ì´ì§ ì¡°ê±´ ê´ê³ë¥¼ ì ì§íëë° ëìì´ ë ì ììµëë¤.
(*) 컨í¸ë¡¤ ìì¡´ì±ì ìí´ì ì»´íì¼ë¬ê° ì¡°ê±´ê´ê³ë¥¼ ìì ë²ë¦¬ë ê²ì ë§ìì¼
í©ëë¤. 주ì ê¹ì READ_ONCE() ë atomic{,64}_read() ì ì¬ì©ì´ 컨í¸ë¡¤
ìì¡´ì±ì´ ì¬ë¼ì§ì§ ìê² íëë° ëìì ì¤ ì ììµëë¤. ë ë§ì ì 보를
ìí´ì “ì»´íì¼ë¬ 배리촔 ì¹ì
ì ì°¸ê³ íì기 ë°ëëë¤.
(*) 컨í¸ë¡¤ ìì¡´ì±ì 컨í¸ë¡¤ ìì¡´ì±ì ê°ë if 문ì then ì ê³¼ else ì ê³¼ ì´ ë ì
ë´ìì í¸ì¶ëë í¨ìë¤ìë§ ì ì©ë©ëë¤. 컨í¸ë¡¤ ìì¡´ì±ì 컨í¸ë¡¤ ìì¡´ì±ì
ê°ë if 문ì ë¤ë°ë¥´ë ì½ëìë ì ì©ëì§ -ììµëë¤-.
(*) 컨í¸ë¡¤ ìì¡´ì±ì ë³´íµ ë¤ë¥¸ íì ì 배리ì´ë¤ê³¼ ì§ì ë§ì¶° ì¬ì©ë©ëë¤.
(*) 컨í¸ë¡¤ ìì¡´ì±ì multicopy ììì±ì ì ê³µíì§ -ììµëë¤-. 모ë CPU ë¤ì´
í¹ì ì¤í ì´ë¥¼ ëìì 보길 ìíë¤ë©´, smp_mb() 를 ì¬ì©íì¸ì.
(*) ì»´íì¼ë¬ë 컨í¸ë¡¤ ìì¡´ì±ì ì´í´íê³ ìì§ ììµëë¤. ë°ë¼ì ì»´íì¼ë¬ê°
ì¬ë¬ë¶ì ì½ë를 ë§ê°ë¨ë¦¬ì§ ìëë¡ íëê±´ ì¬ë¬ë¶ì´ í´ì¼ íë ì¼ì
ëë¤.
SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°
CPU ê° ìí¸ìì©ì ë¤ë£° ëì ì¼ë¶ íì
ì ë©ëª¨ë¦¬ 배리ì´ë íì ì§ì ë§ì¶°
ì¬ì©ëì´ì¼ í©ëë¤. ì ì íê² ì§ì ë§ì¶ì§ ìì ì½ëë ì¬ì¤ì ìë¬ì ê°ê¹ìµëë¤.
ë²ì© 배리ì´ë¤ì ë²ì© 배리ì´ë¼ë¦¬ë ì§ì ë§ì¶ì§ë§ multicopy ììì±ì´ ìë
ëë¶ë¶ì ë¤ë¥¸ íì
ì 배리ì´ë¤ê³¼ë ì§ì ë§ì¶¥ëë¤. ACQUIRE 배리ì´ë RELEASE
배리ì´ì ì§ì ë§ì¶¥ëë¤ë§, ë ë¤ ë²ì© 배리ì´ë¥¼ í¬í¨í´ ë¤ë¥¸ 배리ì´ë¤ê³¼ë ì§ì
ë§ì¶ ì ììµëë¤. ì°ê¸° 배리ì´ë ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë 컨í¸ë¡¤ ìì¡´ì±, ACQUIRE
배리ì´, RELEASE 배리ì´, ì½ê¸° 배리ì´, ëë ë²ì© 배리ì´ì ì§ì ë§ì¶¥ëë¤.
ë¹ì·íê² ì½ê¸° 배리ì´ë 컨í¸ë¡¤ ìì¡´ì±, ëë ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ì°ê¸° 배리ì´ë
ACQUIRE 배리ì´, RELEASE 배리ì´, ëë ë²ì© 배리ì´ì ì§ì ë§ì¶ëë°, ë¤ìê³¼
ê°ìµëë¤:
CPU 1 CPU 2
=============== ===============
WRITE_ONCE(a, 1);
<ì°ê¸° 배리ì´>
WRITE_ONCE(b, 2); x = READ_ONCE(b);
<ì½ê¸° 배리ì´>
y = READ_ONCE(a);
ëë:
CPU 1 CPU 2
=============== ===============================
a = 1;
<ì°ê¸° 배리ì´>
WRITE_ONCE(b, &a); x = READ_ONCE(b);
<ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´>
y = *x;
ëë:
CPU 1 CPU 2
=============== ===============================
r1 = READ_ONCE(y);
<ë²ì© 배리ì´>
WRITE_ONCE(x, 1); if (r2 = READ_ONCE(x)) {
<묵ìì 컨í¸ë¡¤ ìì¡´ì±>
WRITE_ONCE(y, 1);
}
assert(r1 == 0 || r2 == 0);
기본ì ì¼ë¡, ì¬ê¸°ìì ì½ê¸° 배리ì´ë “ë ìíë” íì
ì¼ ì ìì´ë íì ì¡´ì¬í´ì¼
í©ëë¤.
[!] ì°ê¸° ë°°ë¦¬ì´ ìì ì¤í ì´ ì¤í¼ë ì´ì
ì ì¼ë°ì ì¼ë¡ ì½ê¸° 배리ì´ë ë°ì´í°
ìì¡´ì± ë°°ë¦¬ì´ ë¤ì ë¡ë ì¤í¼ë ì´ì
ê³¼ 매ì¹ë ê²ì´ê³ , ë°ëë ë§ì°¬ê°ì§ì
ëë¤:
CPU 1 CPU 2
=================== ===================
WRITE_ONCE(a, 1); }---- --->{ v = READ_ONCE(c);
WRITE_ONCE(b, 2); } \ / { w = READ_ONCE(d);
<ì°ê¸° 배리ì´> \ <ì½ê¸° 배리ì´>
WRITE_ONCE(c, 3); } / \ { x = READ_ONCE(a);
WRITE_ONCE(d, 4); }---- --->{ y = READ_ONCE(b);
ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ìíì¤ì ì
첫째, ì°ê¸° 배리ì´ë ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì ë¶ë¶ì ìì ì¸ì°ê¸°ë¡ ëìí©ëë¤.
ìëì ì´ë²¤í¸ ìíì¤ë¥¼ ë³´ì¸ì:
CPU 1
=======================
STORE A = 1
STORE B = 2
STORE C = 3
<ì°ê¸° 배리ì´>
STORE D = 4
STORE E = 5
ì´ ì´ë²¤í¸ ìíì¤ë ë©ëª¨ë¦¬ ì¼ê´ì± ìì¤í
ì ììë¼ë¦¬ì ììê° ì¡´ì¬íì§ ìë ì§í©
{ STORE A, STORE B, STORE C } ê° ìì ììë¼ë¦¬ì ììê° ì¡´ì¬íì§ ìë ì§í©
{ STORE D, STORE E } ë³´ë¤ ë¨¼ì ì¼ì´ë ê²ì¼ë¡ ìì¤í
ì ëë¨¸ì§ ììë¤ì ë³´ì´ëë¡
ì ë¬ë©ëë¤:
+-------+ : :
| | +------+
| |------>| C=3 | } /\
| | : +------+ }----- \ -----> ìì¤í
ì ëë¨¸ì§ ììì
| | : | A=1 | } \/ ë³´ì¬ì§ ì ìë ì´ë²¤í¸ë¤
| | : +------+ }
| CPU 1 | : | B=2 | }
| | +------+ }
| | wwwwwwwwwwwwwwww } <--- ì¬ê¸°ì ì°ê¸° 배리ì´ë ë°°ë¦¬ì´ ìì
| | +------+ } 모ë ì¤í ì´ê° ë°°ë¦¬ì´ ë¤ì ì¤í ì´
| | : | E=5 | } ì ì ë©ëª¨ë¦¬ ìì¤í
ì ì ë¬ëëë¡
| | : +------+ } í©ëë¤
| |------>| D=4 | }
| | +------+
+-------+ : :
|
| CPU 1 ì ìí´ ë©ëª¨ë¦¬ ìì¤í
ì ì ë¬ëë
| ì¼ë ¨ì ì¤í ì´ ì¤í¼ë ì´ì
ë¤
V
ë째, ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ë°ì´í° ìì¡´ì ë¡ë ì¤í¼ë ì´ì
ë¤ì ë¶ë¶ì ìì
ì¸ì°ê¸°ë¡ ëìí©ëë¤. ë¤ì ì¼ë ¨ì ì´ë²¤í¸ë¤ì ë³´ì¸ì:
CPU 1 CPU 2
======================= =======================
{ B = 7; X = 9; Y = 8; C = &Y }
STORE A = 1
STORE B = 2
<ì°ê¸° 배리ì´>
STORE C = &B LOAD X
STORE D = 4 LOAD C (gets &B)
LOAD *C (reads B)
ì¬ê¸°ì ë³ë¤ë¥¸ ê°ì
ì´ ìë¤ë©´, CPU 1 ì ì°ê¸° 배리ì´ìë ë¶êµ¬íê³ CPU 2 ë CPU 1
ì ì´ë²¤í¸ë¤ì ìì í 무ììì ììë¡ ì¸ì§íê² ë©ëë¤:
+-------+ : : : :
| | +------+ +-------+ | CPU 2 ì ì¸ì§ëë
| |------>| B=2 |----- --->| Y->8 | | ì
ë°ì´í¸ ì´ë²¤í¸
| | : +------+ \ +-------+ | ìíì¤
| CPU 1 | : | A=1 | \ --->| C->&Y | V
| | +------+ | +-------+
| | wwwwwwwwwwwwwwww | : :
| | +------+ | : :
| | : | C=&B |--- | : : +-------+
| | : +------+ \ | +-------+ | |
| |------>| D=4 | ----------->| C->&B |------>| |
| | +------+ | +-------+ | |
+-------+ : : | : : | |
| : : | |
| : : | CPU 2 |
| +-------+ | |
ë¶ëª
í ì못ë ---> | | B->7 |------>| |
B ì ê° ì¸ì§ (!) | +-------+ | |
| : : | |
| +-------+ | |
X ì ë¡ëê° B ì ---> \ | X->9 |------>| |
ì¼ê´ì± ì ì§ë¥¼ \ +-------+ | |
ì§ì°ìí´ ----->| B->2 | +-------+
+-------+
: :
ìì ììì, CPU 2 ë (B ì ê°ì´ ë ) *C ì ê° ì½ê¸°ê° C ì LOAD ë¤ì ì´ì´ì§ìë
B ê° 7 ì´ë¼ë 결과를 ì»ìµëë¤.
íì§ë§, ë§ì½ ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ê° C ì ë¡ëì *C (ì¦, B) ì ë¡ë ì¬ì´ì
ììë¤ë©´:
CPU 1 CPU 2
======================= =======================
{ B = 7; X = 9; Y = 8; C = &Y }
STORE A = 1
STORE B = 2
<ì°ê¸° 배리ì´>
STORE C = &B LOAD X
STORE D = 4 LOAD C (gets &B)
<ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´>
LOAD *C (reads B)
ë¤ìê³¼ ê°ì´ ë©ëë¤:
+-------+ : : : :
| | +------+ +-------+
| |------>| B=2 |----- --->| Y->8 |
| | : +------+ \ +-------+
| CPU 1 | : | A=1 | \ --->| C->&Y |
| | +------+ | +-------+
| | wwwwwwwwwwwwwwww | : :
| | +------+ | : :
| | : | C=&B |--- | : : +-------+
| | : +------+ \ | +-------+ | |
| |------>| D=4 | ----------->| C->&B |------>| |
| | +------+ | +-------+ | |
+-------+ : : | : : | |
| : : | |
| : : | CPU 2 |
| +-------+ | |
| | X->9 |------>| |
| +-------+ | |
C ë¡ì ì¤í ì´ ìì ---> \ ddddddddddddddddd | |
모ë ì´ë²¤í¸ ê²°ê³¼ê° \ +-------+ | |
ë¤ì ë¡ëìê² ----->| B->2 |------>| |
ë³´ì´ê² ê°ì íë¤ +-------+ | |
: : +-------+
ì
째, ì½ê¸° 배리ì´ë ë¡ë ì¤í¼ë ì´ì
ë¤ìì ë¶ë¶ì ìì ì¸ì°ê¸°ë¡ ëìí©ëë¤.
ìëì ì¼ë ¨ì ì´ë²¤í¸ë¥¼ ë´
ìë¤:
CPU 1 CPU 2
======================= =======================
{ A = 0, B = 9 }
STORE A=1
<ì°ê¸° 배리ì´>
STORE B=2
LOAD B
LOAD A
CPU 1 ì ì°ê¸° 배리ì´ë¥¼ 쳤ì§ë§, ë³ë¤ë¥¸ ê°ì
ì´ ìë¤ë©´ CPU 2 ë CPU 1 ìì íí´ì§
ì´ë²¤í¸ì 결과를 무ììì ììë¡ ì¸ì§íê² ë©ëë¤.
+-------+ : : : :
| | +------+ +-------+
| |------>| A=1 |------ --->| A->0 |
| | +------+ \ +-------+
| CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
| | +------+ | +-------+
| |------>| B=2 |--- | : :
| | +------+ \ | : : +-------+
+-------+ : : \ | +-------+ | |
---------->| B->2 |------>| |
| +-------+ | CPU 2 |
| | A->0 |------>| |
| +-------+ | |
| : : +-------+
\ : :
\ +-------+
---->| A->1 |
+-------+
: :
íì§ë§, ë§ì½ ì½ê¸° 배리ì´ê° B ì ë¡ëì A ì ë¡ë ì¬ì´ì ì¡´ì¬íë¤ë©´:
CPU 1 CPU 2
======================= =======================
{ A = 0, B = 9 }
STORE A=1
<ì°ê¸° 배리ì´>
STORE B=2
LOAD B
<ì½ê¸° 배리ì´>
LOAD A
CPU 1 ì ìí´ ë§ë¤ì´ì§ ë¶ë¶ì ììê° CPU 2 ìë ê·¸ëë¡ ì¸ì§ë©ëë¤:
+-------+ : : : :
| | +------+ +-------+
| |------>| A=1 |------ --->| A->0 |
| | +------+ \ +-------+
| CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
| | +------+ | +-------+
| |------>| B=2 |--- | : :
| | +------+ \ | : : +-------+
+-------+ : : \ | +-------+ | |
---------->| B->2 |------>| |
| +-------+ | CPU 2 |
| : : | |
| : : | |
ì¬ê¸°ì ì½ê¸° 배리ì´ë ----> \ rrrrrrrrrrrrrrrrr | |
B ë¡ì ì¤í ì´ ì ì \ +-------+ | |
모ë 결과를 CPU 2 ì ---->| A->1 |------>| |
ë³´ì´ëë¡ íë¤ +-------+ | |
: : +-------+
ë ìë²½í ì¤ëª
ì ìí´, A ì ë¡ëê° ì½ê¸° ë°°ë¦¬ì´ ìê³¼ ë¤ì ìì¼ë©´ ì´ë»ê² ë ì§
ìê°í´ ë´
ìë¤:
CPU 1 CPU 2
======================= =======================
{ A = 0, B = 9 }
STORE A=1
<ì°ê¸° 배리ì´>
STORE B=2
LOAD B
LOAD A [first load of A]
<ì½ê¸° 배리ì´>
LOAD A [second load of A]
A ì ë¡ë ëê°ê° 모ë B ì ë¡ë ë¤ì ìì§ë§, ìë¡ ë¤ë¥¸ ê°ì ì»ì´ì¬ ì
ììµëë¤:
+-------+ : : : :
| | +------+ +-------+
| |------>| A=1 |------ --->| A->0 |
| | +------+ \ +-------+
| CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
| | +------+ | +-------+
| |------>| B=2 |--- | : :
| | +------+ \ | : : +-------+
+-------+ : : \ | +-------+ | |
---------->| B->2 |------>| |
| +-------+ | CPU 2 |
| : : | |
| : : | |
| +-------+ | |
| | A->0 |------>| 1st |
| +-------+ | |
ì¬ê¸°ì ì½ê¸° 배리ì´ë ----> \ rrrrrrrrrrrrrrrrr | |
B ë¡ì ì¤í ì´ ì ì \ +-------+ | |
모ë 결과를 CPU 2 ì ---->| A->1 |------>| 2nd |
ë³´ì´ëë¡ íë¤ +-------+ | |
: : +-------+
íì§ë§ CPU 1 ììì A ì
ë°ì´í¸ë ì½ê¸° 배리ì´ê° ìë£ë기 ì ìë ë³´ì¼ ìë
ì긴 í©ëë¤:
+-------+ : : : :
| | +------+ +-------+
| |------>| A=1 |------ --->| A->0 |
| | +------+ \ +-------+
| CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
| | +------+ | +-------+
| |------>| B=2 |--- | : :
| | +------+ \ | : : +-------+
+-------+ : : \ | +-------+ | |
---------->| B->2 |------>| |
| +-------+ | CPU 2 |
| : : | |
\ : : | |
\ +-------+ | |
---->| A->1 |------>| 1st |
+-------+ | |
rrrrrrrrrrrrrrrrr | |
+-------+ | |
| A->1 |------>| 2nd |
+-------+ | |
: : +-------+
ì¬ê¸°ì ë³´ì¥ëë ê±´, ë§ì½ B ì ë¡ëê° B == 2 ë¼ë 결과를 ë´¤ë¤ë©´, A ìì ëë²ì§¸
ë¡ëë íì A == 1 ì ë³´ê² ë ê²ì´ë¼ë ê²ëë¤. A ìì 첫ë²ì§¸ ë¡ëìë ê·¸ë°
ë³´ì¥ì´ ììµëë¤; A == 0 ì´ê±°ë A == 1 ì´ê±°ë ë ì¤ íëì 결과를 ë³´ê² ë ê²ëë¤.
ì½ê¸° ë©ëª¨ë¦¬ ë°°ë¦¬ì´ VS ë¡ë ì측
ë§ì CPUë¤ì´ ë¡ë를 ì측ì ì¼ë¡ (speculatively) í©ëë¤: ì´ë¤ ë°ì´í°ë¥¼ ë©ëª¨ë¦¬ìì
ë¡ëí´ì¼ íê² ë ì§ ì측ì íë¤ë©´, í´ë¹ ë°ì´í°ë¥¼ ë¡ëíë ì¸ì¤í¸ëì
ì ì¤ì ë¡ë
ìì§ ë§ëì§ ììëë¼ë ë¤ë¥¸ ë¡ë ìì
ì´ ìì´ ë²ì¤ (bus) ê° ì무 ì¼ë íê³ ìì§
ìë¤ë©´, ê·¸ ë°ì´í°ë¥¼ ë¡ëí©ëë¤. ì´íì ì¤ì ë¡ë ì¸ì¤í¸ëì
ì´ ì¤íëë©´ CPU ê°
ì´ë¯¸ ê·¸ ê°ì ê°ì§ê³ ì기 ë문ì ê·¸ ë¡ë ì¸ì¤í¸ëì
ì ì¦ì ìë£ë©ëë¤.
í´ë¹ CPU ë ì¤ì ë¡ë ê·¸ ê°ì´ íìì¹ ììë¤ë ì¬ì¤ì´ ëì¤ì ëë¬ë ìë ìëë° -
í´ë¹ ë¡ë ì¸ì¤í¸ëì
ì´ ë¸ëì¹ë¡ ì°íëê±°ë íì ì ìê² ì£ - , ê·¸ë ê² ëë©´ ìì
ì½ì´ë ê°ì ë²ë¦¬ê±°ë ëì¤ì ì¬ì©ì ìí´ ìºìì ë£ì´ë ì ììµëë¤.
ë¤ìì ìê°í´ ë´ ìë¤:
CPU 1 CPU 2
======================= =======================
LOAD B
DIVIDE } ëë기 ëª
ë ¹ì ì¼ë°ì ì¼ë¡
DIVIDE } 긴 ìê°ì íìë¡ í©ëë¤
LOAD A
ë ì´ë ê² ë ì ììµëë¤:
: : +-------+
+-------+ | |
--->| B->2 |------>| |
+-------+ | CPU 2 |
: :DIVIDE | |
+-------+ | |
ëë기 íëë¼ ë°ì ---> --->| A->0 |~~~~ | |
CPU ë A ì LOAD 를 +-------+ ~ | |
ì측í´ì ìííë¤ : : ~ | |
: :DIVIDE | |
: : ~ | |
ëëê¸°ê° ëëë©´ ---> ---> : : ~-->| |
CPU ë í´ë¹ LOAD 를 : : | |
ì¦ê° ìë£íë¤ : : +-------+
ì½ê¸° 배리ì´ë ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë¥¼ ëë²ì§¸ ë¡ë ì§ì ì ëëë¤ë©´:
CPU 1 CPU 2
======================= =======================
LOAD B
DIVIDE
DIVIDE
<ì½ê¸° 배리ì´>
LOAD A
ì측ì¼ë¡ ì»ì´ì§ ê°ì ì¬ì©ë 배리ì´ì íì
ì ë°ë¼ì í´ë¹ ê°ì´ ì³ìì§ ê²í ëê²
ë©ëë¤. ë§ì½ í´ë¹ ë©ëª¨ë¦¬ ììì ë³íê° ììë¤ë©´, ì측ì¼ë¡ ì»ì´ëìë ê°ì´
ì¬ì©ë©ëë¤:
: : +-------+
+-------+ | |
--->| B->2 |------>| |
+-------+ | CPU 2 |
: :DIVIDE | |
+-------+ | |
ëë기 íëë¼ ë°ì ---> --->| A->0 |~~~~ | |
CPU ë A ì LOAD 를 +-------+ ~ | |
ì측íë¤ : : ~ | |
: :DIVIDE | |
: : ~ | |
: : ~ | |
rrrrrrrrrrrrrrrr~ | |
: : ~ | |
: : ~-->| |
: : | |
: : +-------+
íì§ë§ ë¤ë¥¸ CPU ìì ì
ë°ì´í¸ë 무í¨íê° ììë¤ë©´, ê·¸ ì측ì 무í¨íëê³ ê·¸ ê°ì
ë¤ì ì½íì§ëë¤:
: : +-------+
+-------+ | |
--->| B->2 |------>| |
+-------+ | CPU 2 |
: :DIVIDE | |
+-------+ | |
ëë기 íëë¼ ë°ì ---> --->| A->0 |~~~~ | |
CPU ë A ì LOAD 를 +-------+ ~ | |
ì측íë¤ : : ~ | |
: :DIVIDE | |
: : ~ | |
: : ~ | |
rrrrrrrrrrrrrrrrr | |
+-------+ | |
ìì¸¡ì± ëìì 무í¨í ëê³ ---> --->| A->1 |------>| |
ì
ë°ì´í¸ë ê°ì´ ë¤ì ì½íì§ë¤ +-------+ | |
: : +-------+
MULTICOPY ììì±
Multicopy ììì±ì ì¤ì ì ì»´í¨í° ìì¤í
ìì íì ì ê³µëì§ë ìë, ìì ë§ì¶ê¸°ì
ëí ìë¹í ì§ê´ì ì¸ ê°ë
ì¼ë¡, í¹ì ì¤í ì´ê° 모ë CPU ë¤ìê² ëìì ë³´ì¬ì§ê²
ë¨ì, ë¬ë¦¬ ë§íìë©´ 모ë CPU ë¤ì´ 모ë ì¤í ì´ë¤ì´ ë³´ì¬ì§ë ìì를 ëìíê² ëë
ê²ì
ëë¤. íì§ë§, ìì í multicopy ììì±ì ì¬ì©ì ê°ì¹ìë íëì¨ì´
ìµì íë¤ì 무ë¥íê² ë§ë¤ì´ë²ë¦´ ì ìì´ì, ë³´ë¤ ìíë ííì ë¤ë¥¸ multicopy ììì±'' ë¼ë ì´ë¦ì, í¹ì ì¤í ì´ê° 모ë -ë¤ë¥¸- CPU ë¤ìê²ë ëìì ë³´ì¬ì§ê² íë ë³´ì¥ì ëì ì ê³µí©ëë¤. ì´ ë¬¸ìì ë·ë¶ë¶ë¤ì ì´ ìíë ííì ëí´ ë
¼íê² ë©ëë¤ë§, ë¨ìí
multicopy ììì±’’ ì´ë¼ê³ ë¶ë¥´ê² ìµëë¤.
ë¤ìì ìê° multicopy ììì±ì ë³´ì ëë¤:
CPU 1 CPU 2 CPU 3
======================= ======================= =======================
{ X = 0, Y = 0 }
STORE X=1 r1=LOAD X (reads 1) LOAD Y (reads 1)
<ë²ì© 배리ì´> <ì½ê¸° 배리ì´>
STORE Y=r1 LOAD X
CPU 2 ì Y ë¡ì ì¤í ì´ì ì¬ì©ëë X ë¡ëì ê²°ê³¼ê° 1 ì´ìê³ CPU 3 ì Y ë¡ëê°
1ì 리í´íë¤ê³ í´ë´
ìë¤. ì´ë CPU 1 ì X ë¡ì ì¤í ì´ê° CPU 2 ì X ë¡ë¶í°ì
ë¡ë를 ììê³ CPU 2 ì Y ë¡ì ì¤í ì´ê° CPU 3 ì Y ë¡ë¶í°ì ë¡ë를 ìì¬ì
ì미í©ëë¤. ëí, ì¬ê¸°ìì ë©ëª¨ë¦¬ 배리ì´ë¤ì CPU 2 ê° ìì ì ë¡ë를 ìì ì
ì¤í ì´ ì ì ìííê³ , CPU 3 ê° Y ë¡ë¶í°ì ë¡ë를 X ë¡ë¶í°ì ë¡ë ì ì ìíí¨ì
ë³´ì¥í©ëë¤. ê·¸ë¼ “CPU 3 ì X ë¡ë¶í°ì ë¡ëë 0 ì 리í´í ì ììê¹ì?”
CPU 3 ì X ë¡ëê° CPU 2 ì ë¡ëë³´ë¤ ë¤ì ì´ë£¨ì´ì¡ì¼ë¯ë¡, CPU 3 ì X ë¡ë¶í°ì
ë¡ëë 1 ì 리í´íë¤ê³ ììíëê² ë¹ì°í©ëë¤. ì´ë° ììì multicopy
ììì±ì¼ë¡ë¶í° ëìµëë¤: CPU B ìì ìíë ë¡ëê° CPU A ì ê°ì ë³ìë¡ë¶í°ì
ë¡ë를 ë¤ë°ë¥¸ë¤ë©´ (ê·¸ë¦¬ê³ CPU A ê° ìì ì´ ì½ì ê°ì¼ë¡ 먼ì í´ë¹ ë³ìì ì¤í ì´
íì§ ììë¤ë©´) multicopy ììì±ì ì ê³µíë ìì¤í
ììë, CPU B ì ë¡ëê° CPU A
ì ë¡ëì ê°ì ê° ëë ê·¸ ëì¤ ê°ì 리í´í´ì¼ë§ í©ëë¤. íì§ë§, 리ë
ì¤ ì»¤ëì
ìì¤í
ë¤ì´ multicopy ììì±ì ì ê³µí ê²ì ì구íì§ ììµëë¤.
ìì ë²ì© ë©ëª¨ë¦¬ 배리ì´ì ì¬ì©ì 모ë multicopy ììì±ì ë¶ì¡±ì ë³´ìí´ì¤ëë¤.
ìì ììì, CPU 2 ì X ë¡ë¶í°ì ë¡ëê° 1 ì 리í´íê³ CPU 3 ì Y ë¡ë¶í°ì
ë¡ëê° 1 ì 리í´íë¤ë©´, CPU 3 ì X ë¡ë¶í°ì ë¡ëë 1ì 리í´í´ì¼ë§ í©ëë¤.
íì§ë§, ìì¡´ì±, ì½ê¸° 배리ì´, ì°ê¸° 배리ì´ë íì non-multicopy ììì±ì ë³´ìí´
주ì§ë ììµëë¤. ì를 ë¤ì´, CPU 2 ì ë²ì© 배리ì´ê° ìì ììì ì¬ë¼ì ¸ì
ìëì²ë¼ ë°ì´í° ìì¡´ì±ë§ ë¨ê² ëìë¤ê³ í´ë´
ìë¤:
CPU 1 CPU 2 CPU 3
======================= ======================= =======================
{ X = 0, Y = 0 }
STORE X=1 r1=LOAD X (reads 1) LOAD Y (reads 1)
<ë°ì´í° ìì¡´ì±> <ì½ê¸° 배리ì´>
STORE Y=r1 LOAD X (reads 0)
ì´ ë³íë non-multicopy ììì±ì´ ë§ì°íê² í©ëë¤: ì´ ììì, CPU 2 ì X
ë¡ë¶í°ì ë¡ëê° 1ì 리í´íê³ , CPU 3 ì Y ë¡ë¶í°ì ë¡ëê° 1 ì 리í´íëë°, CPU 3
ì X ë¡ë¶í°ì ë¡ëê° 0 ì 리í´íëê² ìì í í©ë²ì ì
ëë¤.
íµì¬ì, CPU 2 ì ë°ì´í° ìì¡´ì±ì´ ìì ì ë¡ëì ì¤í ì´ë¥¼ ììì§ì§ë§, CPU 1 ì
ì¤í ì´ì ëí ììë ë³´ì¥íì§ ìëë¤ë ê²ì
ëë¤. ë°ë¼ì, ì´ ìì ê° CPU 1 ê³¼
CPU 2 ê° ì¤í ì´ ë²í¼ë í ìì¤ì ìºì를 ê³µì íë, multicopy ììì±ì ì ê³µíì§
ìë ìì¤í
ìì ìíëë¤ë©´ CPU 2 ë CPU 1 ì ì°ê¸°ì ì´ë¥¸ ì ê·¼ì í ìë
ììµëë¤. ë°ë¼ì, 모ë CPU ë¤ì´ ì¬ë¬ ì ê·¼ë¤ì ì¡°í©ë ììì ëí´ì ëìíê²
í기 ìí´ìë ë²ì© 배리ì´ê° íìí©ëë¤.
ë²ì© 배리ì´ë non-multicopy ììì±ë§ ë³´ìí ì ìëê² ìëë¼, -모ë - CPU ë¤ì´
-모ë - ì¤í¼ë ì´ì
ë¤ì ìì를 ëì¼íê² ì¸ìíê² íë ì¶ê°ì ì¸ ìì ë³´ì¥ì
ë§ë¤ì´ë
ëë¤. ë°ëë¡, release-acquire ì§ì ì°ê²°ì ì´ë° ì¶ê°ì ì¸ ììë
ì ê³µíì§ ìëë°, í´ë¹ ì°ê²°ì ë¤ì´ìë CPU ë¤ë§ì´ ë©ëª¨ë¦¬ ì ê·¼ì ì¡°í©ë ììì
ëí´ ëìí ê²ì¼ë¡ ë³´ì¥ë¨ì ì미í©ëë¤. ì를 ë¤ì´, ì¡´ê²½ì¤ë° Herman Hollerith
ì ì½ë를 C ì½ëë¡ ë³ííë©´:
int u, v, x, y, z;
void cpu0(void)
{
r0 = smp_load_acquire(&x);
WRITE_ONCE(u, 1);
smp_store_release(&y, 1);
}
void cpu1(void)
{
r1 = smp_load_acquire(&y);
r4 = READ_ONCE(v);
r5 = READ_ONCE(u);
smp_store_release(&z, 1);
}
void cpu2(void)
{
r2 = smp_load_acquire(&z);
smp_store_release(&x, 1);
}
void cpu3(void)
{
WRITE_ONCE(v, 1);
smp_mb();
r3 = READ_ONCE(u);
}
cpu0(), cpu1(), ê·¸ë¦¬ê³ cpu2() ë smp_store_release()/smp_load_acquire() ìì
ì°ê²°ì ì°¸ì¬ëì´ ìì¼ë¯ë¡, ë¤ìê³¼ ê°ì ê²°ê³¼ë ëì¤ì§ ìì ê²ëë¤:
r0 == 1 && r1 == 1 && r2 == 1
ë ëìê°ì, cpu0() ì cpu1() ì¬ì´ì release-acquire ê´ê³ë¡ ì¸í´, cpu1() ì
cpu0() ì ì°ê¸°ë¥¼ ë´ì¼ë§ íë¯ë¡, ë¤ìê³¼ ê°ì ê²°ê³¼ë ìì ê²ëë¤:
r1 == 1 && r5 == 0
íì§ë§, release-acquire ì ìí´ ì ê³µëë ììë í´ë¹ ì°ê²°ì ëì°¸í CPU ë¤ìë§
ì ì©ëë¯ë¡ cpu3() ì, ì ì´ë ì¤í ì´ë¤ ì¸ìë ì ì©ëì§ ììµëë¤. ë°ë¼ì, ë¤ìê³¼
ê°ì ê²°ê³¼ê° ê°ë¥í©ëë¤:
r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0
ë¹ì·íê², ë¤ìê³¼ ê°ì ê²°ê³¼ë ê°ë¥í©ëë¤:
r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 && r5 == 1
cpu0(), cpu1(), ê·¸ë¦¬ê³ cpu2() ë ê·¸ë¤ì ì½ê¸°ì ì°ê¸°ë¥¼ ììëë¡ ë³´ê² ëì§ë§,
release-acquire ì²´ì¸ì ê´ì¬ëì§ ìì CPU ë¤ì ê·¸ ììì ì´ê²¬ì ê°ì§ ì
ììµëë¤. ì´ë° ì´ê²¬ì smp_load_acquire() ì smp_store_release() ì 구íì
ì¬ì©ëë ìíë ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ì¸ì¤í¸ëì
ë¤ì íì ë°°ë¦¬ì´ ìì ì¤í ì´ë¤ì ë¤ì
ë¡ëë¤ì ìì¸ì¸ íìë ìë¤ë ì¬ì¤ìì 기ì¸í©ëë¤. ì´ ë§ì cpu3() ë cpu0() ì
u ë¡ì ì¤í ì´ë¥¼ cpu1() ì v ë¡ë¶í°ì ë¡ë ë¤ì ì¼ì´ë ê²ì¼ë¡ ë³¼ ì ìë¤ë
ë»ì
ëë¤, cpu0() ì cpu1() ì ì´ ë ì¤í¼ë ì´ì
ì´ ìëë ììëë¡ ì¼ì´ë¬ìì
모ë ëìíëë°ë ë§ì
ëë¤.
íì§ë§, smp_load_acquire() ë ë§ì ì´ ìëì ëª
ì¬íì기 ë°ëëë¤. 구체ì ì¼ë¡,
ì´ í¨ìë ë¨ìí ìì ê·ì¹ì ì§í¤ë©° ì¸ìë¡ë¶í°ì ì½ê¸°ë¥¼ ìíí©ëë¤. ì´ê²ì
ì´ë¤ í¹ì í ê°ì´ ì½í ê²ì¸ì§ë ë³´ì¥íì§ -ììµëë¤-. ë°ë¼ì, ë¤ìê³¼ ê°ì ê²°ê³¼ë
ê°ë¥í©ëë¤:
r0 == 0 && r1 == 0 && r2 == 0 && r5 == 0
ì´ë° ê²°ê³¼ë ì´ë¤ ê²ë ì¬ë°°ì¹ ëì§ ìë, ìì°¨ì ì¼ê´ì±ì ê°ì§ ê°ìì
ìì¤í
ììë ì¼ì´ë ì ììì 기ìµí´ ëì기 ë°ëëë¤.
ë¤ì ë§íì§ë§, ë¹ì ì ì½ëê° ëª¨ë ì¤í¼ë ì´ì
ë¤ì ìì í ìì를 íìë¡ íë¤ë©´,
ë²ì© 배리ì´ë¥¼ ì¬ì©íììì¤.
==================
ëª
ìì 커ë 배리ì´
==================
리ë ì¤ ì»¤ëì ìë¡ ë¤ë¥¸ ë¨ê³ìì ëìíë ë¤ìí 배리ì´ë¤ì ê°ì§ê³ ììµëë¤:
(*) ì»´íì¼ë¬ 배리ì´.
(*) CPU ë©ëª¨ë¦¬ 배리ì´.
(*) MMIO ì°ê¸° 배리ì´.
ì»´íì¼ë¬ 배리ì´
리ë
ì¤ ì»¤ëì ì»´íì¼ë¬ê° ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¥¼ ì¬ë°°ì¹ íë ê²ì ë§ì주ë ëª
ìì ì¸
ì»´íì¼ë¬ 배리ì´ë¥¼ ê°ì§ê³ ììµëë¤:
barrier();
ì´ê±´ ë²ì© 배리ì´ì
ëë¤ – barrier() ì ì½ê¸°-ì½ê¸° ë ì°ê¸°-ì°ê¸° ë³ì¢
ì ììµëë¤.
íì§ë§, READ_ONCE() ì WRITE_ONCE() ë í¹ì ì¡ì¸ì¤ë¤ì ëí´ìë§ ëìíë
barrier() ì ìíë ííë¡ ë³¼ ì ììµëë¤.
barrier() í¨ìë ë¤ìê³¼ ê°ì í¨ê³¼ë¥¼ ê°ìµëë¤:
(*) ì»´íì¼ë¬ê° barrier() ë¤ì ì¡ì¸ì¤ë¤ì´ barrier() ìì ì¡ì¸ì¤ë³´ë¤ ìì¼ë¡
ì¬ë°°ì¹ëì§ ëª»íê² í©ëë¤. ì를 ë¤ì´, ì¸í°ë½í¸ í¸ë¤ë¬ ì½ëì ì¸í°ë½í¸ ë¹í
ì½ë ì¬ì´ì íµì ì ì ì¤í í기 ìí´ ì¬ì©ë ì ììµëë¤.
(*) 루íìì, ì»´íì¼ë¬ê° 루í ì¡°ê±´ì ì¬ì©ë ë³ì를 매 ì´í°ë ì´ì
ë§ë¤
ë©ëª¨ë¦¬ìì ë¡ëíì§ ììë ëëë¡ ìµì í íë걸 ë°©ì§í©ëë¤.
READ_ONCE() ì WRITE_ONCE() í¨ìë ì±ê¸ ì°ë ë ì½ëììë 문ì ìì§ë§ ëìì±ì´
ìë ì½ëììë 문ì ê° ë ì ìë 모ë ìµì í를 ë§ìµëë¤. ì´ë° ë¥ì ìµì íì
ëí ì를 ëªê°ì§ ë¤ì´ë³´ë©´ ë¤ìê³¼ ê°ìµëë¤:
(*) ì»´íì¼ë¬ë ê°ì ë³ìì ëí ë¡ëì ì¤í ì´ë¥¼ ì¬ë°°ì¹ í ì ìê³ , ì´ë¤
ê²½ì°ìë CPUê° ê°ì ë³ìë¡ë¶í°ì ë¡ëë¤ì ì¬ë°°ì¹í ìë ììµëë¤. ì´ë
ë¤ìì ì½ëê°:
a[0] = x;
a[1] = x;
x ì ìì ê°ì´ a[1] ì, ì ê°ì´ a[0] ì ìê² í ì ìë¤ë ë»ì
ëë¤.
ì»´íì¼ë¬ì CPUê° ì´ë° ì¼ì 못íê² íë ¤ë©´ ë¤ìê³¼ ê°ì´ í´ì¼ í©ëë¤:
a[0] = READ_ONCE(x);
a[1] = READ_ONCE(x);
ì¦, READ_ONCE() ì WRITE_ONCE() ë ì¬ë¬ CPU ìì íëì ë³ìì ê°í´ì§ë
ì¡ì¸ì¤ë¤ì ìºì ì¼ê´ì±ì ì ê³µí©ëë¤.
(*) ì»´íì¼ë¬ë ê°ì ë³ìì ëí ì°ìì ì¸ ë¡ëë¤ì ë³í©í ì ììµëë¤. ê·¸ë°
ë³í© ìì
ì¼ë¡ ì»´íì¼ë¬ë ë¤ìì ì½ë를:
while (tmp = a)
do_something_with(tmp);
ë¤ìê³¼ ê°ì´, ì±ê¸ ì°ë ë ì½ëììë ë§ì´ ëì§ë§ ê°ë°ìì ìëì ì í ë§ì§
ìë ë°©í¥ì¼ë¡ "ìµì í" í ì ììµëë¤:
if (tmp = a)
for (;;)
do_something_with(tmp);
ì»´íì¼ë¬ê° ì´ë° ì§ì íì§ ëª»íê² íë ¤ë©´ READ_ONCE() 를 ì¬ì©íì¸ì:
while (tmp = READ_ONCE(a))
do_something_with(tmp);
(*) ì컨ë ë ì§ì¤í° ì¬ì©ëì´ ë§ì ì»´íì¼ë¬ê° 모ë ë°ì´í°ë¥¼ ë ì§ì¤í°ì ë´ì ì
ìë ê²½ì°, ì»´íì¼ë¬ë ë³ì를 ë¤ì ë¡ëí ì ììµëë¤. ë°ë¼ì ì»´íì¼ë¬ë
ìì ììì ë³ì ‘tmp’ ì¬ì©ì ìµì íë¡ ìì ë²ë¦´ ì ììµëë¤:
while (tmp = a)
do_something_with(tmp);
ì´ ì½ëë ë¤ìê³¼ ê°ì´ ì±ê¸ ì°ë ëììë ìë²½íì§ë§ ëìì±ì´ ì¡´ì¬íë
ê²½ì°ì ì¹ëª
ì ì¸ ì½ëë¡ ë°ë ì ììµëë¤:
while (a)
do_something_with(a);
ì를 ë¤ì´, ìµì íë ì´ ì½ëë ë³ì a ê° ë¤ë¥¸ CPU ì ìí´ "while" 문과
do_something_with() í¸ì¶ ì¬ì´ì ë°ëì´ do_something_with() ì 0ì ë길
ìë ììµëë¤.
ì´ë²ìë, ì»´íì¼ë¬ê° ê·¸ë° ì§ì íë걸 ë§ê¸° ìí´ READ_ONCE() 를 ì¬ì©íì¸ì:
while (tmp = READ_ONCE(a))
do_something_with(tmp);
ë ì§ì¤í°ê° ë¶ì¡±í ìí©ì 겪ë ê²½ì°, ì»´íì¼ë¬ë tmp 를 ì¤íì ì ì¥í´ë ìë
ììµëë¤. ì»´íì¼ë¬ê° ë³ì를 ë¤ì ì½ì´ë¤ì´ëê±´ ì´ë ê² ì ì¥í´ëê³ íì ë¤ì
ì½ì´ë¤ì´ëë° ëë ì¤ë²í¤ë ë문ì
ëë¤. ê·¸ë ê² íëê² ì±ê¸ ì°ë ë
ì½ëììë ìì íë¯ë¡, ìì íì§ ìì ê²½ì°ìë ì»´íì¼ë¬ìê² ì§ì ìë ¤ì¤ì¼
í©ëë¤.
(*) ì»´íì¼ë¬ë ê·¸ ê°ì´ 무ìì¼ì§ ìê³ ìë¤ë©´ ë¡ë를 ìì ìí ìë ììµëë¤.
ì를 ë¤ì´, ë¤ìì ì½ëë ë³ì ‘a’ ì ê°ì´ íì 0ìì ì¦ëª
í ì ìë¤ë©´:
while (tmp = a)
do_something_with(tmp);
ì´ë ê² ìµì í ëì´ë²ë¦´ ì ììµëë¤:
do { } while (0);
ì´ ë³íì ì±ê¸ ì°ë ë ì½ëììë ëìì´ ëëë° ë¡ëì ë¸ëì¹ë¥¼ ì ê±°í기
ë문ì
ëë¤. 문ì ë ì»´íì¼ë¬ê° 'a' ì ê°ì ì
ë°ì´í¸ íëê±´ íì¬ì CPU íë
ë¿ì´ë¼ë ê°ì ììì ì¦ëª
ì íë¤ëë° ììµëë¤. ë§ì½ ë³ì 'a' ê° ê³µì ëì´
ìë¤ë©´, ì»´íì¼ë¬ì ì¦ëª
ì í린 ê²ì´ ë ê²ëë¤. ì»´íì¼ë¬ë ê·¸ ìì ì´
ìê°íë ê²ë§í¼ ë§ì ê²ì ìê³ ìì§ ëª»í¨ì ì»´íì¼ë¬ìê² ì리기 ìí´
READ_ONCE() 를 ì¬ì©íì¸ì:
while (tmp = READ_ONCE(a))
do_something_with(tmp);
íì§ë§ ì»´íì¼ë¬ë READ_ONCE() ë¤ì ëì¤ë ê°ì ëí´ìë ë길ì ëê³ ììì
기ìµíì¸ì. ì를 ë¤ì´, ë¤ìì ì½ëìì MAX ë ì ì²ë¦¬ê¸° 매í¬ë¡ë¡, 1ì ê°ì
ê°ëë¤ê³ í´ë´
ìë¤:
while ((tmp = READ_ONCE(a)) % MAX)
do_something_with(tmp);
ì´ë ê² ëë©´ ì»´íì¼ë¬ë MAX 를 ê°ì§ê³ ìíëë "%" ì¤í¼ë ì´í°ì ê²°ê³¼ê° íì
0ì´ë¼ë ê²ì ìê² ëê³ , ì»´íì¼ë¬ê° ì½ë를 ì¤ì§ì ì¼ë¡ë ì¡´ì¬íì§ ìë
ê²ì²ë¼ ìµì í íë ê²ì´ íì©ëì´ ë²ë¦½ëë¤. ('a' ë³ìì ë¡ëë ì¬ì í
íí´ì§ ê²ëë¤.)
(*) ë¹ì·íê², ì»´íì¼ë¬ë ë³ìê° ì ì¥íë ¤ íë ê°ì ì´ë¯¸ ê°ì§ê³ ìë¤ë ê²ì
ìë©´ ì¤í ì´ ì체를 ì ê±°í ì ììµëë¤. ì´ë²ìë, ì»´íì¼ë¬ë íì¬ì CPU
ë§ì´ ê·¸ ë³ìì ê°ì ì°ë ì¤ë¡ì§ íëì ì¡´ì¬ë¼ê³ ìê°íì¬ ê³µì ë ë³ìì
ëí´ìë ì못ë ì¼ì íê² ë©ëë¤. ì를 ë¤ì´, ë¤ìê³¼ ê°ì ê²½ì°ê° ìì ì
ììµëë¤:
a = 0;
... ë³ì a ì ì¤í ì´ë¥¼ íì§ ìë ì½ë ...
a = 0;
ì»´íì¼ë¬ë ë³ì 'a' ì ê°ì ì´ë¯¸ 0ì´ë¼ë ê²ì ìê³ , ë°ë¼ì ëë²ì§¸ ì¤í ì´ë¥¼
ìì í ê²ëë¤. ë§ì½ ë¤ë¥¸ CPU ê° ê·¸ ì¬ì´ ë³ì 'a' ì ë¤ë¥¸ ê°ì ì¼ë¤ë©´
í©ë¹í ê²°ê³¼ê° ëì¬ ê²ëë¤.
ì»´íì¼ë¬ê° ê·¸ë° ì못ë ì¶ì¸¡ì íì§ ìëë¡ WRITE_ONCE() 를 ì¬ì©íì¸ì:
WRITE_ONCE(a, 0);
... ë³ì a ì ì¤í ì´ë¥¼ íì§ ìë ì½ë ...
WRITE_ONCE(a, 0);
(*) ì»´íì¼ë¬ë íì§ ë§ë¼ê³ íì§ ìì¼ë©´ ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¤ì ì¬ë°°ì¹ í ì
ììµëë¤. ì를 ë¤ì´, ë¤ìì íë¡ì¸ì¤ ë 벨 ì½ëì ì¸í°ë½í¸ í¸ë¤ë¬ ì¬ì´ì
ìí¸ìì©ì ìê°í´ ë´
ìë¤:
void process_level(void)
{
msg = get_message();
flag = true;
}
void interrupt_handler(void)
{
if (flag)
process_message(msg);
}
ì´ ì½ëìë ì»´íì¼ë¬ê° process_level() ì ë¤ìê³¼ ê°ì´ ë³ííë ê²ì ë§ì
ìë¨ì´ ìê³ , ì´ë° ë³íì ì±ê¸ì°ë ëììë¼ë©´ ì¤ì ë¡ íë¥í ì íì¼ ì
ììµëë¤:
void process_level(void)
{
flag = true;
msg = get_message();
}
ì´ ëê°ì ë¬¸ì¥ ì¬ì´ì ì¸í°ë½í¸ê° ë°ìíë¤ë©´, interrupt_handler() ë ì미를
ì ì ìë ë©ì¸ì§ë¥¼ ë°ì ìë ììµëë¤. ì´ê±¸ ë§ê¸° ìí´ ë¤ìê³¼ ê°ì´
WRITE_ONCE() 를 ì¬ì©íì¸ì:
void process_level(void)
{
WRITE_ONCE(msg, get_message());
WRITE_ONCE(flag, true);
}
void interrupt_handler(void)
{
if (READ_ONCE(flag))
process_message(READ_ONCE(msg));
}
interrupt_handler() ìììë ì¤ì²©ë ì¸í°ë½í¸ë NMI ì ê°ì´ ì¸í°ë½í¸ í¸ë¤ë¬
ìì 'flag' ì 'msg' ì ì ê·¼íë ëë¤ë¥¸ 무ì¸ê°ì ì¸í°ë½í¸ ë ì ìë¤ë©´
READ_ONCE() ì WRITE_ONCE() 를 ì¬ì©í´ì¼ í¨ì 기ìµí´ ëì¸ì. ë§ì½ ê·¸ë°
ê°ë¥ì±ì´ ìë¤ë©´, interrupt_handler() ìììë 문ìí 목ì ì´ ìëë¼ë©´
READ_ONCE() ì WRITE_ONCE() ë íìì¹ ììµëë¤. (ê·¼ëì 리ë
ì¤ ì»¤ëìì
ì¤ì²©ë ì¸í°ë½í¸ë ë³´íµ ì ì¼ì´ëì§ ììë 기ìµí´ ëì¸ì, ì¤ì ë¡, ì´ë¤
ì¸í°ë½í¸ í¸ë¤ë¬ê° ì¸í°ë½í¸ê° íì±íë ì±ë¡ 리í´íë©´ WARN_ONCE() ê°
ì¤íë©ëë¤.)
ì»´íì¼ë¬ë READ_ONCE() ì WRITE_ONCE() ë¤ì READ_ONCE() ë WRITE_ONCE(),
barrier(), ëë ë¹ì·í ê²ë¤ì ë´ê³ ìì§ ìì ì½ë를 ìì§ì¼ ì ìì ê²ì¼ë¡
ê°ì ëì´ì¼ í©ëë¤.
ì´ í¨ê³¼ë barrier() 를 íµí´ìë ë§ë¤ ì ìì§ë§, READ_ONCE() ì
WRITE_ONCE() ê° ì¢ ë ì목 ëì ì íì
ëë¤: READ_ONCE() ì WRITE_ONCE()ë
ì»´íì¼ë¬ì 주ì´ì§ ë©ëª¨ë¦¬ ììì ëí´ìë§ ìµì í ê°ë¥ì±ì í¬ê¸°íëë¡
íì§ë§, barrier() ë ì»´íì¼ë¬ê° ì§ê¸ê¹ì§ 기ê³ì ë ì§ì¤í°ì ìºìí´ ëì
모ë ë©ëª¨ë¦¬ ììì ê°ì ë²ë ¤ì¼ íê² í기 ë문ì
ëë¤. ë¬¼ë¡ , ì»´íì¼ë¬ë
READ_ONCE() ì WRITE_ONCE() ê° ì¼ì´ë ììë ì§ì¼ì¤ëë¤, CPU ë ë¹ì°í
ê·¸ ìì를 ì§í¬ ìë¬´ê° ìì§ë§ì.
(*) ì»´íì¼ë¬ë ë¤ìì ìììì ê°ì´ ë³ììì ì¤í ì´ë¥¼ ë ì¡°í´ë¼ ìë ììµëë¤:
if (a)
b = a;
else
b = 42;
ì»´íì¼ë¬ë ìëì ê°ì ìµì íë¡ ë¸ëì¹ë¥¼ ì¤ì¼ ê²ëë¤:
b = 42;
if (a)
b = a;
ì±ê¸ ì°ë ë ì½ëìì ì´ ìµì íë ìì í ë¿ ìëë¼ ë¸ëì¹ ê°¯ì를
ì¤ì¬ì¤ëë¤. íì§ë§ ìíê¹ê²ë, ëìì±ì´ ìë ì½ëììë ì´ ìµì íë ë¤ë¥¸
CPU ê° 'b' 를 ë¡ëí ë, -- 'a' ê° 0ì´ ìëë°ë -- ê°ì§ì¸ ê°, 42를 ë³´ê²
ëë ê²½ì°ë¥¼ ê°ë¥íê² í©ëë¤. ì´ê±¸ ë°©ì§í기 ìí´ WRITE_ONCE() 를
ì¬ì©íì¸ì:
if (a)
WRITE_ONCE(b, a);
else
WRITE_ONCE(b, 42);
ì»´íì¼ë¬ë ë¡ë를 ë§ë¤ì´ë¼ ìë ììµëë¤. ì¼ë°ì ì¼ë¡ë 문ì 를 ì¼ì¼í¤ì§
ìì§ë§, ìºì ë¼ì¸ ë°ì´ì±ì ì¼ì¼ì¼ ì±ë¥ê³¼ íì¥ì±ì ë¨ì´ë¨ë¦´ ì ììµëë¤.
ë ì¡°ë ë¡ë를 ë§ê¸° ìí´ì READ_ONCE() 를 ì¬ì©íì¸ì.
(*) ì ë ¬ë ë©ëª¨ë¦¬ 주ìì ìì¹í, íë²ì ë©ëª¨ë¦¬ 참조 ì¸ì¤í¸ëì
ì¼ë¡ ì¡ì¸ì¤
ê°ë¥í í¬ê¸°ì ë°ì´í°ë íëì í° ì¡ì¸ì¤ê° ì¬ë¬ê°ì ìì ì¡ì¸ì¤ë¤ë¡
ëì²´ëë “ë¡ë í°ì´ë§(load tearing)” ê³¼ “ì¤í ì´ í°ì´ë§(store tearing)” ì
ë°©ì§í©ëë¤. ì를 ë¤ì´, 주ì´ì§ ìí¤í
ì³ê° 7-bit imeediate field 를 ê°ë
16-bit ì¤í ì´ ì¸ì¤í¸ëì
ì ì ê³µíë¤ë©´, ì»´íì¼ë¬ë ë¤ìì 32-bit ì¤í ì´ë¥¼
구ííëë°ì ëê°ì 16-bit store-immediate ëª
ë ¹ì ì¬ì©íë ¤ í ê²ëë¤:
p = 0x00010002;
ì¤í ì´ í ìì를 ë§ë¤ê³ ê·¸ ê°ì ì¤í ì´ í기 ìí´ ëê°ê° ëë ì¸ì¤í¸ëì
ì
ì¬ì©íê² ëë, ì´ë° ì¢
ë¥ì ìµì í를 GCC ë ì¤ì ë¡ í¨ì ë¶ë ìì ëììì¤.
ì´ ìµì íë ì±ê¸ ì°ë ë ì½ëììë ì±ê³µì ì¸ ìµì í ì
ëë¤. ì¤ì ë¡, ê·¼ëì
ë°ìí (ê·¸ë¦¬ê³ ê³ ì³ì§) ë²ê·¸ë GCC ê° volatile ì¤í ì´ì ë¹ì ìì ì¼ë¡ ì´
ìµì í를 ì¬ì©íê² íìµëë¤. ê·¸ë° ë²ê·¸ê° ìë¤ë©´, ë¤ìì ììì
WRITE_ONCE() ì ì¬ì©ì ì¤í ì´ í°ì´ë§ì ë°©ì§í©ëë¤:
WRITE_ONCE(p, 0x00010002);
Packed 구조체ì ì¬ì© ìì ë¤ìì ìì²ë¼ ë¡ë / ì¤í ì´ í°ì´ë§ì ì ë°í ì
ììµëë¤:
struct __attribute__((__packed__)) foo {
short a;
int b;
short c;
};
struct foo foo1, foo2;
...
foo2.a = foo1.a;
foo2.b = foo1.b;
foo2.c = foo1.c;
READ_ONCE() ë WRITE_ONCE() ë ìê³ volatile ë§í¹ë ì기 ë문ì,
ì»´íì¼ë¬ë ì´ ì¸ê°ì ëì
문ì ëê°ì 32-bit ë¡ëì ëê°ì 32-bit ì¤í ì´ë¡
ë³íí ì ììµëë¤. ì´ë 'foo1.b' ì ê°ì ë¡ë í°ì´ë§ê³¼ 'foo2.b' ì
ì¤í ì´ í°ì´ë§ì ì´ëí ê²ëë¤. ì´ ìììë READ_ONCE() ì WRITE_ONCE()
ê° í°ì´ë§ì ë§ì ì ììµëë¤:
foo2.a = foo1.a;
WRITE_ONCE(foo2.b, READ_ONCE(foo1.b));
foo2.c = foo1.c;
ê·¸ë ì§ë§, volatile ë¡ ë§í¬ë ë³ìì ëí´ìë READ_ONCE() ì WRITE_ONCE() ê°
íìì¹ ììµëë¤. ì를 ë¤ì´, ‘jiffies’ ë volatile ë¡ ë§í¬ëì´ ì기 ë문ì,
READ_ONCE(jiffies) ë¼ê³ í íìê° ììµëë¤. READ_ONCE() ì WRITE_ONCE() ê°
ì¤ì volatile ìºì¤í
ì¼ë¡ 구íëì´ ìì´ì ì¸ìê° ì´ë¯¸ volatile ë¡ ë§í¬ëì´
ìë¤ë©´ ëë¤ë¥¸ í¨ê³¼ë¥¼ ë´ì§ë ì기 ë문ì
ëë¤.
ì´ ì»´íì¼ë¬ 배리ì´ë¤ì CPU ìë ì§ì ì í¨ê³¼ë¥¼ ì í ë§ë¤ì§ ì기 ë문ì, ê²°êµì
ì¬ë°°ì¹ê° ì¼ì´ë ìë ììì ë¶ë 기ìµí´ ëììì¤.
CPU ë©ëª¨ë¦¬ 배리ì´
리ë ì¤ ì»¤ëì ë¤ìì ì¬ëê° ê¸°ë³¸ CPU ë©ëª¨ë¦¬ 배리ì´ë¥¼ ê°ì§ê³ ììµëë¤:
TYPE MANDATORY SMP CONDITIONAL
=============== ======================= ===========================
ë²ì© mb() smp_mb()
ì°ê¸° wmb() smp_wmb()
ì½ê¸° rmb() smp_rmb()
ë°ì´í° ìì¡´ì± READ_ONCE()
ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë¥¼ ì ì¸í 모ë ë©ëª¨ë¦¬ 배리ì´ë ì»´íì¼ë¬ 배리ì´ë¥¼
í¬í¨í©ëë¤. ë°ì´í° ìì¡´ì±ì ì»´íì¼ë¬ìì ì¶ê°ì ì¸ ìì ë³´ì¥ì í¬í¨íì§
ììµëë¤.
ë°©ë°±: ë°ì´í° ìì¡´ì±ì´ ìë ê²½ì°, ì»´íì¼ë¬ë í´ë¹ ë¡ë를 ì¬ë°ë¥¸ ììë¡ ì¼ì¼í¬
ê²ì¼ë¡ (ì: a[b]
ë a[b] 를 ë¡ë í기 ì ì b ì ê°ì 먼ì ë¡ëíë¤)
기ëëì§ë§, C ì¸ì´ ì¬ììë ì»´íì¼ë¬ê° b ì ê°ì ì¶ì¸¡ (ì: 1 ê³¼ ê°ì) í´ì
b ë¡ë ì ì a ë¡ë를 íë ì½ë (ì: tmp = a[1]; if (b != 1) tmp = a[b]; ) 를
ë§ë¤ì§ ììì¼ íë¤ë ë´ì© ê°ì ê±´ ììµëë¤. ëí ì»´íì¼ë¬ë a[b] 를 ë¡ëí
íì b 를 ëë¤ì ë¡ëí ìë ìì´ì, a[b] ë³´ë¤ ìµì ë²ì ì b ê°ì ê°ì§ ìë
ììµëë¤. ì´ë° 문ì ë¤ì í´ê²°ì±
ì ëí ì견 ì¼ì¹ë ìì§ ììµëë¤ë§, ì¼ë¨
READ_ONCE() 매í¬ë¡ë¶í° 보기 ììíëê² ì¢ì ììì´ ë ê²ëë¤.
SMP ë©ëª¨ë¦¬ 배리ì´ë¤ì ì ëíë¡ì¸ìë¡ ì»´íì¼ë ìì¤í
ììë ì»´íì¼ë¬ 배리ì´ë¡
ë°ëëë°, íëì CPU ë ì¤ì¤ë¡ ì¼ê´ì±ì ì ì§íê³ , ê²¹ì¹ë ì¡ì¸ì¤ë¤ ìì ì¬ë°ë¥¸
ììë¡ íí´ì§ ê²ì¼ë¡ ìê°ë기 ë문ì
ëë¤. íì§ë§, ìëì “Virtual Machine
Guests” ìë¸ì¹ì
ì ì°¸ê³ íììì¤.
[!] SMP ìì¤í
ìì ê³µì ë©ëª¨ë¦¬ë¡ì ì ê·¼ë¤ì ìì ì¸ìì¼ í ë, SMP ë©ëª¨ë¦¬
배리ì´ë ë°ëì ì¬ì©ëì´ì¼ í¨ì 기ìµíì¸ì, ê·¸ëì ë½ì ì¬ì©íë ê²ì¼ë¡ë
충ë¶í긴 íì§ë§ ë§ì´ì£ .
Mandatory 배리ì´ë¤ì SMP ìì¤í
ììë UP ìì¤í
ììë SMP í¨ê³¼ë§ íµì í기ìë
ë¶íìí ì¤ë²í¤ë를 ê°ê¸° ë문ì SMP í¨ê³¼ë§ íµì íë©´ ëë ê³³ìë ì¬ì©ëì§ ììì¼
í©ëë¤. íì§ë§, ëì¨í ìì ê·ì¹ì ë©ëª¨ë¦¬ I/O ìëì°ë¥¼ íµí MMIO ì í¨ê³¼ë¥¼
íµì í ëìë mandatory 배리ì´ë¤ì´ ì¬ì©ë ì ììµëë¤. ì´ ë°°ë¦¬ì´ë¤ì
ì»´íì¼ë¬ì CPU 모ë ì¬ë°°ì¹ë¥¼ 못íëë¡ í¨ì¼ë¡ì¨ ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì´ ëë°ì´ì¤ì
ë³´ì¬ì§ë ìììë ìí¥ì 주기 ë문ì, SMP ê° ìë ìì¤í
ì´ë¼ í ì§ë¼ë íìí ì
ììµëë¤.
ì¼ë¶ ê³ ê¸ ë°°ë¦¬ì´ í¨ìë¤ë ììµëë¤:
(*) smp_store_mb(var, value)
ì´ í¨ìë í¹ì ë³ìì í¹ì ê°ì ëì
íê³ ë²ì© ë©ëª¨ë¦¬ 배리ì´ë¥¼ 칩ëë¤.
UP ì»´íì¼ììë ì»´íì¼ë¬ 배리ì´ë³´ë¤ ëí ê²ì ì¹ë¤ê³ ë ë³´ì¥ëì§ ììµëë¤.
() smp_mb__before_atomic();
() smp_mb__after_atomic();
ì´ê²ë¤ì ê°ì 리í´íì§ ìë (ëí기, 빼기, ì¦ê°, ê°ìì ê°ì) ì´í 믹
í¨ìë¤ì ìí, í¹í ê·¸ê²ë¤ì´ ë í¼ë°ì¤ ì¹´ì´í
ì ì¬ì©ë ë를 ìí
í¨ìë¤ì
ëë¤. ì´ í¨ìë¤ì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´í¬íê³ ìì§ë ììµëë¤.
ì´ê²ë¤ì ê°ì 리í´íì§ ìì¼ë©° ì´í 믹í (set_bit ê³¼ clear_bit ê°ì) ë¹í¸
ì°ì°ìë ì¬ì©ë ì ììµëë¤.
í ìë¡, ê°ì²´ íë를 무í¨í ê²ì¼ë¡ íìíê³ ê·¸ ê°ì²´ì ë í¼ë°ì¤ ì¹´ì´í¸ë¥¼
ê°ììí¤ë ë¤ì ì½ë를 ë³´ì¸ì:
obj->dead = 1;
smp_mb__before_atomic();
atomic_dec(&obj->ref_count);
ì´ ì½ëë ê°ì²´ì ì
ë°ì´í¸ë death ë§í¬ê° ë í¼ë°ì¤ ì¹´ì´í° ê°ì ëì
*ì ì* ë³´ì¼ ê²ì ë³´ì¥í©ëë¤.
ë ë§ì ì 보를 ìí´ì Documentation/atomic_{t,bitops}.txt 문ì를
ì°¸ê³ íì¸ì.
() dma_wmb();
() dma_rmb();
ì´ê²ë¤ì CPU ì DMA ê°ë¥í ëë°ì´ì¤ìì 모ë ì¡ì¸ì¤ ê°ë¥í ê³µì ë©ëª¨ë¦¬ì
ì½ê¸°, ì°ê¸° ìì
ë¤ì ìì를 ë³´ì¥í기 ìí´ consistent memory ìì ì¬ì©í기
ìí ê²ë¤ì
ëë¤.
ì를 ë¤ì´, ëë°ì´ì¤ì ë©ëª¨ë¦¬ë¥¼ ê³µì íë©°, ëì¤í¬ë¦½í° ìí ê°ì ì¬ì©í´
ëì¤í¬ë¦½í°ê° ëë°ì´ì¤ì ìí´ ìëì§ ìëë©´ CPU ì ìí´ ìëì§ íìíê³ ,
ê³µì§ì© ì´ì¸ì¢
(doorbell) ì ì¬ì©í´ ì
ë°ì´í¸ë ëì¤í¬ë¦½í°ê° ëë°ì´ì¤ì ì¬ì©
ê°ë¥í´ì¡ìì ê³µì§íë ëë°ì´ì¤ ëë¼ì´ë²ë¥¼ ìê°í´ ë´
ìë¤:
if (desc->status != DEVICE_OWN) {
/* ëì¤í¬ë¦½í°ë¥¼ ìì í기 ì ìë ë°ì´í°ë¥¼ ì½ì§ ìì */
dma_rmb();
/* ë°ì´í°ë¥¼ ì½ê³ ì */
read_data = desc->data;
desc->data = write_data;
/* ìí ì
ë°ì´í¸ ì ìì ì¬íì ë°ì */
dma_wmb();
/* ìì ê¶ì ìì */
desc->status = DEVICE_OWN;
/* MMIO 를 íµí´ ëë°ì´ì¤ì ê³µì§ë¥¼ í기 ì ì ë©ëª¨ë¦¬ë¥¼ ë기í */
wmb();
/* ì
ë°ì´í¸ë ëì¤í¬ë¦½í°ì ëë°ì´ì¤ì ê³µì§ */
writel(DESC_NOTIFY, doorbell);
}
dma_rmb() ë ëì¤í¬ë¦½í°ë¡ë¶í° ë°ì´í°ë¥¼ ì½ì´ì¤ê¸° ì ì ëë°ì´ì¤ê° ìì ê¶ì
ë´ëììì ë³´ì¥íê² íê³ , dma_wmb() ë ëë°ì´ì¤ê° ìì ì´ ìì ê¶ì ë¤ì
ê°ì¡ìì 보기 ì ì ëì¤í¬ë¦½í°ì ë°ì´í°ê° ì°ììì ë³´ì¥í©ëë¤. wmb() ë
ìºì ì¼ê´ì±ì´ ìë (cache incoherent) MMIO ììì ì°ê¸°ë¥¼ ìëí기 ì ì
ìºì ì¼ê´ì±ì´ ìë ë©ëª¨ë¦¬ (cache coherent memory) ì°ê¸°ê° ìë£ëììì
ë³´ì¥í´ì£¼ê¸° ìí´ íìí©ëë¤.
consistent memory ì ëí ìì¸í ë´ì©ì ìí´ì Documentation/DMA-API.txt
문ì를 ì°¸ê³ íì¸ì.
MMIO ì°ê¸° 배리ì´
리ë
ì¤ ì»¤ëì ëí memory-mapped I/O ì°ê¸°ë¥¼ ìí í¹ë³í 배리ì´ë ê°ì§ê³
ììµëë¤:
mmiowb();
ì´ê²ì mandatory ì°ê¸° 배리ì´ì ë³ì¢
ì¼ë¡, ìíë ìì ê·ì¹ì I/O ìììì¼ë¡ì
ì°ê¸°ê° ë¶ë¶ì ì¼ë¡ ìì를 ë§ì¶ëë¡ í´ì¤ëë¤. ì´ í¨ìë CPU->íëì¨ì´ ì¬ì´ë¥¼
ëì´ì ì¤ì íëì¨ì´ìê¹ì§ ì¼ë¶ ìì¤ì ìí¥ì ë¼ì¹©ëë¤.
ë ë§ì ì 보를 ìí´ì “Acquire vs I/O ì¡ì¸ì¤” ìë¸ì¹ì ì ì°¸ê³ íì¸ì.
=========================
ì묵ì 커ë ë©ëª¨ë¦¬ 배리ì´
=========================
리ë
ì¤ ì»¤ëì ì¼ë¶ í¨ìë¤ì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´ì¥íê³ ìëë°, ë½(lock)ê³¼
ì¤ì¼ì¥´ë§ ê´ë ¨ í¨ìë¤ì´ ëë¶ë¶ì
ëë¤.
ì¬ê¸°ì ìµìíì ë³´ì¥ì ì¤ëª
í©ëë¤; í¹ì ìí¤í
ì³ììë ì´ ì¤ëª
ë³´ë¤ ë ë§ì
ë³´ì¥ì ì ê³µí ìë ììµëë¤ë§ í´ë¹ ìí¤í
ì³ì ì¢
ìì ì¸ ì½ë ì¸ì ë¶ë¶ììë
ê·¸ë° ë³´ì¥ì 기ëí´ì ìë ê²ëë¤.
ë½ ACQUISITION í¨ì
리ë ì¤ ì»¤ëì ë¤ìí ë½ êµ¬ì±ì²´ë¥¼ ê°ì§ê³ ììµëë¤:
() ì¤í ë½
() R/W ì¤í ë½
() 뮤í
ì¤
() ì¸ë§í¬ì´
(*) R/W ì¸ë§í¬ì´
ê° êµ¬ì±ì²´ë§ë¤ 모ë ê²½ì°ì “ACQUIRE” ì¤í¼ë ì´ì
ê³¼ “RELEASE” ì¤í¼ë ì´ì
ì ë³ì¢
ì´
ì¡´ì¬í©ëë¤. ì´ ì¤í¼ë ì´ì
ë¤ì 모ë ì ì í 배리ì´ë¥¼ ë´í¬íê³ ììµëë¤:
(1) ACQUIRE ì¤í¼ë ì´ì ì ìí¥:
ACQUIRE ë¤ìì ìì²ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ì ACQUIRE ì¤í¼ë ì´ì
ì´ ìë£ë
ë¤ì ìë£ë©ëë¤.
ACQUIRE ììì ìì²ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ì ACQUIRE ì¤í¼ë ì´ì
ì´ ìë£ë íì
ìë£ë ì ììµëë¤.
(2) RELEASE ì¤í¼ë ì´ì ì ìí¥:
RELEASE ììì ìì²ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ì RELEASE ì¤í¼ë ì´ì
ì´ ìë£ë기
ì ì ìë£ë©ëë¤.
RELEASE ë¤ìì ìì²ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ì RELEASE ì¤í¼ë ì´ì
ìë£ ì ì
ìë£ë ì ììµëë¤.
(3) ACQUIRE vs ACQUIRE ìí¥:
ì´ë¤ ACQUIRE ì¤í¼ë ì´ì
ë³´ë¤ ììì ìì²ë 모ë ACQUIRE ì¤í¼ë ì´ì
ì ê·¸
ACQUIRE ì¤í¼ë ì´ì
ì ì ìë£ë©ëë¤.
(4) ACQUIRE vs RELEASE implication:
ì´ë¤ RELEASE ì¤í¼ë ì´ì
ë³´ë¤ ìì ìì²ë ACQUIRE ì¤í¼ë ì´ì
ì ê·¸ RELEASE
ì¤í¼ë ì´ì
ë³´ë¤ ë¨¼ì ìë£ë©ëë¤.
(5) ì¤í¨í ì¡°ê±´ì ACQUIRE ìí¥:
ACQUIRE ì¤í¼ë ì´ì
ì ì¼ë¶ ë½(lock) ë³ì¢
ì ë½ì´ 곧ë°ë¡ íëí기ìë
ë¶ê°ë¥í ìíì´ê±°ë ë½ì´ íë ê°ë¥í´ì§ëë¡ ê¸°ë¤ë¦¬ë ëì¤ ìê·¸ëì ë°ê±°ë
í´ì ì¤í¨í ì ììµëë¤. ì¤í¨í ë½ì ì´ë¤ 배리ì´ë ë´í¬íì§ ììµëë¤.
[!] ì°¸ê³ : ë½ ACQUIRE ì RELEASE ê° ë¨ë°©í¥ 배리ì´ì¬ì ëíëë íì ì¤ íëë
í¬ë¦¬í°ì»¬ ì¹ì
ë°ê¹¥ì ì¸ì¤í¸ëì
ì ìí¥ì´ í¬ë¦¬í°ì»¬ ì¹ì
ë´ë¶ë¡ë ë¤ì´ì¬ ì
ìë¤ë ê²ì
ëë¤.
RELEASE íì ìì²ëë ACQUIRE ë ì ì²´ ë©ëª¨ë¦¬ 배리ì´ë¼ ì¬ê²¨ì§ë©´ ìëëë°,
ACQUIRE ìì ì¡ì¸ì¤ê° ACQUIRE íì ìíë ì ìê³ , RELEASE íì ì¡ì¸ì¤ê°
RELEASE ì ì ìíë ìë ìì¼ë©°, ê·¸ ëê°ì ì¡ì¸ì¤ê° ìë¡ë¥¼ ì§ëì¹ ìë ì기
ë문ì
ëë¤:
*A = a;
ACQUIRE M
RELEASE M
*B = b;
ë ë¤ìê³¼ ê°ì´ ë ìë ììµëë¤:
ACQUIRE M, STORE *B, STORE *A, RELEASE M
ACQUIRE ì RELEASE ê° ë½ íëê³¼ í´ì ë¼ë©´, ê·¸ë¦¬ê³ ë½ì ACQUIRE ì RELEASE ê°
ê°ì ë½ ë³ìì ëí ê²ì´ë¼ë©´, í´ë¹ ë½ì ì¥ê³ ìì§ ìì ë¤ë¥¸ CPU ì ìì¼ìë
ì´ì ê°ì ì¬ë°°ì¹ê° ì¼ì´ëë ê²ì¼ë¡ ë³´ì¼ ì ììµëë¤. ìì½íìë©´, ACQUIRE ì
ì´ì´ RELEASE ì¤í¼ë ì´ì
ì ìì°¨ì ì¼ë¡ ì¤ííë íìê° ì ì²´ ë©ëª¨ë¦¬ 배리ì´ë¡
ìê°ëì´ì -ìë©ëë¤-.
ë¹ì·íê², ìì ë°ë ì¼ì´ì¤ì¸ RELEASE ì ACQUIRE ëê° ì¤í¼ë ì´ì
ì ìì°¨ì ì¤í
ìì ì ì²´ ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´í¬íì§ ììµëë¤. ë°ë¼ì, RELEASE, ACQUIRE ë¡
ê·ì ëë í¬ë¦¬í°ì»¬ ì¹ì
ì CPU ìíì RELEASE ì ACQUIRE 를 ê°ë¡ì§ë¥¼ ì ìì¼ë¯ë¡,
ë¤ìê³¼ ê°ì ì½ëë:
*A = a;
RELEASE M
ACQUIRE N
*B = b;
ë¤ìê³¼ ê°ì´ ìíë ì ììµëë¤:
ACQUIRE N, STORE *B, STORE *A, RELEASE M
ì´ë° ì¬ë°°ì¹ë ë°ëë½ì ì¼ì¼í¬ ìë ìì ê²ì²ë¼ ë³´ì¼ ì ììµëë¤. íì§ë§, ê·¸ë°
ë°ëë½ì ì¡°ì§ì´ ìë¤ë©´ RELEASE ë ë¨ìí ìë£ë ê²ì´ë¯ë¡ ë°ëë½ì ì¡´ì¬í ì
ììµëë¤.
ì´ê² ì´ë»ê² ì¬ë°ë¥¸ ëìì í ì ììê¹ì?
ì°ë¦¬ê° ì´ì¼ê¸° íê³ ìëê±´ ì¬ë°°ì¹ë¥¼ íë CPU ì ëí ì´ì¼ê¸°ì´ì§,
ì»´íì¼ë¬ì ëí ê²ì´ ìëë ì ì´ íµì¬ì
ëë¤. ì»´íì¼ë¬ (ëë, ê°ë°ì)
ê° ì¤í¼ë ì´ì
ë¤ì ì´ë ê² ì¬ë°°ì¹íë©´, ë°ëë½ì´ ì¼ì´ë ì -ììµ-ëë¤.
íì§ë§ CPU ê° ì¤í¼ë ì´ì
ë¤ì ì¬ë°°ì¹ íë¤ë걸 ìê°í´ ë³´ì¸ì. ì´ ììì,
ì´ì
ë¸ë¦¬ ì½ë ìì¼ë¡ë ì¸ë½ì´ ë½ì ììê² ëì´ ììµëë¤. CPU ê° ì´ë¥¼
ì¬ë°°ì¹í´ì ë¤ì ë½ ì¤í¼ë ì´ì
ì 먼ì ì¤ííê² ë©ëë¤. ë§ì½ ë°ëë½ì´
ì¡´ì¬íë¤ë©´, ì´ ë½ ì¤í¼ë ì´ì
ì ê·¸ì ì¤íì íë©° ê³ìí´ì ë½ì
ìëí©ëë¤ (ëë, íì°¸ íìê² ì§ë§, ì ëëë¤). CPU ë ì¸ì ê°ë
(ì´ì
ë¸ë¦¬ ì½ëììë ë½ì ììë) ì¸ë½ ì¤í¼ë ì´ì
ì ì¤ííëë°, ì´ ì¸ë½
ì¤í¼ë ì´ì
ì´ ì ì¬ì ë°ëë½ì í´ê²°íê³ , ë½ ì¤í¼ë ì´ì
ë ë¤ì´ì´ ì±ê³µíê²
ë©ëë¤.
íì§ë§ ë§ì½ ë½ì´ ì ì ìë íì
ì´ìë¤ë©´ì? ê·¸ë° ê²½ì°ì ì½ëë
ì¤ì¼ì¥´ë¬ë¡ ë¤ì´ê°ë ¤ í ê±°ê³ , ì¬ê¸°ì ê²°êµì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë§ëê²
ëëë°, ì´ ë©ëª¨ë¦¬ 배리ì´ë ìì ì¸ë½ ì¤í¼ë ì´ì
ì´ ìë£ëëë¡ ë§ë¤ê³ ,
ë°ëë½ì ì´ë²ìë í´ê²°ë©ëë¤. ì ì ìë íìì ì¸ë½ ì¬ì´ì 경주 ìí©
(race) ë ìì ì ìê² ìµëë¤ë§, ë½ ê´ë ¨ 기ë¥ë¤ì ê·¸ë° ê²½ì£¼ ìí©ì 모ë
ê²½ì°ì ì ëë¡ í´ê²°í ì ìì´ì¼ í©ëë¤.
ë½ê³¼ ì¸ë§í¬ì´ë UP ì»´íì¼ë ìì¤í
ììì ììì ëí´ ë³´ì¥ì íì§ ì기 ë문ì,
ê·¸ë° ìí©ìì ì¸í°ë½í¸ ë¹íì±í ì¤í¼ë ì´ì
ê³¼ í¨ê»ê° ìëë¼ë©´ ì´ë¤ ì¼ìë - í¹í
I/O ì¡ì¸ì¤ì ê´ë ¨í´ìë - ì ëë¡ ì¬ì©ë ì ìì ê²ëë¤.
“CPU ê° ACQUIRING ë°°ë¦¬ì´ í¨ê³¼” ì¹ì ë ì°¸ê³ íì기 ë°ëëë¤.
ì를 ë¤ì´, ë¤ìê³¼ ê°ì ì½ë를 ìê°í´ ë´ ìë¤:
*A = a;
*B = b;
ACQUIRE
*C = c;
*D = d;
RELEASE
*E = e;
*F = f;
ì¬ê¸°ì ë¤ìì ì´ë²¤í¸ ìíì¤ê° ì길 ì ììµëë¤:
ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE
[+] {*F,*A} ë ì¡°í©ë ì¡ì¸ì¤ë¥¼ ì미í©ëë¤.
íì§ë§ ë¤ìê³¼ ê°ì ê±´ ë¶ê°ë¥íì£ :
{*F,*A}, *B, ACQUIRE, *C, *D, RELEASE, *E
*A, *B, *C, ACQUIRE, *D, RELEASE, *E, *F
*A, *B, ACQUIRE, *C, RELEASE, *D, *E, *F
*B, ACQUIRE, *C, *D, RELEASE, {*F,*A}, *E
ì¸í°ë½í¸ ë¹íì±í í¨ì
ì¸í°ë½í¸ë¥¼ ë¹íì±í íë í¨ì (ACQUIRE ì ëì¼) ì ì¸í°ë½í¸ë¥¼ íì±í íë í¨ì
(RELEASE ì ëì¼) ë ì»´íì¼ë¬ 배리ì´ì²ë¼ë§ ëìí©ëë¤. ë°ë¼ì, ë³ëì ë©ëª¨ë¦¬
배리ì´ë I/O 배리ì´ê° íìí ìí©ì´ë¼ë©´ ê·¸ 배리ì´ë¤ì ì¸í°ë½í¸ ë¹íì±í í¨ì
ì¸ì ë°©ë²ì¼ë¡ ì ê³µëì´ì¼ë§ í©ëë¤.
ì¬ë¦½ê³¼ ì¨ì´í¬ì í¨ì
ê¸ë¡ë² ë°ì´í°ì íìë ì´ë²¤í¸ì ìí´ íë¡ì¸ì¤ë¥¼ ì ì ë¹ í¸ë¦¬ë ê²ê³¼ 깨ì°ë ê²ì
í´ë¹ ì´ë²¤í¸ë¥¼ 기ë¤ë¦¬ë íì¤í¬ì íì¤í¬ ìíì ê·¸ ì´ë²¤í¸ë¥¼ ì리기 ìí´ ì¬ì©ëë
ê¸ë¡ë² ë°ì´í°, ë ë°ì´í°ê°ì ìí¸ìì©ì¼ë¡ ë³¼ ì ììµëë¤. ì´ê²ì´ ì³ì ììëë¡
ì¼ì´ë¨ì ë¶ëª
í í기 ìí´, íë¡ì¸ì¤ë¥¼ ì ì ë¤ê² íë 기ë¥ê³¼ 깨ì°ë 기ë¥ì
ëªê°ì§ 배리ì´ë¥¼ ë´í¬í©ëë¤.
먼ì , ì ì ì¬ì°ë 쪽ì ì¼ë°ì ì¼ë¡ ë¤ìê³¼ ê°ì ì´ë²¤í¸ ìíì¤ë¥¼ ë°ë¦ ëë¤:
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (event_indicated)
break;
schedule();
}
set_current_state() ì ìí´, íì¤í¬ ìíê° ë°ë í ë²ì© ë©ëª¨ë¦¬ 배리ì´ê°
ìëì¼ë¡ ì½ì
ë©ëë¤:
CPU 1
===============================
set_current_state();
smp_store_mb();
STORE current->state
<ë²ì© 배리ì´>
LOAD event_indicated
set_current_state() ë ë¤ìì ê²ë¤ë¡ ê°ì¸ì§ ìë ììµëë¤:
prepare_to_wait();
prepare_to_wait_exclusive();
ì´ê²ë¤ ìì ìí를 ì¤ì í í ë²ì© ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì½ì
í©ëë¤.
ìì ì ì²´ ìíì¤ë ë¤ìê³¼ ê°ì í¨ìë¤ë¡ íë²ì ìí ê°ë¥íë°, ì´ê²ë¤ì 모ë
ì¬ë°ë¥¸ ì¥ìì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì½ì
í©ëë¤:
wait_event();
wait_event_interruptible();
wait_event_interruptible_exclusive();
wait_event_interruptible_timeout();
wait_event_killable();
wait_event_timeout();
wait_on_bit();
wait_on_bit_lock();
ëë²ì§¸ë¡, 깨ì°ê¸°ë¥¼ ìííë ì½ëë ì¼ë°ì ì¼ë¡ ë¤ìê³¼ ê°ì ê²ëë¤:
event_indicated = 1;
wake_up(&event_wait_queue);
ëë:
event_indicated = 1;
wake_up_process(event_daemon);
wake_up() ë¥ì ìí´ ì°ê¸° ë©ëª¨ë¦¬ 배리ì´ê° ë´í¬ë©ëë¤. ë§ì½ ê·¸ê²ë¤ì´ ëê°ë¥¼
깨ì´ë¤ë©´ì. ì´ ë°°ë¦¬ì´ë íì¤í¬ ìíê° ì§ìì§ê¸° ì ì ìíëë¯ë¡, ì´ë²¤í¸ë¥¼
ì리기 ìí STORE ì íì¤í¬ ìí를 TASK_RUNNING ì¼ë¡ ì¤ì íë STORE ì¬ì´ì
ìì¹íê² ë©ëë¤.
CPU 1 CPU 2
=============================== ===============================
set_current_state(); STORE event_indicated
smp_store_mb(); wake_up();
STORE current->state <ì°ê¸° 배리ì´>
<ë²ì© 배리ì´> STORE current->state
LOAD event_indicated
íë²ë ë§í©ëë¤ë§, ì´ ì°ê¸° ë©ëª¨ë¦¬ 배리ì´ë ì´ ì½ëê° ì ë§ë¡ ëê°ë¥¼ ê¹¨ì¸ ëìë§
ì¤íë©ëë¤. ì´ê±¸ ì¤ëª
í기 ìí´, X ì Y ë 모ë 0 ì¼ë¡ ì´ê¸°í ëì´ ìë¤ë ê°ì
íì ìëì ì´ë²¤í¸ ìíì¤ë¥¼ ìê°í´ ë´
ìë¤:
CPU 1 CPU 2
=============================== ===============================
X = 1; STORE event_indicated
smp_mb(); wake_up();
Y = 1; wait_event(wq, Y == 1);
wake_up(); load from Y sees 1, no memory barrier
load from X might see 0
ì ìì ììì ê²½ì°ì ë¬ë¦¬ 깨ì°ê¸°ê° ì ë§ë¡ íí´ì¡ë¤ë©´, CPU 2 ì X ë¡ëë 1 ì
본ë¤ê³ ë³´ì¥ë ì ìì ê²ëë¤.
ì¬ì© ê°ë¥í 깨ì°ê¸°ë¥ í¨ìë¤ë¡ ë¤ìê³¼ ê°ì ê²ë¤ì´ ììµëë¤:
complete();
wake_up();
wake_up_all();
wake_up_bit();
wake_up_interruptible();
wake_up_interruptible_all();
wake_up_interruptible_nr();
wake_up_interruptible_poll();
wake_up_interruptible_sync();
wake_up_interruptible_sync_poll();
wake_up_locked();
wake_up_locked_poll();
wake_up_nr();
wake_up_poll();
wake_up_process();
[!] ì ì¬ì°ë ì½ëì 깨ì°ë ì½ëì ë´í¬ëë ë©ëª¨ë¦¬ 배리ì´ë¤ì 깨ì°ê¸° ì ì
ì´ë£¨ì´ì§ ì¤í ì´ë¥¼ ì ì¬ì°ë ì½ëê° set_current_state() 를 í¸ì¶í íì ííë
ë¡ëì ëí´ ìì를 ë§ì¶ì§ ìëë¤ë ì ì 기ìµíì¸ì. ì를 ë¤ì´, ì ì¬ì°ë
ì½ëê° ë¤ìê³¼ ê°ê³ :
set_current_state(TASK_INTERRUPTIBLE);
if (event_indicated)
break;
__set_current_state(TASK_RUNNING);
do_something(my_data);
깨ì°ë ì½ëë ë¤ìê³¼ ê°ë¤ë©´:
my_data = value;
event_indicated = 1;
wake_up(&event_wait_queue);
event_indecated ìì ë³ê²½ì´ ì ì¬ì°ë ì½ëìê² my_data ìì ë³ê²½ íì ì´ë£¨ì´ì§
ê²ì¼ë¡ ì¸ì§ë ê²ì´ë¼ë ë³´ì¥ì´ ììµëë¤. ì´ë° ê²½ì°ìë ì쪽 ì½ë 모ë ê°ê°ì
ë°ì´í° ì¡ì¸ì¤ ì¬ì´ì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì§ì ì³ì¼ í©ëë¤. ë°ë¼ì ìì ì¬ì°ë
ì½ëë ë¤ìê³¼ ê°ì´:
set_current_state(TASK_INTERRUPTIBLE);
if (event_indicated) {
smp_rmb();
do_something(my_data);
}
ê·¸ë¦¬ê³ ê¹¨ì°ë ì½ëë ë¤ìê³¼ ê°ì´ ëì´ì¼ í©ëë¤:
my_data = value;
smp_wmb();
event_indicated = 1;
wake_up(&event_wait_queue);
ê·¸ì¸ì í¨ìë¤
ê·¸ì¸ì 배리ì´ë¥¼ ë´í¬íë í¨ìë¤ì ë¤ìê³¼ ê°ìµëë¤:
(*) schedule() ê³¼ ê·¸ ì ì¬í ê²ë¤ì´ ìì í ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´í¬í©ëë¤.
==============================
CPU ê° ACQUIRING 배리ì´ì í¨ê³¼
==============================
SMP ìì¤í
ììì ë½ ê¸°ë¥ë¤ì ëì± ê°ë ¥í ííì 배리ì´ë¥¼ ì ê³µí©ëë¤: ì´
배리ì´ë ëì¼í ë½ì ì¬ì©íë ë¤ë¥¸ CPU ë¤ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ ìììë ìí¥ì
ë¼ì¹©ëë¤.
ACQUIRE VS ë©ëª¨ë¦¬ ì¡ì¸ì¤
ë¤ìì ì를 ìê°í´ ë´
ìë¤: ìì¤í
ì ëê°ì ì¤íë½ (M) ê³¼ (Q), ê·¸ë¦¬ê³ ì¸ê°ì CPU
를 ê°ì§ê³ ììµëë¤; ì¬ê¸°ì ë¤ìì ì´ë²¤í¸ ìíì¤ê° ë°ìí©ëë¤:
CPU 1 CPU 2
=============================== ===============================
WRITE_ONCE(*A, a); WRITE_ONCE(*E, e);
ACQUIRE M ACQUIRE Q
WRITE_ONCE(*B, b); WRITE_ONCE(*F, f);
WRITE_ONCE(*C, c); WRITE_ONCE(*G, g);
RELEASE M RELEASE Q
WRITE_ONCE(*D, d); WRITE_ONCE(*H, h);
*A ë¡ì ì¡ì¸ì¤ë¶í° *H ë¡ì ì¡ì¸ì¤ê¹ì§ê° ì´ë¤ ììë¡ CPU 3 ìê² ë³´ì¬ì§ì§ì
ëí´ìë ê° CPU ììì ë½ ì¬ì©ì ìí´ ë´í¬ëì´ ìë ì ì½ì ì ì¸íê³ ë ì´ë¤
ë³´ì¥ë ì¡´ì¬íì§ ììµëë¤. ì를 ë¤ì´, CPU 3 ìê² ë¤ìê³¼ ê°ì ììë¡ ë³´ì¬ì§ë
ê²ì´ ê°ë¥í©ëë¤:
*E, ACQUIRE M, ACQUIRE Q, *G, *C, *F, *A, *B, RELEASE Q, *D, *H, RELEASE M
íì§ë§ ë¤ìê³¼ ê°ì´ ë³´ì´ì§ë ìì ê²ëë¤:
*B, *C or *D preceding ACQUIRE M
*A, *B or *C following RELEASE M
*F, *G or *H preceding ACQUIRE Q
*E, *F or *G following RELEASE Q
ACQUIRE VS I/O ì¡ì¸ì¤
í¹ì í (í¹í NUMA ê° ê´ë ¨ë) íê²½ íìì ëê°ì CPU ìì ëì¼í ì¤íë½ì¼ë¡
ë³´í¸ëë ëê°ì í¬ë¦¬í°ì»¬ ì¹ì
ìì I/O ì¡ì¸ì¤ë PCI ë¸ë¦¿ì§ì ê²¹ì³ì§ I/O
ì¡ì¸ì¤ë¡ ë³´ì¼ ì ìëë°, PCI ë¸ë¦¿ì§ë ìºì ì¼ê´ì± íë¡í ì½ê³¼ í©ì ë§ì¶°ì¼ í
ìë¬´ê° ìì¼ë¯ë¡, íìí ì½ê¸° ë©ëª¨ë¦¬ 배리ì´ê° ìì²ëì§ ì기 ë문ì
ëë¤.
ì를 ë¤ì´ì:
CPU 1 CPU 2
=============================== ===============================
spin_lock(Q)
writel(0, ADDR)
writel(1, DATA);
spin_unlock(Q);
spin_lock(Q);
writel(4, ADDR);
writel(5, DATA);
spin_unlock(Q);
ë PCI ë¸ë¦¿ì§ì ë¤ìê³¼ ê°ì´ ë³´ì¼ ì ììµëë¤:
STORE *ADDR = 0, STORE *ADDR = 4, STORE *DATA = 1, STORE *DATA = 5
ì´ë ê² ëë©´ íëì¨ì´ì ì¤ëìì ì¼ì¼í¬ ì ììµëë¤.
ì´ë° ê²½ì°ì ì¡ìë ì¤íë½ì ë´ë ¤ë기 ì ì mmiowb() 를 ìíí´ì¼ íëë°, ì를
ë¤ë©´ ë¤ìê³¼ ê°ìµëë¤:
CPU 1 CPU 2
=============================== ===============================
spin_lock(Q)
writel(0, ADDR)
writel(1, DATA);
mmiowb();
spin_unlock(Q);
spin_lock(Q);
writel(4, ADDR);
writel(5, DATA);
mmiowb();
spin_unlock(Q);
ì´ ì½ëë CPU 1 ìì ìì²ë ëê°ì ì¤í ì´ê° PCI ë¸ë¦¿ì§ì CPU 2 ìì ìì²ë
ì¤í ì´ë¤ë³´ë¤ 먼ì ë³´ì¬ì§ì ë³´ì¥í©ëë¤.
ëí, ê°ì ëë°ì´ì¤ìì ì¤í ì´ë¥¼ ì´ì´ ë¡ëê° ìíëë©´ ì´ ë¡ëë ë¡ëê° ìíë기
ì ì ì¤í ì´ê° ìë£ë기를 ê°ì íë¯ë¡ mmiowb() ì íìê° ìì´ì§ëë¤:
CPU 1 CPU 2
=============================== ===============================
spin_lock(Q)
writel(0, ADDR)
a = readl(DATA);
spin_unlock(Q);
spin_lock(Q);
writel(4, ADDR);
b = readl(DATA);
spin_unlock(Q);
ë ë§ì ì 보를 ìí´ì Documentation/driver-api/device-io.rst 를 ì°¸ê³ íì¸ì.
=========================
ë©ëª¨ë¦¬ 배리ì´ê° íìí ê³³
=========================
ì¤ë ¹ SMP 커ëì ì¬ì©íëë¼ë ì±ê¸ ì°ë ëë¡ ëìíë ì½ëë ì¬ë°ë¥´ê² ëìíë
ê²ì¼ë¡ ë³´ì¬ì§ ê²ì´ê¸° ë문ì, íë²í ìì¤í
ì´ìì¤ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ì¬ë°°ì¹ë
ì¼ë°ì ì¼ë¡ 문ì ê° ëì§ ììµëë¤. íì§ë§, ì¬ë°°ì¹ê° 문ì ê° ë ì ìë ë¤ê°ì§
íê²½ì´ ììµëë¤:
(*) íë¡ì¸ìê° ìí¸ ìì©.
(*) ì´í 믹 ì¤í¼ë ì´ì .
(*) ëë°ì´ì¤ ì¡ì¸ì¤.
(*) ì¸í°ë½í¸.
íë¡ì¸ìê° ìí¸ ìì©
ëê° ì´ìì íë¡ì¸ì를 ê°ì§ ìì¤í
ì´ ìë¤ë©´, ìì¤í
ì ëê° ì´ìì CPU ë ëìì
ê°ì ë°ì´í°ì ëí ìì
ì í ì ììµëë¤. ì´ë ë기í 문ì 를 ì¼ì¼í¬ ì ìê³ ,
ì´ ë¬¸ì 를 í´ê²°íë ì¼ë°ì ë°©ë²ì ë½ì ì¬ì©íë ê²ì
ëë¤. íì§ë§, ë½ì ìë¹í
ë¹ì©ì´ ë¹ì¸ì ê°ë¥íë©´ ë½ì ì¬ì©íì§ ìê³ ì¼ì ì²ë¦¬íë ê²ì´ ë«ìµëë¤. ì´ë°
ê²½ì°, ë CPU 모ëì ìí¥ì ë¼ì¹ë ì¤í¼ë ì´ì
ë¤ì ì¤ëìì ë§ê¸° ìí´ ì ì¤íê²
ììê° ë§ì¶°ì ¸ì¼ í©ëë¤.
ì를 ë¤ì´, R/W ì¸ë§í¬ì´ì ë린 ìíê²½ë¡ (slow path) 를 ìê°í´ ë´
ìë¤.
ì¸ë§í¬ì´ë¥¼ ìí´ ë기를 íë íëì íë¡ì¸ì¤ê° ìì ì ì¤í ì¤ ì¼ë¶ë¥¼ ì´
ì¸ë§í¬ì´ì ë기 íë¡ì¸ì¤ 리ì¤í¸ì ë§í¬í ì±ë¡ ììµëë¤:
struct rw_semaphore {
...
spinlock_t lock;
struct list_head waiters;
};
struct rwsem_waiter {
struct list_head list;
struct task_struct *task;
};
í¹ì ë기 ìí íë¡ì¸ì¤ë¥¼ 깨ì°ê¸° ìí´, up_read() ë up_write() í¨ìë ë¤ìê³¼
ê°ì ì¼ì í©ëë¤:
(1) ë¤ì ë기 ìí íë¡ì¸ì¤ ë ì½ëë ì´ëìëì§ ì기 ìí´ ì´ ë기 ìí
íë¡ì¸ì¤ ë ì½ëì next í¬ì¸í°ë¥¼ ì½ìµëë¤;
(2) ì´ ë기 ìí íë¡ì¸ì¤ì task 구조체ë¡ì í¬ì¸í°ë¥¼ ì½ìµëë¤;
(3) ì´ ë기 ìí íë¡ì¸ì¤ê° ì¸ë§í¬ì´ë¥¼ íëíìì ì리기 ìí´ task
í¬ì¸í°ë¥¼ ì´ê¸°í í©ëë¤;
(4) í´ë¹ íì¤í¬ì ëí´ wake_up_process() 를 í¸ì¶í©ëë¤; 그리ê³
(5) í´ë¹ ë기 ìí íë¡ì¸ì¤ì task 구조체를 ì¡ê³ ìë ë í¼ë°ì¤ë¥¼ í´ì í©ëë¤.
ë¬ë¦¬ ë§íìë©´, ë¤ì ì´ë²¤í¸ ìíì¤ë¥¼ ìíí´ì¼ í©ëë¤:
LOAD waiter->list.next;
LOAD waiter->task;
STORE waiter->task;
CALL wakeup
RELEASE task
ê·¸ë¦¬ê³ ì´ ì´ë²¤í¸ë¤ì´ ë¤ë¥¸ ììë¡ ìíëë¤ë©´, ì¤ëìì´ ì¼ì´ë ì ììµëë¤.
íë² ì¸ë§í¬ì´ì ë기ì¤ì ë¤ì´ê°ê³ ì¸ë§í¬ì´ ë½ì ëìë¤ë©´, í´ë¹ ë기 íë¡ì¸ì¤ë
ë½ì ë¤ìë ì¡ì§ ììµëë¤; ëì ìì ì task í¬ì¸í°ê° ì´ê¸°í ë길 기ë¤ë¦½ëë¤.
ê·¸ ë ì½ëë ë기 íë¡ì¸ì¤ì ì¤íì ì기 ë문ì, 리ì¤í¸ì next í¬ì¸í°ê° ì½íì§ê¸°
ì ì task í¬ì¸í°ê° ì§ìì§ë¤ë©´, ë¤ë¥¸ CPU ë í´ë¹ ë기 íë¡ì¸ì¤ë¥¼ ììí´ ë²ë¦¬ê³
up*() í¨ìê° next í¬ì¸í°ë¥¼ ì½ê¸° ì ì ë기 íë¡ì¸ì¤ì ì¤íì ë§êµ¬ ê±´ë릴 ì
ììµëë¤.
ê·¸ë ê² ëë©´ ìì ì´ë²¤í¸ ìíì¤ì ì´ë¤ ì¼ì´ ì¼ì´ëëì§ ìê°í´ ë³´ì£ :
CPU 1 CPU 2
=============================== ===============================
down_xxx()
Queue waiter
Sleep
up_yyy()
LOAD waiter->task;
STORE waiter->task;
Woken up by other event
<preempt>
Resume processing
down_xxx() returns
call foo()
foo() clobbers *waiter
</preempt>
LOAD waiter->list.next;
--- OOPS ---
ì´ ë¬¸ì ë ì¸ë§í¬ì´ ë½ì ì¬ì©ì¼ë¡ í´ê²°ë ìë ìê² ì§ë§, ê·¸ë ê² ëë©´ 깨ì´ë íì
down_xxx() í¨ìê° ë¶íìíê² ì¤íë½ì ëë¤ì ì»ì´ì¼ë§ í©ëë¤.
ì´ ë¬¸ì 를 í´ê²°íë ë°©ë²ì ë²ì© SMP ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì¶ê°íë ê²ëë¤:
LOAD waiter->list.next;
LOAD waiter->task;
smp_mb();
STORE waiter->task;
CALL wakeup
RELEASE task
ì´ ê²½ì°ì, 배리ì´ë ìì¤í
ì ëë¨¸ì§ CPU ë¤ìê² ëª¨ë ë°°ë¦¬ì´ ìì ë©ëª¨ë¦¬ ì¡ì¸ì¤ê°
ë°°ë¦¬ì´ ë¤ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ë³´ë¤ ìì ì¼ì´ë ê²ì¼ë¡ ë³´ì´ê² ë§ëëë¤. ë°°ë¦¬ì´ ìì
ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¤ì´ ë°°ë¦¬ì´ ëª
ë ¹ ìì²´ê° ìë£ëë ìì ê¹ì§ ìë£ëë¤ê³ ë ë³´ì¥íì§
ììµëë¤.
(ì´ê² 문ì ê° ëì§ ìì) ë¨ì¼ íë¡ì¸ì ìì¤í
ìì smp_mb() ë ì¤ì ë¡ë ê·¸ì
ì»´íì¼ë¬ê° CPU ìììì ìì를 ë°ê¾¸ê±°ë íì§ ìê³ ì£¼ì´ì§ ììëë¡ ëª
ë ¹ì
ë´ë¦¬ëë¡ íë ì»´íì¼ë¬ 배리ì´ì¼ ë¿ì
ëë¤. ì¤ì§ íëì CPU ë§ ìì¼ë, CPU ì
ìì¡´ì± ìì ë¡ì§ì´ ê·¸ ì¸ì 모ë ê²ì ììì ì²ë¦¬í ê²ëë¤.
ì´í 믹 ì¤í¼ë ì´ì
ì´í 믹 ì¤í¼ë ì´ì
ì 기ì ì ì¼ë¡ íë¡ì¸ìê° ìí¸ìì©ì¼ë¡ ë¶ë¥ëë©° ê·¸ ì¤ ì¼ë¶ë
ì ì²´ ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´í¬íê³ ë ì¼ë¶ë ë´í¬íì§ ìì§ë§, 커ëìì ìë¹í
ìì¡´ì ì¼ë¡ ì¬ì©íë ê¸°ë¥ ì¤ íëì
ëë¤.
ë ë§ì ë´ì©ì ìí´ì Documentation/atomic_t.txt 를 ì°¸ê³ íì¸ì.
ëë°ì´ì¤ ì¡ì¸ì¤
ë§ì ëë°ì´ì¤ê° ë©ëª¨ë¦¬ 매í 기ë²ì¼ë¡ ì ì´ë ì ìëë°, ê·¸ë ê² ì ì´ëë
ëë°ì´ì¤ë CPU ìë ë¨ì§ í¹ì ë©ëª¨ë¦¬ ììì ì§í©ì²ë¼ ë³´ì´ê² ë©ëë¤. ëë¼ì´ë²ë
ê·¸ë° ëë°ì´ì¤ë¥¼ ì ì´í기 ìí´ ì íí ì¬ë°ë¥¸ ììë¡ ì¬ë°ë¥¸ ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¥¼
ë§ë¤ì´ì¼ í©ëë¤.
íì§ë§, ì¡ì¸ì¤ë¤ì ì¬ë°°ì¹ íê±°ë ì¡°í©íê±°ë ë³í©íëê² ë í¨ì¨ì ì´ë¼ íë¨íë
ì리í CPU ë ì»´íì¼ë¬ë¤ì ì¬ì©íë©´ ëë¼ì´ë² ì½ëì ì¡°ì¬ì¤ë½ê² ìì ë§ì¶°ì§
ì¡ì¸ì¤ë¤ì´ ëë°ì´ì¤ìë ìì²ë ììëë¡ ëì°©íì§ ëª»íê² í ì ìë - ëë°ì´ì¤ê°
ì¤ëìì íê² í - ì ì¬ì 문ì ê° ì길 ì ììµëë¤.
리ë
ì¤ ì»¤ë ë´ë¶ìì, I/O ë ì´ë»ê² ì¡ì¸ì¤ë¤ì ì ì í ìì°¨ì ì´ê² ë§ë¤ ì ìëì§
ìê³ ìë, - inb() ë writel() ê³¼ ê°ì - ì ì í ì¡ì¸ì¤ 루í´ì íµí´ ì´ë£¨ì´ì ¸ì¼ë§
í©ëë¤. ì´ê²ë¤ì ëë¶ë¶ì ê²½ì°ìë ëª
ìì ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ì í¨ê» ì¬ì©ë íìê°
ììµëë¤ë§, ë¤ìì ëê°ì§ ìí©ììë ëª
ìì ë©ëª¨ë¦¬ 배리ì´ê° íìí ì ììµëë¤:
(1) ì¼ë¶ ìì¤í
ìì I/O ì¤í ì´ë 모ë CPU ì ì¼ê´ëê² ìì ë§ì¶°ì§ì§ ìëë°,
ë°ë¼ì _모ë _ ì¼ë°ì ì¸ ëë¼ì´ë²ë¤ì ë½ì´ ì¬ì©ëì´ì¼ë§ íê³ ì´ í¬ë¦¬í°ì»¬
ì¹ì
ì ë¹ ì ¸ëì¤ê¸° ì ì mmiowb() ê° ê¼ í¸ì¶ëì´ì¼ í©ëë¤.
(2) ë§ì½ ì¡ì¸ì¤ í¨ìë¤ì´ ìíë ë©ëª¨ë¦¬ ì¡ì¸ì¤ ìì±ì ê°ë I/O ë©ëª¨ë¦¬ ìëì°ë¥¼
ì¬ì©íë¤ë©´, ìì를 ê°ì í기 ìí´ì mandatory ë©ëª¨ë¦¬ 배리ì´ê° íìí©ëë¤.
ë ë§ì ì 보를 ìí´ì Documentation/driver-api/device-io.rst 를 ì°¸ê³ íììì¤.
ì¸í°ë½í¸
ëë¼ì´ë²ë ìì ì ì¸í°ë½í¸ ìë¹ì¤ 루í´ì ìí´ ì¸í°ë½í¸ ë¹í ì ì기 ë문ì
ëë¼ì´ë²ì ì´ ë ë¶ë¶ì ìë¡ì ëë°ì´ì¤ ì ì´ ëë ì¡ì¸ì¤ ë¶ë¶ê³¼ ìí¸ ê°ìí ì
ììµëë¤.
ì¤ì¤ë¡ìê² ì¸í°ë½í¸ ë¹íë 걸 ë¶ê°ë¥íê² íê³ , ëë¼ì´ë²ì í¬ë¦¬í°ì»¬í
ì¤í¼ë ì´ì
ë¤ì 모ë ì¸í°ë½í¸ê° ë¶ê°ë¥íê² ë ììì ì§ì´ë£ê±°ë íë ë°©ë² (ë½ì
í íí) ì¼ë¡ ì´ë° ìí¸ ê°ìì - ìµìí ë¶ë¶ì ì¼ë¡ë¼ë - ì¤ì¼ ì ììµëë¤.
ëë¼ì´ë²ì ì¸í°ë½í¸ 루í´ì´ ì¤í ì¤ì¸ ëì, í´ë¹ ëë¼ì´ë²ì ì½ì´ë ê°ì CPU ìì
ìíëì§ ìì ê²ì´ë©°, íì¬ì ì¸í°ë½í¸ê° ì²ë¦¬ëë ì¤ìë ëë¤ì ì¸í°ë½í¸ê°
ì¼ì´ëì§ ëª»íëë¡ ëì´ ìì¼ë ì¸í°ë½í¸ í¸ë¤ë¬ë ê·¸ì ëí´ìë ë½ì ì¡ì§ ììë
ë©ëë¤.
íì§ë§, ì´ëë ì¤ ë ì§ì¤í°ì ë°ì´í° ë ì§ì¤í°ë¥¼ ê°ë ì´ëë· ì¹´ë를 ë¤ë£¨ë
ëë¼ì´ë²ë¥¼ ìê°í´ ë´
ìë¤. ë§ì½ ì´ ëë¼ì´ë²ì ì½ì´ê° ì¸í°ë½í¸ë¥¼ ë¹íì±íìí¨
ì±ë¡ ì´ëë· ì¹´ëì ëííê³ ëë¼ì´ë²ì ì¸í°ë½í¸ í¸ë¤ë¬ê° í¸ì¶ëìë¤ë©´:
LOCAL IRQ DISABLE
writew(ADDR, 3);
writew(DATA, y);
LOCAL IRQ ENABLE
<interrupt>
writew(ADDR, 4);
q = readw(DATA);
</interrupt>
ë§ì½ ìì ê·ì¹ì´ 충ë¶í ìíëì´ ìë¤ë©´ ë°ì´í° ë ì§ì¤í°ìì ì¤í ì´ë ì´ëë ì¤
ë ì§ì¤í°ì ëë²ì§¸ë¡ íí´ì§ë ì¤í ì´ ë¤ì ì¼ì´ë ìë ììµëë¤:
STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA
ë§ì½ ìì ê·ì¹ì´ 충ë¶í ìíëì´ ìê³ ë¬µìì ì¼ë¡ë ëª
ìì ì¼ë¡ë 배리ì´ê°
ì¬ì©ëì§ ììë¤ë©´ ì¸í°ë½í¸ ë¹íì±í ì¹ì
ìì ì¼ì´ë ì¡ì¸ì¤ê° ë°ê¹¥ì¼ë¡ ìì´ì
ì¸í°ë½í¸ ë´ìì ì¼ì´ë ì¡ì¸ì¤ì ìì¼ ì ìë¤ê³ - ê·¸ë¦¬ê³ ê·¸ ë°ëë - ê°ì í´ì¼ë§
í©ëë¤.
ê·¸ë° ìì ììì ì¼ì´ëë I/O ì¡ì¸ì¤ë¤ì ì격í ìì ê·ì¹ì I/O ë ì§ì¤í°ì
묵ìì I/O 배리ì´ë¥¼ íì±íë ë기ì (synchronous) ë¡ë ì¤í¼ë ì´ì
ì í¬í¨í기
ë문ì ì¼ë°ì ì¼ë¡ë ì´ë°ê² 문ì ê° ëì§ ììµëë¤. ë§ì½ ì´ê±¸ë¡ë 충ë¶ì¹ ìë¤ë©´
mmiowb() ê° ëª
ìì ì¼ë¡ ì¬ì©ë íìê° ììµëë¤.
íëì ì¸í°ë½í¸ 루í´ê³¼ ë³ëì CPU ìì ìíì¤ì´ë©° ìë¡ íµì ì íë ë 루í´
ì¬ì´ìë ë¹ì·í ìí©ì´ ì¼ì´ë ì ììµëë¤. ë§ì½ ê·¸ë° ê²½ì°ê° ë°ìí ê°ë¥ì±ì´
ìë¤ë©´, ìì를 ë³´ì¥í기 ìí´ ì¸í°ë½í¸ ë¹íì±í ë½ì´ ì¬ì©ëì´ì ¸ì¼ë§ í©ëë¤.
======================
커ë I/O 배리ì´ì í¨ê³¼
======================
I/O ë©ëª¨ë¦¬ì ì¡ì¸ì¤í ë, ëë¼ì´ë²ë ì ì í ì¡ì¸ì¤ í¨ì를 ì¬ì©í´ì¼ í©ëë¤:
(*) inX(), outX():
ì´ê²ë¤ì ë©ëª¨ë¦¬ ê³µê°ë³´ë¤ë I/O ê³µê°ì ì´ì¼ê¸°ë¥¼ íë ¤ë ìëë¡
ë§ë¤ì´ì¡ìµëë¤ë§, 그건 기본ì ì¼ë¡ CPU ë§ë¤ ë¤ë¥¸ 컨ì
ì
ëë¤. i386 ê³¼
x86_64 íë¡ì¸ìë¤ì í¹ë³í I/O ê³µê° ì¡ì¸ì¤ ì¬ì´í´ê³¼ ëª
ë ¹ì´ë¥¼ ì¤ì ë¡ ê°ì§ê³
ìì§ë§, ë¤ë¥¸ ë§ì CPU ë¤ìë ê·¸ë° ì»¨ì
ì´ ì¡´ì¬íì§ ììµëë¤.
ë¤ë¥¸ ê²ë¤ ì¤ììë PCI ë²ì¤ê° I/O ê³µê° ì»¨ì
ì ì ìíëë°, ì´ë - i386 ê³¼
x86_64 ê°ì CPU ìì - CPU ì I/O ê³µê° ì»¨ì
ì¼ë¡ ì½ê² 매ì¹ë©ëë¤. íì§ë§,
ëì²´í I/O ê³µê°ì´ ìë CPU ììë CPU ì ë©ëª¨ë¦¬ 맵ì ê°ì I/O ê³µê°ì¼ë¡
매íë ìë ììµëë¤.
ì´ ê³µê°ì¼ë¡ì ì¡ì¸ì¤ë (i386 ë±ììë) ìì íê² ë기í ë©ëë¤ë§, ì¤ê°ì
(PCI í¸ì¤í¸ ë¸ë¦¬ì§ì ê°ì) ë¸ë¦¬ì§ë¤ì ì´ë¥¼ ìì í ë³´ì¥íì§ ìììë
ììµëë¤.
ì´ê²ë¤ì ìí¸ê°ì ììë ìì íê² ë³´ì¥ë©ëë¤.
ë¤ë¥¸ íì
ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
, I/O ì¤í¼ë ì´ì
ì ëí ììë ìì íê²
ë³´ì¥ëì§ë ììµëë¤.
(*) readX(), writeX():
ì´ê²ë¤ì´ ìí ìì²ëë CPU ìì ìë¡ìê² ìì í ììê° ë§ì¶°ì§ê³ ë
립ì ì¼ë¡
ìíëëì§ì ëí ë³´ì¥ ì¬ë¶ë ì´ë¤ì´ ì¡ì¸ì¤ íë ë©ëª¨ë¦¬ ìëì°ì ì ìë
í¹ì±ì ìí´ ê²°ì ë©ëë¤. ì를 ë¤ì´, ìµì ì i386 ìí¤í
ì³ ë¨¸ì ììë MTRR
ë ì§ì¤í°ë¡ ì´ í¹ì±ì´ ì¡°ì ë©ëë¤.
ì¼ë°ì ì¼ë¡ë, í리íì¹ (prefetch) ê°ë¥í ëë°ì´ì¤ë¥¼ ì¡ì¸ì¤ íëê²
ìëë¼ë©´, ì´ê²ë¤ì ìì í ììê° ë§ì¶°ì§ê³ ê²°í©ëì§ ìê² ë³´ì¥ë ê²ëë¤.
íì§ë§, (PCI ë¸ë¦¬ì§ì ê°ì) ì¤ê°ì íëì¨ì´ë ìì ì´ ìíë¤ë©´ ì§íì
ì°ê¸°ìí¬ ì ììµëë¤; ì¤í ì´ ëª
ë ¹ì ì¤ì ë¡ íëì¨ì´ë¡ ë´ë ¤ë³´ë´ê¸°(flush)
ìí´ìë ê°ì ìì¹ë¡ë¶í° ë¡ë를 íë ë°©ë²ì´ ììµëë¤ë§[*], PCI ì ê²½ì°ë
ê°ì ëë°ì´ì¤ë íê²½ êµ¬ì± ììììì ë¡ëë§ì¼ë¡ë 충ë¶í ê²ëë¤.
[*] 주ì! ì°ì¬ì§ ê²ê³¼ ê°ì ìì¹ë¡ë¶í°ì ë¡ë를 ìëíë ê²ì ì¤ëìì
ì¼ì¼í¬ ìë ììµëë¤ - ìë¡ 16650 Rx/Tx ìë¦¬ì¼ ë ì§ì¤í°ë¥¼ ìê°í´
ë³´ì¸ì.
í리íì¹ ê°ë¥í I/O ë©ëª¨ë¦¬ê° ì¬ì©ëë©´, ì¤í ì´ ëª
ë ¹ë¤ì´ ìì를 ì§í¤ëë¡
í기 ìí´ mmiowb() 배리ì´ê° íìí ì ììµëë¤.
PCI í¸ëìì
ì¬ì´ì ìí¸ìì©ì ëí´ ë ë§ì ì 보를 ìí´ì PCI ëª
ì¸ì를
ì°¸ê³ íì기 ë°ëëë¤.
(*) readX_relaxed(), writeX_relaxed()
ì´ê²ë¤ì readX() ì writeX() ë ë¹ì·íì§ë§, ë ìíë ë©ëª¨ë¦¬ ìì ë³´ì¥ì
ì ê³µí©ëë¤. 구체ì ì¼ë¡, ì´ê²ë¤ì ì¼ë°ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ (ì: DMA ë²í¼) ìë
LOCK ì´ë UNLOCK ì¤í¼ë ì´ì
ë¤ìë ìì를 ë³´ì¥íì§ ììµëë¤. LOCK ì´ë
UNLOCK ì¤í¼ë ì´ì
ë¤ì ë§ì¶°ì§ë ììê° íìíë¤ë©´, mmiowb() 배리ì´ê° ì¬ì©ë
ì ììµëë¤. ê°ì ì£¼ë³ ì¥ì¹ìì ìíë ì¡ì¸ì¤ë¼ë¦¬ë ììê° ì§ì¼ì§ì ìì
ëì기 ë°ëëë¤.
(*) ioreadX(), iowriteX()
ì´ê²ë¤ì inX()/outX() ë readX()/writeX() ì²ë¼ ì¤ì ë¡ ìííë ì¡ì¸ì¤ì
ì¢
ë¥ì ë°ë¼ ì ì íê² ìíë ê²ì
ëë¤.
===================================
ê°ì ëë ê°ì¥ ìíë ì¤í ìì 모ë¸
===================================
컨ì
ì ì¼ë¡ CPU ë 주ì´ì§ íë¡ê·¸ë¨ì ëí´ íë¡ê·¸ë¨ ê·¸ ìì²´ìë ì¸ê³¼ì± (program
causality) ì ì§í¤ë ê²ì²ë¼ ë³´ì´ê² íì§ë§ ì¼ë°ì ì¼ë¡ë ìì를 ê±°ì ì§ì¼ì£¼ì§
ìëë¤ê³ ê°ì ëì´ì¼ë§ í©ëë¤. (i386 ì´ë x86_64 ê°ì) ì¼ë¶ CPU ë¤ì ì½ë
ì¬ë°°ì¹ì (powerpc ë frv ì ê°ì) ë¤ë¥¸ ê²ë¤ì ë¹í´ ê°í ì ì½ì ê°ì§ë§, ìí¤í
ì³
ì¢
ìì ì½ë ì´ì¸ì ì½ëììë ììì ëí ì ì½ì´ ê°ì¥ ìíë ê²½ì° (DEC Alpha)
를 ê°ì í´ì¼ í©ëë¤.
ì´ ë§ì, CPU ìê² ì£¼ì´ì§ë ì¸ì¤í¸ëì
ì¤í¸ë¦¼ ë´ì í ì¸ì¤í¸ëì
ì´ ìì
ì¸ì¤í¸ëì
ì ì¢
ìì ì´ë¼ë©´ ìì ì¸ì¤í¸ëì
ì ë¤ì ì¢
ìì ì¸ì¤í¸ëì
ì´ ì¤íë기
ì ì ìë£[*]ë ì ìì´ì¼ íë¤ë ì ì½ (ë¬ë¦¬ ë§í´ì, ì¸ê³¼ì±ì´ ì§ì¼ì§ë ê²ì¼ë¡
ë³´ì´ê² í¨) ì¸ìë ìì ì´ ìíë ììëë¡ - ì¬ì§ì´ ë³ë ¬ì ì¼ë¡ë - ê·¸ ì¤í¸ë¦¼ì
ì¤íí ì ììì ì미í©ëë¤
[*] ì¼ë¶ ì¸ì¤í¸ëì
ì íë ì´ìì ìí¥ - ì¡°ê±´ ì½ë를 ë°ê¾¼ë¤ëì§, ë ì§ì¤í°ë
ë©ëª¨ë¦¬ë¥¼ ë°ê¾¼ë¤ëì§ - ì ë§ë¤ì´ë´ë©°, ë¤ë¥¸ ì¸ì¤í¸ëì
ì ë¤ë¥¸ í¨ê³¼ì
ì¢
ìì ì¼ ì ììµëë¤.
CPU ë ìµì¢
ì ì¼ë¡ ì무 í¨ê³¼ë ë§ë¤ì§ ìë ì¸ì¤í¸ëì
ìíì¤ë ìì ë²ë¦´ ìë
ììµëë¤. ì를 ë¤ì´, ë§ì½ ëê°ì ì°ìëë ì¸ì¤í¸ëì
ì´ ë ë¤ ê°ì ë ì§ì¤í°ì
ì§ì ì ì¸ ê° (immediate value) ì ì§ì´ë£ëë¤ë©´, 첫ë²ì§¸ ì¸ì¤í¸ëì
ì ë²ë ¤ì§ ìë
ììµëë¤.
ë¹ì·íê², ì»´íì¼ë¬ ìì íë¡ê·¸ë¨ì ì¸ê³¼ì±ë§ ì§ì¼ì¤ë¤ë©´ ì¸ì¤í¸ëì
ì¤í¸ë¦¼ì
ìì ì´ ë³´ê¸°ì ì¬ë°ë¥´ë¤ ìê°ëëëë¡ ì¬ë°°ì¹ í ì ììµëë¤.
===============
CPU ìºìì ìí¥
===============
ìºìë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì´ ìì¤í
ì ì²´ì ì´ë»ê² ì¸ì§ëëì§ë CPU ì ë©ëª¨ë¦¬
ì¬ì´ì ì¡´ì¬íë ìºìë¤, ê·¸ë¦¬ê³ ìì¤í
ìíì ì¼ê´ì±ì ê´ë¦¬íë ë©ëª¨ë¦¬ ì¼ê´ì±
ìì¤í
ì ìë¹ ë¶ë¶ ìí¥ì ë°ìµëë¤.
í CPU ê° ìì¤í
ì ë¤ë¥¸ ë¶ë¶ë¤ê³¼ ìºì를 íµí´ ìí¸ìì©íë¤ë©´, ë©ëª¨ë¦¬ ìì¤í
ì
CPU ì ìºìë¤ì í¬í¨í´ì¼ íë©°, CPU ì CPU ìì ì ìºì ì¬ì´ììì ëìì ìí
ë©ëª¨ë¦¬ 배리ì´ë¥¼ ê°ì ¸ì¼ í©ëë¤. (ë©ëª¨ë¦¬ 배리ì´ë ë
¼ë¦¬ì ì¼ë¡ë ë¤ì 그림ì
ì ì ìì ëìí©ëë¤):
<--- CPU ---> : <----------- Memory ----------->
:
+--------+ +--------+ : +--------+ +-----------+
| | | | : | | | | +--------+
| CPU | | Memory | : | CPU | | | | |
| Core |--->| Access |----->| Cache |<-->| | | |
| | | Queue | : | | | |--->| Memory |
| | | | : | | | | | |
+--------+ +--------+ : +--------+ | | | |
: | Cache | +--------+
: | Coherency |
: | Mechanism | +--------+
+--------+ +--------+ : +--------+ | | | |
| | | | : | | | | | |
| CPU | | Memory | : | CPU | | |--->| Device |
| Core |--->| Access |----->| Cache |<-->| | | |
| | | Queue | : | | | | | |
| | | | : | | | | +--------+
+--------+ +--------+ : +--------+ +-----------+
:
:
í¹ì ë¡ëë ì¤í ì´ë í´ë¹ ì¤í¼ë ì´ì
ì ìì²í CPU ì ìºì ë´ìì ëìì ìë£í
ìë ì기 ë문ì í´ë¹ CPU ì ë°ê¹¥ìë ë³´ì´ì§ ìì ì ìì§ë§, ë¤ë¥¸ CPU ê° ê´ì¬ì
ê°ëë¤ë©´ ìºì ì¼ê´ì± ë©ì»¤ëì¦ì´ í´ë¹ ìºìë¼ì¸ì í´ë¹ CPU ìê² ì ë¬íê³ , í´ë¹
ë©ëª¨ë¦¬ ììì ëí ì¤í¼ë ì´ì
ì´ ë°ìí ëë§ë¤ ê·¸ ìí¥ì ì íìí¤ê¸° ë문ì, í´ë¹
ì¤í¼ë ì´ì
ì ë©ëª¨ë¦¬ì ì¤ì ë¡ ì¡ì¸ì¤ë¥¼ íê²ì²ë¼ ëíë ê²ì
ëë¤.
CPU ì½ì´ë íë¡ê·¸ë¨ì ì¸ê³¼ì±ì´ ì ì§ëë¤ê³ ë§ ì¬ê²¨ì§ë¤ë©´ ì¸ì¤í¸ëì
ë¤ì ì´ë¤
ììë¡ë ì¬ë°°ì¹í´ì ìíí ì ììµëë¤. ì¼ë¶ ì¸ì¤í¸ëì
ë¤ì ë¡ëë ì¤í ì´
ì¤í¼ë ì´ì
ì ë§ëëë° ì´ ì¤í¼ë ì´ì
ë¤ì ì´í ìíë ë©ëª¨ë¦¬ ì¡ì¸ì¤ íì ë¤ì´ê°ê²
ë©ëë¤. ì½ì´ë ì´ ì¤í¼ë ì´ì
ë¤ì í´ë¹ íì ì´ë¤ ììë¡ë ìíëëë¡ ë£ì ì
ìê³ , ë¤ë¥¸ ì¸ì¤í¸ëì
ì ìë£ë¥¼ 기ë¤ë¦¬ëë¡ ê°ì ë기 ì ê¹ì§ë ìíì ê³ìí©ëë¤.
ë©ëª¨ë¦¬ 배리ì´ê° íë ì¼ì CPU 쪽ìì ë©ëª¨ë¦¬ 쪽ì¼ë¡ ëì´ê°ë ì¡ì¸ì¤ë¤ì ìì,
ê·¸ë¦¬ê³ ê·¸ ì¡ì¸ì¤ì ê²°ê³¼ê° ìì¤í
ì ë¤ë¥¸ ê´ì°°ìë¤ìê² ì¸ì§ëë ìì를 ì ì´íë
ê²ì
ëë¤.
[!] CPU ë¤ì íì ê·¸ë¤ ìì ì ë¡ëì ì¤í ì´ë íë¡ê·¸ë¨ ììëë¡ ì¼ì´ë ê²ì¼ë¡
보기 ë문ì, 주ì´ì§ CPU ë´ììë ë©ëª¨ë¦¬ 배리ì´ë¥¼ ì¬ì©í íìê° ììµëë¤.
[!] MMIO ë ë¤ë¥¸ ëë°ì´ì¤ ì¡ì¸ì¤ë¤ì ìºì ìì¤í
ì ì°íí ìë ììµëë¤. ì°í
ì¬ë¶ë ëë°ì´ì¤ê° ì¡ì¸ì¤ ëë ë©ëª¨ë¦¬ ìëì°ì í¹ì±ì ìí´ ê²°ì ë ìë ìê³ , CPU
ê° ê°ì§ê³ ìì ì ìë í¹ìí ëë°ì´ì¤ íµì ì¸ì¤í¸ëì
ì ì¬ì©ì ìí´ì ê²°ì ë
ìë ììµëë¤.
ìºì ì¼ê´ì±
íì§ë§ ì¶ì ììì ì´ì¼ê¸°í ê²ì²ë¼ ë¨ìíì§ ììµëë¤: ìºìë¤ì ì¼ê´ì ì¼ ê²ì¼ë¡
기ëëì§ë§, ê·¸ ì¼ê´ì±ì´ ìììë ì ì©ë ê±°ë¼ë ë³´ì¥ì ììµëë¤. í CPU ìì
ë§ë¤ì´ì§ ë³ê²½ ì¬íì ìµì¢
ì ì¼ë¡ë ìì¤í
ì 모ë CPU ìê² ë³´ì¬ì§ê² ëì§ë§, ë¤ë¥¸
CPU ë¤ìê²ë ê°ì ììë¡ ë³´ì´ê² ë ê±°ë¼ë ë³´ì¥ì ìë¤ë ë»ì
ëë¤.
ëê°ì CPU (1 & 2) ê° ë¬ë ¤ ìê³ , ê° CPU ì ëê°ì ë°ì´í° ìºì(CPU 1 ì A/B 를,
CPU 2 ë C/D 를 ê°ìµëë¤)ê° ë³ë ¬ë¡ ì°ê²°ëì´ ìë ìì¤í
ì ë¤ë£¬ë¤ê³ ìê°í´
ë´
ìë¤:
:
: +--------+
: +---------+ | |
+--------+ : +--->| Cache A |<------->| |
| | : | +---------+ | |
| CPU 1 |<---+ | |
| | : | +---------+ | |
+--------+ : +--->| Cache B |<------->| |
: +---------+ | |
: | Memory |
: +---------+ | System |
+--------+ : +--->| Cache C |<------->| |
| | : | +---------+ | |
| CPU 2 |<---+ | |
| | : | +---------+ | |
+--------+ : +--->| Cache D |<------->| |
: +---------+ | |
: +--------+
:
ì´ ìì¤í ì´ ë¤ìê³¼ ê°ì í¹ì±ì ê°ëë¤ ìê°í´ ë´ ìë¤:
(*) íìë² ìºìë¼ì¸ì ìºì A, ìºì C ëë ë©ëª¨ë¦¬ì ìì¹í ì ìì;
(*) ì§ìë² ìºìë¼ì¸ì ìºì B, ìºì D ëë ë©ëª¨ë¦¬ì ìì¹í ì ìì;
(*) CPU ì½ì´ê° íê°ì ìºìì ì ê·¼íë ëì, ë¤ë¥¸ ìºìë - ëí° ìºìë¼ì¸ì
ë©ëª¨ë¦¬ì ë´ë¦¬ê±°ë ì¶ì¸¡ì± ë¡ë를 íê±°ë í기 ìí´ - ìì¤í
ì ë¤ë¥¸ ë¶ë¶ì
ì¡ì¸ì¤ í기 ìí´ ë²ì¤ë¥¼ ì¬ì©í ì ìì;
(*) ê° ìºìë ìì¤í
ì ëë¨¸ì§ ë¶ë¶ë¤ê³¼ ì¼ê´ì±ì ë§ì¶ê¸° ìí´ í´ë¹ ìºìì
ì ì©ëì´ì¼ í ì¤í¼ë ì´ì
ë¤ì í를 ê°ì§;
(*) ì´ ì¼ê´ì± íë ìºìì ì´ë¯¸ ì¡´ì¬íë ë¼ì¸ì ê°í´ì§ë íë²í ë¡ëì ìí´ìë
ë¹ìì§ì§ ìëë°, íì ì¤í¼ë ì´ì
ë¤ì´ ì´ ë¡ëì ê²°ê³¼ì ìí¥ì ë¼ì¹ ì ìë¤
í ì§ë¼ë ê·¸ë¬í¨.
ì´ì , 첫ë²ì§¸ CPU ìì ëê°ì ì°ê¸° ì¤í¼ë ì´ì
ì ë§ëëë°, í´ë¹ CPU ì ìºìì
ìì²ë ììë¡ ì¤í¼ë ì´ì
ì´ ëë¬ë¨ì ë³´ì¥í기 ìí´ ë ì¤í¼ë ì´ì
ì¬ì´ì ì°ê¸°
배리ì´ë¥¼ ì¬ì©íë ìí©ì ììí´ ë´
ìë¤:
CPU 1 CPU 2 COMMENT
=============== =============== =======================================
u == 0, v == 1 and p == &u, q == &u
v = 2;
smp_wmb(); v ì ë³ê²½ì´ p ì ë³ê²½ ì ì ë³´ì¼ ê²ì
ë¶ëª
í í¨
<A:modify v=2> v ë ì´ì ìºì A ì ë
ì ì ì¼ë¡ ì¡´ì¬í¨
p = &v;
<B:modify p=&v> p ë ì´ì ìºì B ì ë
ì ì ì¼ë¡ ì¡´ì¬í¨
ì¬ê¸°ìì ì°ê¸° ë©ëª¨ë¦¬ 배리ì´ë CPU 1 ì ìºìê° ì¬ë°ë¥¸ ììë¡ ì
ë°ì´í¸ ë ê²ì¼ë¡
ìì¤í
ì ë¤ë¥¸ CPU ë¤ì´ ì¸ì§íê² ë§ëëë¤. íì§ë§, ì´ì ëë²ì§¸ CPU ê° ê·¸ ê°ë¤ì
ì½ì¼ë ¤ íë ìí©ì ìê°í´ ë´
ìë¤:
CPU 1 CPU 2 COMMENT
=============== =============== =======================================
...
q = p;
x = *q;
ìì ëê°ì ì½ê¸° ì¤í¼ë ì´ì
ì ììë ììë¡ ì¼ì´ëì§ ëª»í ì ìëë°, ëë²ì§¸ CPU
ì í ìºìì ë¤ë¥¸ ìºì ì´ë²¤í¸ê° ë°ìí´ v 를 ë´ê³ ìë ìºìë¼ì¸ì í´ë¹ ìºììì
ì
ë°ì´í¸ê° ì§ì°ëë ì¬ì´, p 를 ë´ê³ ìë ìºìë¼ì¸ì ëë²ì§¸ CPU ì ë¤ë¥¸ ìºìì
ì
ë°ì´í¸ ëì´ë²ë ¸ì ì ì기 ë문ì
ëë¤.
CPU 1 CPU 2 COMMENT
=============== =============== =======================================
u == 0, v == 1 and p == &u, q == &u
v = 2;
smp_wmb();
<A:modify v=2> <C:busy>
<C:queue v=2>
p = &v; q = p;
<D:request p>
<B:modify p=&v> <D:commit p=&v>
<D:read p>
x = *q;
<C:read *q> ìºìì ì
ë°ì´í¸ ë기 ì ì v 를 ì½ì
<C:unbusy>
<C:commit v=2>
기본ì ì¼ë¡, ëê°ì ìºìë¼ì¸ 모ë CPU 2 ì ìµì¢
ì ì¼ë¡ë ì
ë°ì´í¸ ë ê²ì´ì§ë§,
ë³ëì ê°ì
ìì´ë, ì
ë°ì´í¸ì ììê° CPU 1 ìì ë§ë¤ì´ì§ ììì ëì¼í
ê²ì´ë¼ë ë³´ì¥ì´ ììµëë¤.
ì¬ê¸°ì ê°ì
í기 ìí´ì , ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ì½ê¸° 배리ì´ë¥¼ ë¡ë ì¤í¼ë ì´ì
ë¤
ì¬ì´ì ë£ì´ì¼ í©ëë¤ (v4.15 ë¶í°ë READ_ONCE() 매í¬ë¡ì ìí´ ë¬´ì¡°ê±´ì ì¼ë¡
ê·¸ë ê² ë©ëë¤). ì´ë ê² í¨ì¼ë¡ì¨ ìºìê° ë¤ì ìì²ì ì²ë¦¬í기 ì ì ì¼ê´ì± í를
ì²ë¦¬íëë¡ ê°ì íê² ë©ëë¤.
CPU 1 CPU 2 COMMENT
=============== =============== =======================================
u == 0, v == 1 and p == &u, q == &u
v = 2;
smp_wmb();
<A:modify v=2> <C:busy>
<C:queue v=2>
p = &v; q = p;
<D:request p>
<B:modify p=&v> <D:commit p=&v>
<D:read p>
smp_read_barrier_depends()
<C:unbusy>
<C:commit v=2>
x = *q;
<C:read *q> ìºìì ì
ë°ì´í¸ ë v 를 ì½ì
ì´ë° ë¶ë¥ì 문ì ë DEC Alpha ê³ì´ íë¡ì¸ìë¤ìì ë°ê²¬ë ì ìëë°, ì´ë¤ì
ë°ì´í° ë²ì¤ë¥¼ ì¢ ë ì ì¬ì©í´ ì±ë¥ì ê°ì í ì ìë, ë¶í ë ìºì를 ê°ì§ê³ ì기
ë문ì
ëë¤. ëë¶ë¶ì CPU ë íëì ì½ê¸° ì¤í¼ë ì´ì
ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ê° ë¤ë¥¸ ì½ê¸°
ì¤í¼ë ì´ì
ì ìì¡´ì ì´ë¼ë©´ ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë¥¼ ë´í¬ìíµëë¤ë§, 모ëê° ê·¸ë°ê±´
ìë기 ë문ì ì´ì ì ìì¡´í´ì ìë©ëë¤.
ë¤ë¥¸ CPU ë¤ë ë¶í ë ìºì를 ê°ì§ê³ ìì ì ìì§ë§, ê·¸ë° CPU ë¤ì íë²í ë©ëª¨ë¦¬
ì¡ì¸ì¤ë¥¼ ìí´ìë ì´ ë¶í ë ìºìë¤ ì¬ì´ì ì¡°ì ì í´ì¼ë§ í©ëë¤. Alpha ë ê°ì¥
ì½í ë©ëª¨ë¦¬ ìì ìë§¨í± (semantic) ì ì íí¨ì¼ë¡ì¨ ë©ëª¨ë¦¬ 배리ì´ê° ëª
ìì ì¼ë¡
ì¬ì©ëì§ ììì ëìë ê·¸ë° ì¡°ì ì´ íìíì§ ìê² íì¼ë©°, ì´ë Alpha ê° ë¹ìì
ë ëì CPU í´ë½ ìë를 ê°ì§ ì ìê² íìµëë¤. íì§ë§, (ë¤ì ë§íê±´ë, v4.15
ì´íë¶í°ë) Alpha ìí¤í
ì³ ì ì© ì½ëì READ_ONCE() 매í¬ë¡ ë´ë¶ìì를 ì ì¸íê³ ë
smp_read_barrier_depends() ê° ì¬ì©ëì§ ììì¼ í¨ì ììëì기 ë°ëëë¤.
ìºì ì¼ê´ì± VS DMA
모ë ìì¤í
ì´ DMA 를 íë ëë°ì´ì¤ì ëí´ìê¹ì§ ìºì ì¼ê´ì±ì ì ì§íì§ë
ììµëë¤. ê·¸ë° ê²½ì°, DMA 를 ìëíë ëë°ì´ì¤ë RAM ì¼ë¡ë¶í° ì못ë ë°ì´í°ë¥¼
ì½ì ì ìëë°, ëí° ìºì ë¼ì¸ì´ CPU ì ìºìì ë¨¸ë¬´ë¥´ê³ ìê³ , ë°ë ê°ì´ ìì§
RAM ì ì¨ì§ì§ ììì ì ì기 ë문ì
ëë¤. ì´ ë¬¸ì 를 í´ê²°í기 ìí´ì , 커ëì
ì ì í ë¶ë¶ìì ê° CPU ìºìì 문ì ëë ë¹í¸ë¤ì íë¬ì (flush) ìì¼ì¼ë§ í©ëë¤
(ê·¸ë¦¬ê³ ê·¸ê²ë¤ì 무í¨í - invalidation - ìí¬ ìë ìê² ì£ ).
ëí, ëë°ì´ì¤ì ìí´ RAM ì DMA ë¡ ì°ì¬ì§ ê°ì ëë°ì´ì¤ê° ì°ê¸°ë¥¼ ìë£í íì
CPU ì ìºììì RAM ì¼ë¡ ì°ì¬ì§ë ëí° ìºì ë¼ì¸ì ìí´ ë®ì´ì¨ì§ ìë ìê³ , CPU
ì ìºìì ì¡´ì¬íë ìºì ë¼ì¸ì´ í´ë¹ ìºììì ìì ëê³ ë¤ì ê°ì ì½ì´ë¤ì´ê¸°
ì ê¹ì§ë RAM ì´ ì
ë°ì´í¸ ëìë¤ë ì¬ì¤ ìì²´ê° ì¨ê²¨ì ¸ ë²ë¦´ ìë ììµëë¤. ì´
문ì 를 í´ê²°í기 ìí´ì , 커ëì ì ì í ë¶ë¶ìì ê° CPU ì ìºì ìì 문ì ê° ëë
ë¹í¸ë¤ì 무í¨í ìì¼ì¼ í©ëë¤.
ìºì ê´ë¦¬ì ëí ë ë§ì ì 보를 ìí´ì Documentation/core-api/cachetlb.rst 를
ì°¸ê³ íì¸ì.
ìºì ì¼ê´ì± VS MMIO
Memory mapped I/O ë ì¼ë°ì ì¼ë¡ CPU ì ë©ëª¨ë¦¬ ê³µê° ë´ì í ìëì°ì í¹ì ë¶ë¶
ë´ì ë©ëª¨ë¦¬ ì§ìì ì´ë£¨ì´ì§ëë°, ì´ ìëì°ë ì¼ë°ì ì¸, RAM ì¼ë¡ í¥íë
ìëì°ìë ë¤ë¥¸ í¹ì±ì ê°ìµëë¤.
ê·¸ë° í¹ì± ê°ì´ë° íëë, ì¼ë°ì ì¼ë¡ ê·¸ë° ì¡ì¸ì¤ë ìºì를 ìì í ì°ííê³
ëë°ì´ì¤ ë²ì¤ë¡ 곧ë°ë¡ í¥íë¤ë ê²ì
ëë¤. ì´ ë§ì MMIO ì¡ì¸ì¤ë 먼ì
ììëì´ì ìºììì ìë£ë ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¥¼ ì¶ìí ì ìë¤ë ë»ì
ëë¤. ì´ë°
ê²½ì°ì ë©ëª¨ë¦¬ 배리ì´ë§ì¼ë¡ë 충ë¶ì¹ ìê³ , ë§ì½ ìºìë ë©ëª¨ë¦¬ ì°ê¸° ì¤í¼ë ì´ì
ê³¼
MMIO ì¡ì¸ì¤ê° ì´ë¤ ë°©ìì¼ë¡ë ìì¡´ì ì´ë¼ë©´ í´ë¹ ìºìë ë ì¤í¼ë ì´ì
ì¬ì´ì
ë¹ìì ¸(flush)ì¼ë§ í©ëë¤.
======================
CPU ë¤ì´ ì ì§ë¥´ë ì¼ë¤
======================
íë¡ê·¸ë머ë CPU ê° ë©ëª¨ë¦¬ ì¤í¼ë ì´ì
ë¤ì ì íí ìì²íëë¡ ìíí´ ì¤ ê²ì´ë¼ê³
ìê°íëë°, ì를 ë¤ì´ ë¤ìê³¼ ê°ì ì½ë를 CPU ìê² ë긴ë¤ë©´:
a = READ_ONCE(*A);
WRITE_ONCE(*B, b);
c = READ_ONCE(*C);
d = READ_ONCE(*D);
WRITE_ONCE(*E, e);
CPU ë ë¤ì ì¸ì¤í¸ëì
ì ì²ë¦¬í기 ì ì íì¬ì ì¸ì¤í¸ëì
ì ìí ë©ëª¨ë¦¬
ì¤í¼ë ì´ì
ì ìë£í ê²ì´ë¼ ìê°íê³ , ë°ë¼ì ìì¤í
ì¸ë¶ìì ê´ì°°í기ìë ì í´ì§
ììëë¡ ì¤í¼ë ì´ì
ì´ ìíë ê²ì¼ë¡ ììí©ëë¤:
LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.
ë¹ì°íì§ë§, ì¤ì ë¡ë í¨ì¬ ìë§ì
ëë¤. ë§ì CPU ì ì»´íì¼ë¬ìì ìì ê°ì ì
ì±ë¦½íì§ ëª»íëë° ê·¸ ì´ì ë ë¤ìê³¼ ê°ìµëë¤:
(*) ë¡ë ì¤í¼ë ì´ì
ë¤ì ì¤íì ê³ì í´ëê°ê¸° ìí´ ê³§ë°ë¡ ìë£ë íìê° ìë
ê²½ì°ê° ë§ì ë°ë©´, ì¤í ì´ ì¤í¼ë ì´ì
ë¤ì ì¢
ì¢
ë³ë¤ë¥¸ 문ì ìì´ ì ìë ì
ììµëë¤;
(*) ë¡ë ì¤í¼ë ì´ì
ë¤ì ì측ì ì¼ë¡ ìíë ì ìì¼ë©°, íììë ë¡ëìë¤ê³
ì¦ëª
ë ì측ì ë¡ëì ê²°ê³¼ë ë²ë ¤ì§ëë¤;
(*) ë¡ë ì¤í¼ë ì´ì
ë¤ì ì측ì ì¼ë¡ ìíë ì ìì¼ë¯ë¡, ììë ì´ë²¤í¸ì
ìíì¤ì ë¤ë¥¸ ìê°ì ë¡ëê° ì´ë¤ì§ ì ììµëë¤;
(*) ë©ëª¨ë¦¬ ì¡ì¸ì¤ ììë CPU ë²ì¤ì ìºì를 ì¢ ë ì ì¬ì©í ì ìëë¡ ì¬ë°°ì¹
ë ì ììµëë¤;
(*) ë¡ëì ì¤í ì´ë ì¸ì í ìì¹ìì ì¡ì¸ì¤ë¤ì ì¼ê´ì ì¼ë¡ ì²ë¦¬í ì ìë
ë©ëª¨ë¦¬ë I/O íëì¨ì´ (ë©ëª¨ë¦¬ì PCI ëë°ì´ì¤ ë ë¤ ì´ê² ê°ë¥í ì
ììµëë¤) ì ëí´ ìì²ëë ê²½ì°, ê°ë³ ì¤í¼ë ì´ì
ì ìí í¸ëìì
ì¤ì
ë¹ì©ì ìë¼ê¸° ìí´ ì¡°í©ëì´ ì¤íë ì ììµëë¤; 그리ê³
(*) í´ë¹ CPU ì ë°ì´í° ìºìê° ììì ìí¥ì ë¼ì¹ ìë ìê³ , ìºì ì¼ê´ì±
ë©ì»¤ëì¦ì´ - ì¤í ì´ê° ì¤ì ë¡ ìºìì ëë¬íë¤ë©´ - ì´ ë¬¸ì 를 ìíìí¬ ìë
ìì§ë§ ì´ ì¼ê´ì± ê´ë¦¬ê° ë¤ë¥¸ CPU ë¤ìë ê°ì ììë¡ ì ë¬ëë¤ë ë³´ì¥ì
ììµëë¤.
ë°ë¼ì, ìì ì½ëì ëí´ ë¤ë¥¸ CPU ê° ë³´ë ê²°ê³¼ë ë¤ìê³¼ ê°ì ì ììµëë¤:
LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B
("LOAD {*C,*D}" ë ì¡°í©ë ë¡ëì
ëë¤)
íì§ë§, CPU ë ì¤ì¤ë¡ë ì¼ê´ì ì¼ ê²ì ë³´ì¥í©ëë¤: CPU _ìì _ ì ì¡ì¸ì¤ë¤ì
ìì ìê²ë ë©ëª¨ë¦¬ 배리ì´ê° ìììë ë¶êµ¬íê³ ì íí ìì ì¸ìì§ ê²ì¼ë¡ ë³´ì¬ì§
ê²ì
ëë¤. ì를 ë¤ì´ ë¤ìì ì½ëê° ì£¼ì´ì¡ë¤ë©´:
U = READ_ONCE(*A);
WRITE_ONCE(*A, V);
WRITE_ONCE(*A, W);
X = READ_ONCE(*A);
WRITE_ONCE(*A, Y);
Z = READ_ONCE(*A);
ê·¸ë¦¬ê³ ì¸ë¶ì ìí¥ì ìí ê°ìì´ ìë¤ê³ ê°ì íë©´, ìµì¢
ê²°ê³¼ë ë¤ìê³¼ ê°ì´
ëíë ê²ì´ë¼ê³ ììë ì ììµëë¤:
U == *A ì ìµì´ ê°
X == W
Z == Y
*A == Y
ìì ì½ëë CPU ê° ë¤ìì ë©ëª¨ë¦¬ ì¡ì¸ì¤ ìíì¤ë¥¼ ë§ë¤ëë¡ í ê²ëë¤:
U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A
íì§ë§, ë³ë¤ë¥¸ ê°ì
ì´ ìê³ íë¡ê·¸ë¨ì ìì¼ì ì´ ì¸ìì´ ì¬ì í ì¼ê´ì ì´ë¼ê³
ë³´ì¸ë¤ë ë³´ì¥ë§ ì§ì¼ì§ë¤ë©´ ì´ ìíì¤ë ì´ë¤ ì¡°í©ì¼ë¡ë ì¬êµ¬ì±ë ì ìì¼ë©°, ê°
ì¡ì¸ì¤ë¤ì í©ì³ì§ê±°ë ë²ë ¤ì§ ì ììµëë¤. ì¼ë¶ ìí¤í
ì³ìì CPU ë ê°ì ìì¹ì
ëí ì°ìì ì¸ ë¡ë ì¤í¼ë ì´ì
ë¤ì ì¬ë°°ì¹ í ì ì기 ë문ì ìì ìììì
READ_ONCE() ì WRITE_ONCE() ë ë°ëì ì¡´ì¬í´ì¼ í¨ì ììëì¸ì. ê·¸ë° ì¢
ë¥ì
ìí¤í
ì³ìì READ_ONCE() ì WRITE_ONCE() ë ì´ ë¬¸ì 를 ë§ê¸° ìí´ íìí ì¼ì
ëê° ëë ì§ íê² ëëë°, ì를 ë¤ì´ Itanium ììë READ_ONCE() ì WRITE_ONCE()
ê° ì¬ì©íë volatile ìºì¤í
ì GCC ê° ê·¸ë° ì¬ë°°ì¹ë¥¼ ë°©ì§íë í¹ì ì¸ì¤í¸ëì
ì¸
ld.acq ì stl.rel ì¸ì¤í¸ëì
ì ê°ê° ë§ë¤ì´ ë´ëë¡ í©ëë¤.
ì»´íì¼ë¬ ìì ì´ ìíì¤ì ì¡ì¸ì¤ë¤ì CPU ê° ë³´ê¸°ë ì ì í©ì¹ê±°ë ë²ë¦¬ê±°ë ë¤ë¡
미ë¤ë²ë¦´ ì ììµëë¤.
ì를 ë¤ì´:
*A = V;
*A = W;
ë ë¤ìê³¼ ê°ì´ ë³íë ì ììµëë¤:
*A = W;
ë°ë¼ì, ì°ê¸° 배리ì´ë WRITE_ONCE() ê° ìë¤ë©´ *A ë¡ì V ê°ì ì ì¥ì í¨ê³¼ë
ì¬ë¼ì§ë¤ê³ ê°ì ë ì ììµëë¤. ë¹ì·íê²:
*A = Y;
Z = *A;
ë, ë©ëª¨ë¦¬ 배리ì´ë READ_ONCE() ì WRITE_ONCE() ìì´ë ë¤ìê³¼ ê°ì´ ë³íë ì
ììµëë¤:
*A = Y;
Z = Y;
ê·¸ë¦¬ê³ ì´ LOAD ì¤í¼ë ì´ì ì CPU ë°ê¹¥ìë ìì ë³´ì´ì§ ììµëë¤.
ê·¸ë¦¬ê³ , ALPHA ê° ìë¤
DEC Alpha CPU ë ê°ì¥ ìíë ë©ëª¨ë¦¬ ììì CPU ì¤ íëì
ëë¤. ë¿ë§ ìëë¼,
Alpha CPU ì ì¼ë¶ ë²ì ì ë¶í ë ë°ì´í° ìºì를 ê°ì§ê³ ìì´ì, ì미ì ì¼ë¡
ê´ê³ëì´ ìë ëê°ì ìºì ë¼ì¸ì´ ìë¡ ë¤ë¥¸ ìê°ì ì
ë°ì´í¸ ëëê² ê°ë¥í©ëë¤.
ì´ê² ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ê° ì ë§ íìí´ì§ë ë¶ë¶ì¸ë°, ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë
ë©ëª¨ë¦¬ ì¼ê´ì± ìì¤í
ê³¼ í¨ê» ëê°ì ìºì를 ë기í ìì¼ì, í¬ì¸í° ë³ê²½ê³¼ ìë¡ì´
ë°ì´í°ì ë°ê²¬ì ì¬ë°ë¥¸ ììë¡ ì¼ì´ëê² í기 ë문ì
ëë¤.
리ë
ì¤ ì»¤ëì ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ëª¨ë¸ì Alpha ì 기ì´í´ì ì ìëììµëë¤ë§, v4.15
ë¶í°ë 리ë
ì¤ ì»¤ëì´ READ_ONCE() ë´ì smp_read_barrier_depends() 를 ì¶ê°í´ì
Alpha ì ë©ëª¨ë¦¬ 모ë¸ë¡ì ìí¥ë ¥ì´ í¬ê² ì¤ì´ë¤ê¸´ íìµëë¤.
ìì “ìºì ì¼ê´ì±” ìë¸ì¹ì ì ì°¸ê³ íì¸ì.
ê°ì 머ì ê²ì¤í¸
ê°ì 머ì ìì ëìíë ê²ì¤í¸ë¤ì ê²ì¤í¸ ìì²´ë SMP ì§ì ìì´ ì»´íì¼ ëìë¤
í´ë SMP ìí¥ì ë°ì ì ììµëë¤. ì´ê±´ UP 커ëì ì¬ì©íë©´ì SMP í¸ì¤í¸ì
ê²°ë¶ëì´ ë°ìíë ë¶ìì©ì
ëë¤. ì´ ê²½ì°ìë mandatory 배리ì´ë¥¼ ì¬ì©í´ì 문ì 를
í´ê²°í ì ìê² ì§ë§ ê·¸ë° í´ê²°ì ëë¶ë¶ì ê²½ì° ìµì ì í´ê²°ì±
ì´ ìëëë¤.
ì´ ë¬¸ì 를 ìë²½íê² í´ê²°í기 ìí´, ë¡ì° ë 벨ì virt_mb() ë±ì 매í¬ë¡ë¥¼ ì¬ì©í ì
ììµëë¤. ì´ê²ë¤ì SMP ê° íì±í ëì´ ìë¤ë©´ smp_mb() ë±ê³¼ ëì¼í í¨ê³¼ë¥¼
ê°ìµëë¤ë§, SMP ì SMP ìë ìì¤í
모ëì ëí´ ëì¼í ì½ë를 ë§ë¤ì´ë
ëë¤.
ì를 ë¤ì´, ê°ì 머ì ê²ì¤í¸ë¤ì (SMP ì¼ ì ìë) í¸ì¤í¸ì ë기í를 í ëìë
smp_mb() ê° ìëë¼ virt_mb() 를 ì¬ì©í´ì¼ í©ëë¤.
ì´ê²ë¤ì smp_mb() ë¥ì ê²ë¤ê³¼ 모ë ë¶ë¶ìì ëì¼íë©°, í¹í, MMIO ì ìí¥ì
ëí´ìë ê°ì¬íì§ ììµëë¤: MMIO ì ìí¥ì ì ì´íë ¤ë©´, mandatory 배리ì´ë¥¼
ì¬ì©íì기 ë°ëëë¤.
=======
ì¬ì© ì
=======
ìíì ë²í¼
ë©ëª¨ë¦¬ 배리ì´ë ìíì ë²í¼ë¥¼ ìì±ì(producer)ì ìë¹ì(consumer) ì¬ì´ì
ë기íì ë½ì ì¬ì©íì§ ìê³ êµ¬ííëë°ì ì¬ì©ë ì ììµëë¤. ë ìì¸í ë´ì©ì
ìí´ì ë¤ìì ì°¸ê³ íì¸ì:
Documentation/core-api/circular-buffers.rst
=========
ì°¸ê³ ë¬¸í
=========
Alpha AXP Architecture Reference Manual, Second Edition (Sites & Witek,
Digital Press)
Chapter 5.2: Physical Address Space Characteristics
Chapter 5.4: Caches and Write Buffers
Chapter 5.5: Data Sharing
Chapter 5.6: Read/Write Ordering
AMD64 Architecture Programmer’s Manual Volume 2: System Programming
Chapter 7.1: Memory-Access Ordering
Chapter 7.4: Buffering and Combining Memory Writes
ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
Chapter B2: The AArch64 Application Level Memory Model
IA-32 Intel Architecture Software Developer’s Manual, Volume 3:
System Programming Guide
Chapter 7.1: Locked Atomic Operations
Chapter 7.2: Memory Ordering
Chapter 7.4: Serializing Instructions
The SPARC Architecture Manual, Version 9
Chapter 8: Memory Models
Appendix D: Formal Specification of the Memory Models
Appendix J: Programming with the Memory Models
Storage in the PowerPC (Stone and Fitzgerald)
UltraSPARC Programmer Reference Manual
Chapter 5: Memory Accesses and Cacheability
Chapter 15: Sparc-V9 Memory Models
UltraSPARC III Cu User’s Manual
Chapter 9: Memory Models
UltraSPARC IIIi Processor User’s Manual
Chapter 8: Memory Models
UltraSPARC Architecture 2005
Chapter 9: Memory
Appendix D: Formal Specifications of the Memory Models
UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
Chapter 8: Memory Models
Appendix F: Caches and Cache Coherency
Solaris Internals, Core Kernel Architecture, p63-68:
Chapter 3.3: Hardware Considerations for Locks and
Synchronization
Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching
for Kernel Programmers:
Chapter 13: Other Memory Models
Intel Itanium Architecture Software Developer’s Manual: Volume 1:
Section 2.6: Speculation
Section 4.4: Memory Access