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> ======== ë©´ì± ì¡°í ======== ì´ ë¬¸ìë ëª ì¸ìê° ìëëë¤; ì´ ë¬¸ìë ìë²½íì§ ììë°, ê°ê²°ì±ì ìí´ ìëë ë¶ë¶ë ìê³ , ìëíì§ ììì§ë§ ì¬ëì ìí´ ì°ìë¤ë³´ë ë¶ìì í ë¶ë¶ë ììµëë¤. ì´ ë¬¸ìë 리ë ì¤ìì ì ê³µíë ë¤ìí ë©ëª¨ë¦¬ 배리ì´ë¤ì ì¬ì©í기 ìí ìë´ìì ëë¤ë§, ëê° ì´ìíë¤ ì¶ì¼ë©´ (ê·¸ë°ê² ë§ì ê²ëë¤) ì§ë¬¸ì ë¶íë립ëë¤. ë¤ì ë§íì§ë§, ì´ ë¬¸ìë 리ë ì¤ê° íëì¨ì´ì 기ëíë ì¬íì ëí ëª ì¸ìê° ìëëë¤. ì´ ë¬¸ìì 목ì ì ëê°ì§ì ëë¤: (1) ì´ë¤ í¹ì 배리ì´ì ëí´ ê¸°ëí ì ìë ìµìíì 기ë¥ì ëª ì¸í기 ìí´ì, ê·¸ë¦¬ê³ (2) ì¬ì© ê°ë¥í 배리ì´ë¤ì ëí´ ì´ë»ê² ì¬ì©í´ì¼ íëì§ì ëí ìë´ë¥¼ ì ê³µí기 ìí´ì. ì´ë¤ ìí¤í ì³ë í¹ì í 배리ì´ë¤ì ëí´ìë ì¬ê¸°ì ì´ì¼ê¸°íë ìµìíì ì구ì¬íë¤ë³´ë¤ ë§ì 기ë¥ì ì ê³µí ìë ììµëë¤ë§, ì¬ê¸°ì ì´ì¼ê¸°íë ì구ì¬íë¤ì 충족íì§ ìë ìí¤í ì³ê° ìë¤ë©´ ê·¸ ìí¤í ì³ê° ì못ë ê²ì´ë ì ì ììëì기 ë°ëëë¤. ëí, í¹ì ìí¤í ì³ìì ì¼ë¶ 배리ì´ë í´ë¹ ìí¤í ì³ì í¹ìí ëì ë°©ìì¼ë¡ ì¸í´ í´ë¹ 배리ì´ì ëª ìì ì¬ì©ì´ ë¶íìí´ì no-op ì´ ë ìë ììì ììëì기 ë°ëëë¤. ìì: 본 ë²ì ìì ìë²½íì§ ììë°, ì´ ìì ë¶ë¶ì ì¼ë¡ë ìëë ê²ì´ê¸°ë í©ëë¤. ì¬í 기ì 문ìë¤ì´ ê·¸ë ë¯ ìë²½í ì´í´ë¥¼ ìí´ìë ë²ì문과 ì문ì í¨ê» ì½ì¼ìë ë²ì문ì íëì ê°ì´ëë¡ íì©íì길 ì¶ì²ë리며, ë°ê²¬ëë ì¤ì ë±ì ëí´ìë ì¸ì ë ì견ì ë¶íë립ëë¤. ê³¼í ë²ìì¼ë¡ ì¸í ì¤í´ë¥¼ ìµìíí기 ìí´ ì 매í ë¶ë¶ì´ ìì ê²½ì°ìë ì´ìí¨ì´ ìëë¼ë ìëì ì©ì´ë¥¼ ì°¨ì©í©ëë¤. ===== 목차: ===== (*) ì¶ì ë©ëª¨ë¦¬ ì¡ì¸ì¤ 모ë¸. - ëë°ì´ì¤ ì¤í¼ë ì´ì . - ë³´ì¥ì¬í. (*) ë©ëª¨ë¦¬ 배리ì´ë 무ìì¸ê°? - ë©ëª¨ë¦¬ 배리ì´ì ì¢ ë¥. - ë©ëª¨ë¦¬ 배리ì´ì ëí´ ê°ì í´ì ìë ê². - ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´. - 컨í¸ë¡¤ ìì¡´ì±. - SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸°. - ë©ëª¨ë¦¬ ë°°ë¦¬ì´ ìíì¤ì ì. - ì½ê¸° ë©ëª¨ë¦¬ ë°°ë¦¬ì´ vs ë¡ë ì측. - ì´íì± (*) ëª ìì 커ë 배리ì´. - ì»´íì¼ë¬ 배리ì´. - 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); smp_read_barrier_depends(); D = READ_ONCE(*Q); CPU ë ë¤ìê³¼ ê°ì ë©ëª¨ë¦¬ ì¤í¼ë ì´ì ìíì¤ë¥¼ ìí ìì²í©ëë¤: Q = LOAD P, D = LOAD *Q ê·¸ë¦¬ê³ ê·¸ ìíì¤ ë´ììì ììë íì ì§ì¼ì§ëë¤. ëë¶ë¶ì ìì¤í ìì smp_read_barrier_depends() ë ì무ì¼ë ìíì§ë§ DEC Alpha ììë ëª ìì ì¼ë¡ ì¬ì©ëì´ì¼ í©ëë¤. ë³´íµì ê²½ì°ìë smp_read_barrier_depends() 를 ì§ì ì¬ì©íë ëì rcu_dereference() ê°ì ê²ë¤ì ì¬ì©í´ì¼ í¨ì ììëì¸ì. (*) í¹ì 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 ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ -------------------- ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ì ì¬ì©ì ìì´ ì§ì¼ì¼ íë ì¬íë¤ì ì½ê° 미ë¬íê³ , ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ê° ì¬ì©ëì´ì¼ íë ìí©ë íì ëª ë°±íì§ë ììµëë¤. ì¤ëª ì ìí´ ë¤ìì ì´ë²¤í¸ ìíì¤ë¥¼ ìê°í´ ë´ ìë¤: 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ì ìì°ì ì¸ ìì ë³´ì¥ì´ ê·¸ë° ê¸°ë¡ë¤ì ì¬ë¼ì§ì§ ìê² í´ì¤ëë¤. ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ë§¤ì° ì¤ìíë°, ì를 ë¤ì´ 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 문ì ë¤ë°ë¥´ë ì½ëìë ì ì©ëì§ ììµëë¤. ë§ì§ë§ì¼ë¡, 컨í¸ë¡¤ ìì¡´ì±ì ì´íì± (transitivity) ì ì ê³µíì§ -ììµëë¤-. ì´ê±´ 'x' ì 'y' ê° ë ë¤ 0 ì´ë¼ë ì´ê¸°ê°ì ê°ì¡ë¤ë ê°ì íì ëê°ì ìì ë¡ ë³´ì´ê² ìµëë¤: CPU 0 CPU 1 ======================= ======================= r1 = READ_ONCE(x); r2 = READ_ONCE(y); if (r1 > 0) if (r2 > 0) WRITE_ONCE(y, 1); WRITE_ONCE(x, 1); assert(!(r1 == 1 && r2 == 1)); ì´ ë CPU ìì ìì assert() ì ì¡°ê±´ì íì ì°¸ì¼ ê²ì ëë¤. ê·¸ë¦¬ê³ , ë§ì½ 컨í¸ë¡¤ ìì¡´ì±ì´ ì´íì±ì (ì¤ì ë¡ë ê·¸ë¬ì§ ìì§ë§) ë³´ì¥íë¤ë©´, ë¤ìì CPU ê° ì¶ê°ëì´ë ìëì assert() ì¡°ê±´ì ì°¸ì´ ë ê²ì ëë¤: CPU 2 ===================== WRITE_ONCE(x, 2); assert(!(r1 == 2 && r2 == 1 && x == 2)); /* FAILS!!! */ íì§ë§ 컨í¸ë¡¤ ìì¡´ì±ì ì´íì±ì ì ê³µíì§ -ì기- ë문ì, ì¸ê°ì CPU ìì ê° ì¤í ìë£ë íì ìì assert() ì ì¡°ê±´ì ê±°ì§ì¼ë¡ íê°ë ì ììµëë¤. ì¸ê°ì CPU ìì ê° ìì를 ì§í¤ê¸¸ ìíë¤ë©´, CPU 0 ì CPU 1 ì½ëì ë¡ëì ì¤í ì´ ì¬ì´, "if" 문 ë°ë¡ ë¤ìì smp_mb()를 ë£ì´ì¼ í©ëë¤. ë ëìê°ì, ìµì´ì ë CPU ìì ë ë§¤ì° ìííë¯ë¡ ì¬ì©ëì§ ììì¼ í©ëë¤. ì´ ëê°ì ìì ë ë¤ì ë ¼ë¬¸: http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf ì ì´ ì¬ì´í¸: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html ì ëì¨ LB ì WWC 리í¸ë¨¸ì¤ í ì¤í¸ì ëë¤. ìì½íìë©´: (*) 컨í¸ë¡¤ ìì¡´ì±ì ìì ë¡ëë¤ì ë¤ì ì¤í ì´ë¤ì ëí´ ìì를 ë§ì¶°ì¤ëë¤. íì§ë§, ê·¸ ì¸ì ì´ë¤ ììë ë³´ì¥íì§ -ììµëë¤-: ìì ë¡ëì ë¤ì ë¡ëë¤ ì¬ì´ìë, ìì ì¤í ì´ì ë¤ì ì¤í ì´ë¤ ì¬ì´ìëì. ì´ë° ë¤ë¥¸ ííì ììê° íìíë¤ë©´ 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 문ì ë¤ë°ë¥´ë ì½ëìë ì ì©ëì§ -ììµëë¤-. (*) 컨í¸ë¡¤ ìì¡´ì±ì ë³´íµ ë¤ë¥¸ íì ì 배리ì´ë¤ê³¼ ì§ì ë§ì¶° ì¬ì©ë©ëë¤. (*) 컨í¸ë¡¤ ìì¡´ì±ì ì´íì±ì ì ê³µíì§ -ììµëë¤-. ì´íì±ì´ íìíë¤ë©´, smp_mb() 를 ì¬ì©íì¸ì. (*) ì»´íì¼ë¬ë 컨í¸ë¡¤ ìì¡´ì±ì ì´í´íê³ ìì§ ììµëë¤. ë°ë¼ì ì»´íì¼ë¬ê° ì¬ë¬ë¶ì ì½ë를 ë§ê°ë¨ë¦¬ì§ ìëë¡ íëê±´ ì¬ë¬ë¶ì´ í´ì¼ íë ì¼ì ëë¤. SMP ë°°ë¦¬ì´ ì§ë§ì¶ê¸° -------------------- CPU ê° ìí¸ìì©ì ë¤ë£° ëì ì¼ë¶ íì ì ë©ëª¨ë¦¬ 배리ì´ë íì ì§ì ë§ì¶° ì¬ì©ëì´ì¼ í©ëë¤. ì ì íê² ì§ì ë§ì¶ì§ ìì ì½ëë ì¬ì¤ì ìë¬ì ê°ê¹ìµëë¤. ë²ì© 배리ì´ë¤ì ë²ì© 배리ì´ë¼ë¦¬ë ì§ì ë§ì¶ì§ë§ ì´íì±ì´ ìë ëë¶ë¶ì ë¤ë¥¸ íì ì 배리ì´ë¤ê³¼ë ì§ì ë§ì¶¥ëë¤. 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(y, 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 |------>| | ì ë°ì´í¸ë ê°ì´ ë¤ì ì½íì§ë¤ +-------+ | | : : +-------+ ì´íì± ------ ì´íì±(transitivity)ì ì¤ì ì ì»´í¨í° ìì¤í ìì íì ì ê³µëì§ë ìë, ìì ë§ì¶ê¸°ì ëí ìë¹í ì§ê´ì ì¸ ê°ë ì ëë¤. ë¤ìì ìê° ì´íì±ì ë³´ì¬ì¤ëë¤: CPU 1 CPU 2 CPU 3 ======================= ======================= ======================= { X = 0, Y = 0 } STORE X=1 LOAD X STORE Y=1 <ë²ì© 배리ì´> <ë²ì© 배리ì´> LOAD Y LOAD X CPU 2 ì X ë¡ëê° 1ì 리í´íê³ Y ë¡ëê° 0ì 리í´íë¤ê³ í´ë´ ìë¤. ì´ë CPU 2 ì X ë¡ëê° CPU 1 ì X ì¤í ì´ ë¤ì ì´ë£¨ì´ì¡ê³ CPU 2 ì Y ë¡ëë CPU 3 ì Y ì¤í ì´ ì ì ì´ë£¨ì´ì¡ìì ì미í©ëë¤. ê·¸ë¼ "CPU 3 ì X ë¡ëë 0ì 리í´í ì ìëì?" CPU 2 ì X ë¡ëë CPU 1 ì ì¤í ì´ íì ì´ë£¨ì´ì¡ì¼ë, CPU 3 ì X ë¡ëë 1ì 리í´íëê² ìì°ì¤ë½ìµëë¤. ì´ë° ìê°ì´ ì´íì±ì í ìì ëë¤: CPU A ìì ì¤íë ë¡ëê° CPU B ììì ê°ì ë³ìì ëí ë¡ë를 ë¤ë°ë¥¸ë¤ë©´, CPU A ì ë¡ëë CPU B ì ë¡ëê° ë´ëì ê°ê³¼ ê°ê±°ë ê·¸ íì ê°ì ë´ëìì¼ í©ëë¤. 리ë ì¤ ì»¤ëìì ë²ì© 배리ì´ì ì¬ì©ì ì´íì±ì ë³´ì¥í©ëë¤. ë°ë¼ì, ìì ììì CPU 2 ì X ë¡ëê° 1ì, Y ë¡ëë 0ì 리í´íë¤ë©´, CPU 3 ì X ë¡ëë ë°ëì 1ì 리í´í©ëë¤. íì§ë§, ì½ê¸°ë ì°ê¸° 배리ì´ì ëí´ìë ì´íì±ì´ ë³´ì¥ëì§ -ììµëë¤-. ì를 ë¤ì´, ìì ììì CPU 2 ì ë²ì© 배리ì´ê° ìëì²ë¼ ì½ê¸° 배리ì´ë¡ ë°ë ê²½ì°ë¥¼ ìê°í´ ë´ ìë¤: CPU 1 CPU 2 CPU 3 ======================= ======================= ======================= { X = 0, Y = 0 } STORE X=1 LOAD X STORE Y=1 <ì½ê¸° 배리ì´> <ë²ì© 배리ì´> LOAD Y LOAD X ì´ ì½ëë ì´íì±ì ê°ì§ ììµëë¤: ì´ ìììë, CPU 2 ì X ë¡ëê° 1ì 리í´íê³ , Y ë¡ëë 0ì 리í´íì§ë§ CPU 3 ì X ë¡ëê° 0ì 리í´íë ê²ë ìì í í©ë²ì ì ëë¤. CPU 2 ì ì½ê¸° 배리ì´ê° ìì ì ì½ê¸°ë ìì를 ë§ì¶°ì¤ë, CPU 1 ì ì¤í ì´ìì ìì를 ë§ì¶°ì¤ë¤ê³ ë ë³´ì¥í ì ìë¤ëê² íµì¬ì ëë¤. ë°ë¼ì, CPU 1 ê³¼ CPU 2 ê° ë²í¼ë ìºì를 ê³µì íë ìì¤í ìì ì´ ìì ì½ëê° ì¤íëë¤ë©´, CPU 2 ë CPU 1 ì´ ì´ ê°ì ì¢ ë¹¨ë¦¬ ì ê·¼í ì ìì ê²ì ëë¤. ë°ë¼ì CPU 1 ê³¼ CPU 2 ì ì ê·¼ì¼ë¡ ì¡°í©ë ìì를 모ë CPU ê° ëìí ì ìëë¡ í기 ìí´ ë²ì© 배리ì´ê° íìí©ëë¤. ë²ì© 배리ì´ë "ê¸ë¡ë² ì´íì±"ì ì ê³µí´ì, 모ë 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_barrier_depends() smp_read_barrier_depends() ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë¥¼ ì ì¸í 모ë ë©ëª¨ë¦¬ 배리ì´ë ì»´íì¼ë¬ 배리ì´ë¥¼ í¬í¨í©ëë¤. ë°ì´í° ìì¡´ì±ì ì»´íì¼ë¬ìì ì¶ê°ì ì¸ ìì ë³´ì¥ì í¬í¨íì§ ììµëë¤. ë°©ë°±: ë°ì´í° ìì¡´ì±ì´ ìë ê²½ì°, ì»´íì¼ë¬ë í´ë¹ ë¡ë를 ì¬ë°ë¥¸ ììë¡ ì¼ì¼í¬ ê²ì¼ë¡ (ì: `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 문ì를 ì°¸ê³ íì¸ì. (*) lockless_dereference(); ì´ í¨ìë smp_read_barrier_depends() ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë¥¼ ì¬ì©íë í¬ì¸í° ì½ì´ì¤ê¸° ëí¼(wrapper) í¨ìë¡ ìê°ë ì ììµëë¤. ê°ì²´ì ë¼ì´ííìì´ RCU ì¸ì ë©ì»¤ëì¦ì¼ë¡ ê´ë¦¬ëë¤ë ì ì ì ì¸íë©´ rcu_dereference() ìë ì ì¬íë°, ì를 ë¤ë©´ ê°ì²´ê° ìì¤í ì´ êº¼ì§ ëìë§ ì ê±°ëë ê²½ì° ë±ì ëë¤. ëí, lockless_dereference() ì RCU ì í¨ê» ì¬ì©ë ìë, RCU ìì´ ì¬ì©ë ìë ìë ì¼ë¶ ë°ì´í° 구조ì ì¬ì©ëê³ ììµëë¤. (*) 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 ìì ë§ë¤ì´ì§ ììì ëì¼í ê²ì´ë¼ë ë³´ì¥ì´ ììµëë¤. ì¬ê¸°ì ê°ì í기 ìí´ì , ë°ì´í° ìì¡´ì± ë°°ë¦¬ì´ë ì½ê¸° 배리ì´ë¥¼ ë¡ë ì¤í¼ë ì´ì ë¤ ì¬ì´ì ë£ì´ì¼ í©ëë¤. ì´ë ê² í¨ì¼ë¡ì¨ ìºìê° ë¤ì ìì²ì ì²ë¦¬í기 ì ì ì¼ê´ì± í를 ì²ë¦¬íëë¡ ê°ì íê² ë©ëë¤. 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) ì ì íí¨ì¼ë¡ì¨ ë©ëª¨ë¦¬ 배리ì´ê° ëª ìì ì¼ë¡ ì¬ì©ëì§ ììì ëìë ê·¸ë° ì¡°ì ì´ íìíì§ ìê² íìµëë¤. ìºì ì¼ê´ì± VS DMA ------------------ 모ë ìì¤í ì´ DMA 를 íë ëë°ì´ì¤ì ëí´ìê¹ì§ ìºì ì¼ê´ì±ì ì ì§íì§ë ììµëë¤. ê·¸ë° ê²½ì°, DMA 를 ìëíë ëë°ì´ì¤ë RAM ì¼ë¡ë¶í° ì못ë ë°ì´í°ë¥¼ ì½ì ì ìëë°, ëí° ìºì ë¼ì¸ì´ CPU ì ìºìì ë¨¸ë¬´ë¥´ê³ ìê³ , ë°ë ê°ì´ ìì§ RAM ì ì¨ì§ì§ ììì ì ì기 ë문ì ëë¤. ì´ ë¬¸ì 를 í´ê²°í기 ìí´ì , 커ëì ì ì í ë¶ë¶ìì ê° CPU ìºìì 문ì ëë ë¹í¸ë¤ì íë¬ì (flush) ìì¼ì¼ë§ í©ëë¤ (ê·¸ë¦¬ê³ ê·¸ê²ë¤ì 무í¨í - invalidation - ìí¬ ìë ìê² ì£ ). ëí, ëë°ì´ì¤ì ìí´ RAM ì DMA ë¡ ì°ì¬ì§ ê°ì ëë°ì´ì¤ê° ì°ê¸°ë¥¼ ìë£í íì CPU ì ìºììì RAM ì¼ë¡ ì°ì¬ì§ë ëí° ìºì ë¼ì¸ì ìí´ ë®ì´ì¨ì§ ìë ìê³ , CPU ì ìºìì ì¡´ì¬íë ìºì ë¼ì¸ì´ í´ë¹ ìºììì ìì ëê³ ë¤ì ê°ì ì½ì´ë¤ì´ê¸° ì ê¹ì§ë RAM ì´ ì ë°ì´í¸ ëìë¤ë ì¬ì¤ ìì²´ê° ì¨ê²¨ì ¸ ë²ë¦´ ìë ììµëë¤. ì´ ë¬¸ì 를 í´ê²°í기 ìí´ì , 커ëì ì ì í ë¶ë¶ìì ê° CPU ì ìºì ìì 문ì ê° ëë ë¹í¸ë¤ì 무í¨í ìì¼ì¼ í©ëë¤. ìºì ê´ë¦¬ì ëí ë ë§ì ì 보를 ìí´ì Documentation/cachetlb.txt 를 ì°¸ê³ íì¸ì. ìºì ì¼ê´ì± 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 ì 기ì´í´ì ì ìëììµëë¤. ìì "ìºì ì¼ê´ì±" ìë¸ì¹ì ì ì°¸ê³ íì¸ì. ê°ì 머ì ê²ì¤í¸ ---------------- ê°ì 머ì ìì ëìíë ê²ì¤í¸ë¤ì ê²ì¤í¸ ìì²´ë 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/circular-buffers.txt ========= ì°¸ê³ ë¬¸í ========= 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 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 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