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.ibm.com> Will Deacon <will.deacon@arm.com> Peter Zijlstra <peterz@infradead.org> ======== ë©´ì± ì¡°í ======== ì´ ë¬¸ìë ëª ì¸ìê° ìëëë¤; ì´ ë¬¸ìë ìë²½íì§ ììë°, ê°ê²°ì±ì ìí´ ìëë ë¶ë¶ë ìê³ , ìëíì§ ììì§ë§ ì¬ëì ìí´ ì°ìë¤ë³´ë ë¶ìì í ë¶ë¶ë ììµëë¤. ì´ ë¬¸ìë 리ë ì¤ìì ì ê³µíë ë¤ìí ë©ëª¨ë¦¬ 배리ì´ë¤ì ì¬ì©í기 ìí ìë´ìì ëë¤ë§, ëê° ì´ìíë¤ ì¶ì¼ë©´ (ê·¸ë°ê² ë§ì ê²ëë¤) ì§ë¬¸ì ë¶íë립ëë¤. ì¼ë¶ ì´ìí ì ë¤ì ê³µìì ì¸ ë©ëª¨ë¦¬ ì¼ê´ì± 모ë¸ê³¼ tools/memory-model/ ì ìë ê´ë ¨ 문ì를 ì°¸ê³ í´ì í´ê²°ë ì ìì ê²ëë¤. ê·¸ë¬ë, ì´ ë©ëª¨ë¦¬ 모ë¸ì¡°ì°¨ë ê·¸ ê´ë¦¬ìë¤ì ì견ì ì§í©ì¼ë¡ ë´ì¼ì§, ì ë ì³ì ìì¸ìë¡ ì ë´í´ì ìë ê²ëë¤. ë¤ì ë§íì§ë§, ì´ ë¬¸ìë 리ë ì¤ê° íëì¨ì´ì 기ëíë ì¬íì ëí ëª ì¸ìê° ìëëë¤. ì´ ë¬¸ìì 목ì ì ëê°ì§ì ëë¤: (1) ì´ë¤ í¹ì 배리ì´ì ëí´ ê¸°ëí ì ìë ìµìíì 기ë¥ì ëª ì¸í기 ìí´ì, ê·¸ë¦¬ê³ (2) ì¬ì© ê°ë¥í 배리ì´ë¤ì ëí´ ì´ë»ê² ì¬ì©í´ì¼ íëì§ì ëí ìë´ë¥¼ ì ê³µí기 ìí´ì. ì´ë¤ ìí¤í ì³ë í¹ì í 배리ì´ë¤ì ëí´ìë ì¬ê¸°ì ì´ì¼ê¸°íë ìµìíì ì구ì¬íë¤ë³´ë¤ ë§ì 기ë¥ì ì ê³µí ìë ììµëë¤ë§, ì¬ê¸°ì ì´ì¼ê¸°íë ì구ì¬íë¤ì 충족íì§ ìë ìí¤í ì³ê° ìë¤ë©´ ê·¸ ìí¤í ì³ê° ì못ë ê²ì´ë ì ì ììëì기 ë°ëëë¤. ëí, í¹ì ìí¤í ì³ìì ì¼ë¶ 배리ì´ë í´ë¹ ìí¤í ì³ì í¹ìí ëì ë°©ìì¼ë¡ ì¸í´ í´ë¹ 배리ì´ì ëª ìì ì¬ì©ì´ ë¶íìí´ì no-op ì´ ë ìë ììì ììëì기 ë°ëëë¤. ìì: 본 ë²ì ìì ìë²½íì§ ììë°, ì´ ìì ë¶ë¶ì ì¼ë¡ë ìëë ê²ì´ê¸°ë í©ëë¤. ì¬í 기ì 문ìë¤ì´ ê·¸ë ë¯ ìë²½í ì´í´ë¥¼ ìí´ìë ë²ì문과 ì문ì í¨ê» ì½ì¼ìë ë²ì문ì íëì ê°ì´ëë¡ íì©íì길 ì¶ì²ë리며, ë°ê²¬ëë ì¤ì ë±ì ëí´ìë ì¸ì ë ì견ì ë¶íë립ëë¤. ê³¼í ë²ìì¼ë¡ ì¸í ì¤í´ë¥¼ ìµìíí기 ìí´ ì 매í ë¶ë¶ì´ ìì ê²½ì°ìë ì´ìí¨ì´ ìëë¼ë ìëì ì©ì´ë¥¼ ì°¨ì©í©ëë¤. ===== 목차: ===== (*) ì¶ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ 모ë¸. - ëë°ì´ì¤ ì¤í¼ë ì´ì . - ë³´ì¥ì¬í. (*) ë©ëª¨ë¦¬ 배리ì´ë 무ìì¸ê°? - ë©ëª¨ë¦¬ 배리ì´ì ì¢ ë¥. - ë©ëª¨ë¦¬ 배리ì´ì ëí´ ê°ì í´ì ìë ê². - ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ (ìì¬ì ). - 컨í¸ë¡¤ ìì¡´ì±. - SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°. - ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ìíì¤ì ì. - ì½ê¸° ë©ëª¨ë¦¬ ë°°ë¦¬ì´ vs ë¡ë ì측. - Multicopy ììì±. (*) ëª ìì 커ë 배리ì´. - ì»´íì¼ë¬ 배리ì´. - CPU ë©ëª¨ë¦¬ 배리ì´. (*) ì묵ì 커ë ë©ëª¨ë¦¬ 배리ì´. - ë½ Acquisition í¨ì. - ì¸í°ë½í¸ ë¹íì±í í¨ì. - ì¬ë¦½ê³¼ ì¨ì´í¬ì í¨ì. - ê·¸ì¸ì í¨ìë¤. (*) CPU ê° ACQUIRING 배리ì´ì í¨ê³¼. - Acquire vs ë©ëª¨ë¦¬ ì¡ì¸ì¤. (*) ë©ëª¨ë¦¬ 배리ì´ê° íìí ê³³ - íë¡ì¸ìê° ìí¸ ìì©. - ì´í 믹 ì¤í¼ë ì´ì . - ëë°ì´ì¤ ì¡ì¸ì¤. - ì¸í°ë½í¸. (*) 커ë 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_load_acquire() ì¤í¼ë ì´ì ë ACQUIRE ì¤í¼ë ì´ì ì í¬í¨ë©ëë¤. ACQUIRE ì¤í¼ë ì´ì ìì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì ë¤ì ACQUIRE ì¤í¼ë ì´ì ìë£ íì ìíë ê²ì²ë¼ ë³´ì¼ ì ììµëë¤. ACQUIRE ì¤í¼ë ì´ì ì ê±°ì íì RELEASE ì¤í¼ë ì´ì ê³¼ ì§ì ì§ì´ ì¬ì©ëì´ì¼ í©ëë¤. (6) RELEASE ì¤í¼ë ì´ì . ì´ íì ì ì¤í¼ë ì´ì ë¤ë ë¨ë°©í¥ í¬ê³¼ì± 배리ì´ì²ë¼ ëìí©ëë¤. RELEASE ì¤í¼ë ì´ì ìì 모ë ë©ëª¨ë¦¬ ì¤í¼ë ì´ì ë¤ì RELEASE ì¤í¼ë ì´ì ì ì ìë£ë ê²ì¼ë¡ ìì¤í ì ë¤ë¥¸ ì»´í¬ëí¸ë¤ì ë³´ì¬ì§ ê²ì´ ë³´ì¥ë©ëë¤. UNLOCK ë¥ì ì¤í¼ë ì´ì ë¤ê³¼ smp_store_release() ì¤í¼ë ì´ì ë RELEASE ì¤í¼ë ì´ì ì ì¼ì¢ ì ëë¤. RELEASE ì¤í¼ë ì´ì ë¤ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì ë¤ì RELEASE ì¤í¼ë ì´ì ì´ ìë£ë기 ì ì íí´ì§ ê²ì²ë¼ ë³´ì¼ ì ììµëë¤. ACQUIRE ì RELEASE ì¤í¼ë ì´ì ì ì¬ì©ì ì¼ë°ì ì¼ë¡ ë¤ë¥¸ ë©ëª¨ë¦¬ 배리ì´ì íìì±ì ìì±ëë¤. ëí, 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/driver-api/pci/pci.rst Documentation/core-api/dma-api-howto.rst Documentation/core-api/dma-api.rst ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ (ìì¬ì ) ----------------------------- 리ë ì¤ ì»¤ë v4.15 기ì¤ì¼ë¡, smp_mb() ê° DEC Alpha ì© 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.rst íì¼ì 주ì ê¹ê² ì½ì´ 주ì기 ë°ëëë¤: ì»´íì¼ë¬ë ë§¤ì° ì°½ìì ì¸ ë§ì ë°©ë²ì¼ë¡ ì¢ ìì±ì ê¹° ì ììµëë¤. 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 ë©ëª¨ë¦¬ 배리ì´. ì»´íì¼ë¬ ë°°ë¦¬ì´ --------------- 리ë ì¤ ì»¤ëì ì»´íì¼ë¬ê° ë©ëª¨ë¦¬ ì¡ì¸ì¤ë¥¼ ì¬ë°°ì¹ íë ê²ì ë§ì주ë ëª ìì ì¸ ì»´íì¼ë¬ 배리ì´ë¥¼ ê°ì§ê³ ììµëë¤: 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(); ì´ê²ë¤ì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´í¬íì§ ìë ì´í 믹 RMW í¨ì를 ì¬ì©íì§ë§ ì½ëì ë©ëª¨ë¦¬ 배리ì´ê° íìí ê²½ì°ë¥¼ ìí ê²ë¤ì ëë¤. ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´í¬íì§ ìë ì´í 믹 RMW í¨ìë¤ì ìë¡ë ëí기, 빼기, (ì¤í¨í) ì¡°ê±´ì ì¤í¼ë ì´ì ë¤, _relaxed í¨ìë¤ì´ ìì¼ë©°, atomic_read ë atomic_set ì ì´ì í´ë¹ëì§ ììµëë¤. ë©ëª¨ë¦¬ 배리ì´ê° íìí´ì§ë íí ìë¡ë ì´í 믹 ì¤í¼ë ì´ì ì ì¬ì©í´ ë í¼ë°ì¤ ì¹´ì´í¸ë¥¼ ìì íë ê²½ì°ë¥¼ ë¤ ì ììµëë¤. ì´ê²ë¤ì ëí (set_bit ê³¼ clear_bit ê°ì) ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´í¬íì§ ìë ì´í 믹 RMW bitop í¨ìë¤ì ìí´ìë ì¬ì©ë ì ììµëë¤. í ìë¡, ê°ì²´ íë를 무í¨í ê²ì¼ë¡ íìíê³ ê·¸ ê°ì²´ì ë í¼ë°ì¤ ì¹´ì´í¸ë¥¼ ê°ììí¤ë ë¤ì ì½ë를 ë³´ì¸ì: 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; /* ì ë°ì´í¸ë ëì¤í¬ë¦½í°ì ëë°ì´ì¤ì ê³µì§ */ writel(DESC_NOTIFY, doorbell); } dma_rmb() ë ëì¤í¬ë¦½í°ë¡ë¶í° ë°ì´í°ë¥¼ ì½ì´ì¤ê¸° ì ì ëë°ì´ì¤ê° ìì ê¶ì ë´ë ¤ëìì ê²ì ë³´ì¥íê³ , dma_wmb() ë ëë°ì´ì¤ê° ìì ì´ ìì ê¶ì ë¤ì ê°ì¡ìì 보기 ì ì ëì¤í¬ë¦½í°ì ë°ì´í°ê° ì°ìì ê²ì ë³´ì¥í©ëë¤. ì°¸ê³ ë¡, writel() ì ì¬ì©íë©´ ìºì ì¼ê´ì±ì´ ìë ë©ëª¨ë¦¬ (cache coherent memory) ì°ê¸°ê° MMIO ìììì ì°ê¸° ì ì ìë£ëìì ê²ì ë³´ì¥íë¯ë¡ writel() ìì wmb() 를 ì¤íí íìê° ììì ììëì기 ë°ëëë¤. writel() ë³´ë¤ ë¹ì©ì´ ì ë ´í writel_relaxed() ë ì´ë° ë³´ì¥ì ì ê³µíì§ ìì¼ë¯ë¡ ì¬ê¸°ì ì¬ì©ëì§ ììì¼ í©ëë¤. writel_relaxed() ì ê°ì ìíë I/O ì ê·¼ìë¤ì ëí ìì¸í ë´ì©ì ìí´ìë "커ë I/O 배리ì´ì í¨ê³¼" ì¹ì ì, consistent memory ì ëí ìì¸í ë´ì©ì ìí´ì Documentation/core-api/dma-api.rst 문ì를 ì°¸ê³ íì¸ì. (*) pmem_wmb(); ì´ê²ì persistent memory 를 ìí ê²ì¼ë¡, persistent ì ì¥ìì ê°í´ì§ ë³ê²½ ì¬íì´ íë«í¼ ì°ìì± ëë©ì¸ì ëë¬íì ê²ì ë³´ì¥í기 ìí ê²ì ëë¤. ì를 ë¤ì´, ììì ì´ì§ ìì pmem ììì¼ë¡ì ì°ê¸° í, ì°ë¦¬ë ì°ê¸°ê° íë«í¼ ì°ìì± ëë©ì¸ì ëë¬íì ê²ì ë³´ì¥í기 ìí´ pmem_wmb() 를 ì¬ì©í©ëë¤. ì´ë ì°ê¸°ê° ë¤ë°ë¥´ë instruction ë¤ì´ ì ë°íë ì´ë í ë°ì´í° ì¡ì¸ì¤ë ë°ì´í° ì ì¡ì ìì ì ì persistent ì ì¥ì를 ì ë°ì´í¸ íì ê²ì ë³´ì¥í©ëë¤. ì´ë wmb() ì ìí´ ì´ë¤ì§ë ìì ê·ì¹ì í¬í¨í©ëë¤. Persistent memory ììì ë¡ë를 ìí´ì íì¬ì ì½ê¸° ë©ëª¨ë¦¬ 배리ì´ë¡ë ì½ê¸° ìì를 ë³´ì¥íëë° ì¶©ë¶í©ëë¤. ========================= ì묵ì 커ë ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ========================= 리ë ì¤ ì»¤ëì ì¼ë¶ í¨ìë¤ì ë©ëª¨ë¦¬ 배리ì´ë¥¼ ë´ì¥íê³ ìëë°, ë½(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 (Sleeper) CPU 2 (Waker) =============================== =============================== set_current_state(); STORE event_indicated smp_store_mb(); wake_up(); STORE current->state ... <ë²ì© 배리ì´> <ë²ì© 배리ì´> LOAD event_indicated if ((LOAD task->state) & TASK_NORMAL) STORE task->state ì¬ê¸°ì "task" ë 깨ì´ëì§ë ì°ë ëì´ê³ CPU 1 ì "current" ì ê°ìµëë¤. ë°ë³µíì§ë§, wake_up() ì´ ë¬´ì¸ê°ë¥¼ ì ë§ ê¹¨ì´ë¤ë©´ ë²ì© ë©ëª¨ë¦¬ 배리ì´ê° ìíë ê²ì´ ë³´ì¥ëì§ë§, ê·¸ë ì§ ìë¤ë©´ ê·¸ë° ë³´ì¥ì´ ììµëë¤. ì´ê±¸ ì´í´í기 ìí´, X ì Y ë 모ë 0 ì¼ë¡ ì´ê¸°í ëì´ ìë¤ë ê°ì íì ìëì ì´ë²¤í¸ ìíì¤ë¥¼ ìê°í´ ë´ ìë¤: CPU 1 CPU 2 =============================== =============================== X = 1; Y = 1; smp_mb(); wake_up(); LOAD Y LOAD X ì ë§ë¡ 깨ì°ê¸°ê° íí´ì¡ë¤ë©´, ë ë¡ë ì¤ (ìµìí) íëë 1 ì ë³´ê² ë©ëë¤. ë°ë©´ì, ì¤ì 깨ì°ê¸°ê° íí´ì§ì§ ììë¤ë©´, ë ë¡ë 모ë 0ì ë³¼ ìë ììµëë¤. wake_up_process() ë íì ë²ì© ë©ëª¨ë¦¬ 배리ì´ë¥¼ ìíí©ëë¤. ì´ ë°°ë¦¬ì´ ìì íì¤í¬ ìíê° ì ê·¼ë기 ì ì ìíë©ëë¤. í¹í, ìì ìì ì½ëìì wake_up() ì´ wake_up_process() ë¡ ëì²´ëë¤ë©´ ë ë¡ë ì¤ íëë 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(); ë©ëª¨ë¦¬ ììê·ì¹ ê´ì ìì, ì´ í¨ìë¤ì 모ë wake_up() ê³¼ ê°ê±°ë ë³´ë¤ ê°í ìì ë³´ì¥ì ì ê³µí©ëë¤. [!] ì ì¬ì°ë ì½ëì 깨ì°ë ì½ëì ë´í¬ëë ë©ëª¨ë¦¬ 배리ì´ë¤ì 깨ì°ê¸° ì ì ì´ë£¨ì´ì§ ì¤í ì´ë¥¼ ì ì¬ì°ë ì½ëê° 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 ========================= ë©ëª¨ë¦¬ 배리ì´ê° íìí ê³³ ========================= ì¤ë ¹ 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() ê³¼ ê°ì - ì ì í ì¡ì¸ì¤ 루í´ì íµí´ ì´ë£¨ì´ì ¸ì¼ë§ í©ëë¤. ì´ê²ë¤ì ëë¶ë¶ì ê²½ì°ìë ëª ìì ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ì í¨ê» ì¬ì©ë íìê° ììµëë¤ë§, ìíë ë©ëª¨ë¦¬ ì¡ì¸ì¤ ìì±ì¼ë¡ 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 ë ì§ì¤í°ë¡ì ë¡ë ì¤í¼ë ì´ì ì í¬í¨í기 ë문ì ì¼ë°ì ì¼ë¡ë 문ì ê° ëì§ ììµëë¤. íëì ì¸í°ë½í¸ 루í´ê³¼ ë³ëì CPU ìì ìíì¤ì´ë©° ìë¡ íµì ì íë ë ë£¨í´ ì¬ì´ìë ë¹ì·í ìí©ì´ ì¼ì´ë ì ììµëë¤. ë§ì½ ê·¸ë° ê²½ì°ê° ë°ìí ê°ë¥ì±ì´ ìë¤ë©´, ìì를 ë³´ì¥í기 ìí´ ì¸í°ë½í¸ ë¹íì±í ë½ì´ ì¬ì©ëì´ì ¸ì¼ë§ í©ëë¤. ====================== 커ë I/O 배리ì´ì í¨ê³¼ ====================== I/O ì¡ì¸ì¤ë¥¼ íµí 주ë³ì¥ì¹ìì íµì ì ìí¤í ì³ì 기기ì ë§¤ì° ì¢ ìì ì ëë¤. ë°ë¼ì, 본ì§ì ì¼ë¡ ì´ìì±ì´ ìë ëë¼ì´ë²ë ê°ë¥í ê°ì¥ ì ì ì¤ë²í¤ëë¡ ë기í를 í기 ìí´ ê°ìì íê² ìì¤í ì í¹ì ëìì ìì¡´í ê²ëë¤. ë¤ìí ìí¤í ì³ì ë²ì¤ 구íì ì´ìì±ì ê°ì§ë ¤ íë ëë¼ì´ë²ë¥¼ ìí´, 커ëì ë¤ìí ì ëì ìì ë³´ì¥ì ì ê³µíë ì¼ë ¨ì ì¡ì¸ì¤ í¨ì를 ì ê³µí©ëë¤. (*) readX(), writeX(): readX() ì writeX() MMIO ì¡ì¸ì¤ í¨ìë ì ê·¼ëë 주ë³ì¥ì¹ë¡ì í¬ì¸í°ë¥¼ __iomem * í¨ë¬ë¯¸í°ë¡ ë°ìµëë¤. ëí´í¸ I/O 기ë¥ì¼ë¡ 매íëë í¬ì¸í° (ì: ioremap() ì¼ë¡ ë°íëë ê²) ì ìì ë³´ì¥ì ë¤ìê³¼ ê°ìµëë¤: 1. ê°ì 주ë³ì¥ì¹ë¡ì 모ë readX() ì writeX() ì¡ì¸ì¤ë ê°ìì ëí´ ììì§ì´ì§ëë¤. ì´ë ê°ì CPU ì°ë ëì ìí í¹ì ëë°ì´ì¤ë¡ì MMIO ë ì§ì¤í° ì¡ì¸ì¤ê° íë¡ê·¸ë¨ ììëë¡ ëì°©í ê²ì ë³´ì¥í©ëë¤. 2. í ì¤íë½ì ì¡ì CPU ì°ë ëì ìí writeX() ë ê°ì ì¤íë½ì ëì¤ì ì¡ì ë¤ë¥¸ CPU ì°ë ëì ìí´ ê°ì 주ë³ì¥ì¹ë¥¼ í¥í´ í¸ì¶ë writeX() ìì¼ë¡ ììì§ì´ì§ëë¤. ì´ë ì¤íë½ì ì¡ì ì± í¹ì ëë°ì´ì¤ë¥¼ í¥í´ í¸ì¶ë MMIO ë ì§ì¤í° ì°ê¸°ë í´ë¹ ë½ì íëì ì¼ê´ì ì¸ ììë¡ ëë¬í ê²ì ë³´ì¥í©ëë¤. 3. í¹ì 주ë³ì¥ì¹ë¥¼ í¥í í¹ì CPU ì°ë ëì writeX() ë 먼ì í´ë¹ ì°ë ëë¡ ì íëë, ëë í´ë¹ ì°ë ëì ìí´ ìì²ë 모ë ìì ë©ëª¨ë¦¬ ì°ê¸°ê° ìë£ë기 ì ê¹ì§ 먼ì 기ë¤ë¦½ëë¤. ì´ë dma_alloc_coherent() 를 íµí´ í ë¹ë ì ì¡ì© DMA ë²í¼ë¡ì í´ë¹ CPU ì ì°ê¸°ê° ì´ CPU ê° ì´ ì ì¡ì ìììí¤ê¸° ìí´ MMIO 컨í¸ë¡¤ ë ì§ì¤í°ì ì°ê¸°ë¥¼ í ë DMA ìì§ì ë³´ì¬ì§ ê²ì ë³´ì¥í©ëë¤. 4. í¹ì CPU ì°ë ëì ìí 주ë³ì¥ì¹ë¡ì readX() ë ê°ì ì°ë ëì ìí 모ë ë¤ë°ë¥´ë ë©ëª¨ë¦¬ ì½ê¸°ê° ììë기 ì ì ìë£ë©ëë¤. ì´ë dma_alloc_coherent() 를 íµí´ í ë¹ë ìì ì© DMA ë²í¼ë¡ë¶í°ì CPU ì ì½ê¸°ë ì´ DMA ìì ì ìë£ë¥¼ íìíë DMA ìì§ì MMIO ìí ë ì§ì¤í° ì½ê¸° íìë ì¤ì¼ë ë°ì´í°ë¥¼ ì½ì§ ìì ê²ì ë³´ì¥í©ëë¤. 5. CPU ì ìí 주ë³ì¥ì¹ë¡ì readX() ë 모ë ë¤ë°ë¥´ë delay() 루íê° ìíì ììí기 ì ì ìë£ë©ëë¤. ì´ë CPU ì í¹ì 주ë³ì¥ì¹ë¡ì ëê°ì MMIO ë ì§ì¤í° ì°ê¸°ê° íí´ì§ëë° ì²«ë²ì§¸ ì°ê¸°ê° readX() 를 íµí´ 곧ë°ë¡ ì½ì´ì¡ê³ ì´ì´ ëë²ì§¸ writeX() ì ì udelay(1) ì´ í¸ì¶ëìë¤ë©´ ì´ ëê°ì ì°ê¸°ë ìµì 1us ì ê°ê²©ì ëê³ íí´ì§ ê²ì ë³´ì¥í©ëë¤: writel(42, DEVICE_REGISTER_0); // ëë°ì´ì¤ì ëì°©í¨... readl(DEVICE_REGISTER_0); udelay(1); writel(42, DEVICE_REGISTER_1); // ...ì´ê²ë³´ë¤ ìµì 1us ì ì. ëí´í¸ê° ìë 기ë¥ì íµí´ ì»ì´ì§ë __iomem í¬ì¸í° (ì: ioremap_wc() 를 íµí´ 리í´ëë ê²) ì ìì ìì±ì ì¤ì ìí¤í ì³ì ìì¡´ì ì´ì´ì ì´ë° ì¢ ë¥ì 매íì¼ë¡ì ì¡ì¸ì¤ë ìì ì¤ëª ë ë³´ì¥ì¬íì ìì¡´í ì ììµëë¤. (*) readX_relaxed(), writeX_relaxed() ì´ê²ë¤ì readX() ì writeX() ë ë¹ì·íì§ë§, ë ìíë ë©ëª¨ë¦¬ ìì ë³´ì¥ì ì ê³µí©ëë¤. 구체ì ì¼ë¡, ì´ê²ë¤ì ì¼ë°ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ë delay() 루í (ì:ìì 2-5 í목) ì ëí´ ìì를 ë³´ì¥íì§ ììµëë¤ë§ ëí´í¸ I/O 기ë¥ì¼ë¡ 매íë __iomem í¬ì¸í°ì ëí´ ëìí ë, ê°ì CPU ì°ë ëì ìí ê°ì 주ë³ì¥ì¹ë¡ì ì¡ì¸ì¤ìë ììê° ë§ì¶°ì§ ê²ì´ ë³´ì¥ë©ëë¤. (*) readsX(), writesX(): readsX() ì writesX() MMIO ì¡ì¸ì¤ í¨ìë DMA 를 ìííëë° ì ì ì¹ ìì, 주ë³ì¥ì¹ ë´ì ë©ëª¨ë¦¬ 매íë ë ì§ì¤í° ê¸°ë° FIFO ë¡ì ì¡ì¸ì¤ë¥¼ ìí´ ì¤ê³ëììµëë¤. ë°ë¼ì, ì´ ê¸°ë¥ë¤ì ìì ì¤ëª ë readX_relaxed() ì writeX_relaxed() ì ìì ë³´ì¥ë§ì ì ê³µí©ëë¤. (*) inX(), outX(): inX() ì outX() ì¡ì¸ì¤ í¨ìë ì¼ë¶ ìí¤í ì³ (í¹í x86) ììë í¹ìí ëª ë ¹ì´ë¥¼ íìë¡ íë©° í¬í¸ì 매íëë, 과거ì ì ì°ì¸ I/O 주ë³ì¥ì¹ë¡ì ì ê·¼ì ìí´ ë§ë¤ì´ì¡ìµëë¤. ë§ì CPU ìí¤í ì³ê° ê²°êµì ì´ë° 주ë³ì¥ì¹ë¥¼ ë´ë¶ì ê°ì ë©ëª¨ë¦¬ 매íì íµí´ ì ê·¼í기 ë문ì, inX() ì outX() ê° ì ê³µíë ì´ìì± ìë ìì ë³´ì¥ì ëí´í¸ I/O 기ë¥ì íµí 매íì ì ê·¼í ëì readX() ì writeX() ì ìí´ ì ê³µëë ê²ê³¼ ê°ê° ëì¼í©ëë¤. ëë°ì´ì¤ ëë¼ì´ë²ë outX() ê° ë¦¬í´í기 ì ì í´ë¹ I/O 주ë³ì¥ì¹ë¡ë¶í°ì ìë£ ìëµì 기ë¤ë¦¬ë ì°ê¸° í¸ëìì ì ë§ë¤ì´ ë¸ë¤ê³ 기ëí ìë ììµëë¤. ì´ë 모ë ìí¤í ì³ìì ë³´ì¥ëì§ë ìê³ , ë°ë¼ì ì´ìì± ìë ìì ê·ì¹ì ì¼ë¶ë¶ì´ ìëëë¤. (*) insX(), outsX(): ìììì ê°ì´, insX() ì outsX() ì¡ì¸ì¤ í¨ìë ëí´í¸ I/O 기ë¥ì íµí 매íì ì ê·¼í ë ê°ê° readX() ì writeX() ì ê°ì ìì ë³´ì¥ì ì ê³µí©ëë¤. (*) ioreadX(), iowriteX() ì´ê²ë¤ì inX()/outX() ë readX()/writeX() ì²ë¼ ì¤ì ë¡ ìííë ì¡ì¸ì¤ì ì¢ ë¥ì ë°ë¼ ì ì íê² ìíë ê²ì ëë¤. String ì¡ì¸ì¤ í¨ì (insX(), outsX(), readsX() ê·¸ë¦¬ê³ writesX()) ì ìì¸ë¥¼ ì ì¸íê³ ë, ìì 모ë ê²ì´ ìë«ë¨ì 주ë³ì¥ì¹ê° little-endian ì´ë¼ ê°ì íë©°, ë°ë¼ì big-endian ìí¤í ì³ììë byte-swapping ì¤í¼ë ì´ì ì ìíí©ëë¤. =================================== ê°ì ëë ê°ì¥ ìíë ì¤í ìì ëª¨ë¸ =================================== 컨ì ì ì¼ë¡ 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 ê° ê°ì§ê³ ìì ì ìë í¹ìí ëë°ì´ì¤ íµì ì¸ì¤í¸ëì ì ì¬ì©ì ìí´ì ê²°ì ë ìë ììµëë¤. ìºì ì¼ê´ì± 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 ë¶í°ë Alpha ì© READ_ONCE() ì½ë ë´ì smp_mb() ê° ì¶ê°ëì´ì ë©ëª¨ë¦¬ 모ë¸ë¡ì 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