Re: [PATCH] Doc/memory-barriers: Add Korean translation
From: Byungchul Park
Date: Fri Jul 22 2016 - 00:37:44 EST
On Fri, Jul 22, 2016 at 01:01:45PM +0900, SeongJae Park wrote:
> 2016-07-22 12:53 GMT+09:00 Byungchul Park <byungchul.park@xxxxxxx>:
> > On Thu, Jul 21, 2016 at 10:26:47AM -0700, Paul E. McKenney wrote:
> >> On Fri, Jul 22, 2016 at 01:56:26AM +0900, SeongJae Park wrote:
> >> > This commit adds Korean version of memory-barriers.txt document. The
> >> > header is referred to HOWTO Korean version.
> >> >
> >> > The translation has started from Feb, 2016 and using a public git
> >> > repository[1] to maintain the work. It's commit history says that it is
> >> > following upstream changes as well.
> >> >
> >> > [1] https://github.com/sjp38/linux.doc_trans_membarrier
> >> >
> >> > Acked-by: David Howells <dhowells@xxxxxxxxxx>
> >> > Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
> >> > Acked-by: Minchan Kim <minchan@xxxxxxxxxx>
> >> > Signed-off-by: SeongJae Park <sj38.park@xxxxxxxxx>
> >>
> >> Queued with Jon's and Ingo's Acked-by, thank you all!
> >
> > Hello,
> >
> > It looks much better. Thank you for making it done.
> >
> > Do you mind me to get reviewed-by credit?
>
> I think he deserves it. His review was really helpful for quality improvement.
SeongJae and Paul, thank you.
>
>
> Thanks,
> SeongJae Park
>
> >
> >>
> >> Thanx, Paul
> >>
> >> > ---
> >> > Documentation/ko_KR/memory-barriers.txt | 3135 +++++++++++++++++++++++++++++++
> >> > 1 file changed, 3135 insertions(+)
> >> > create mode 100644 Documentation/ko_KR/memory-barriers.txt
> >> >
> >> > diff --git a/Documentation/ko_KR/memory-barriers.txt b/Documentation/ko_KR/memory-barriers.txt
> >> > new file mode 100644
> >> > index 0000000..9b28c0d
> >> > --- /dev/null
> >> > +++ b/Documentation/ko_KR/memory-barriers.txt
> >> > @@ -0,0 +1,3135 @@
> >> > +NOTE:
> >> > +This is a version of Documentation/memory-barriers.txt translated into Korean.
> >> > +This document is maintained by SeongJae Park <sj38.park@xxxxxxxxx>.
> >> > +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@xxxxxxxxx>
> >> > +===================================
> >> > +
> >> > +
> >> > + =========================
> >> > + ëëì ìë ëëë ëëì
> >> > + =========================
> >> > +
> >> > +ìì: David Howells <dhowells@xxxxxxxxxx>
> >> > + Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
> >> > + Will Deacon <will.deacon@xxxxxxx>
> >> > + Peter Zijlstra <peterz@xxxxxxxxxxxxx>
> >> > +
> >> > +========
> >> > +ëììí
> >> > +========
> >> > +
> >> > +ì ëìë ëììê ìëëë; ì ëìë ìëíì ììë, êêìì ìí ìëë
> >> > +ëëë ìê, ìëíì ìììë ìëì ìí ììëëë ëììí ëëë ììëë.
> >> > +ì ëìë ëëììì ìêíë ëìí ëëë ëëìëì ììíê ìí
> >> > +ìëììëëë, ëê ììíë ììë (êëê ëì êëë) ìëì ëíëëëë.
> >> > +
> >> > +ëì ëíìë, ì ëìë ëëìê íëììì êëíë ìíì ëí ëììê
> >> > +ìëëë.
> >> > +
> >> > +ì ëìì ëìì ëêììëë:
> >> > +
> >> > + (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_ops.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;
> >> > +
> >> > +ì ëêì ìì ìì ëêì êê ì íëëì ëìí ì ìê, ìëìì êêë
> >> > +ëìí ì ìëë íëë.
> >> > +
> >> > +ëìí ììì ëëìë ììì ìêì ëíìë ììë ìììëë:
> >> > +
> >> > + CPU 1 CPU 2
> >> > + =============== ===============
> >> > + { A == 1, B == 2, C = 3, P == &A, Q == &C }
> >> > + B = 4;
> >> > + <ìê ëëì>
> >> > + WRITE_ONCE(P, &B);
> >> > + Q = READ_ONCE(P);
> >> > + <ëìí ììì ëëì>
> >> > + *Q = 5;
> >> > +
> >> > +ì ëìí ììì ëëìë Q ëì ìêê *Q ëì ìíìì ììë ëìê
> >> > +íìëë. ìë ëìê êì êêë ëìëë:
> >> > +
> >> > + (Q == &B) && (B == 4)
> >> > +
> >> > +ìë ííì ëëê ììëìì íì ìì ëìê ëëëë. ëìëëë, ììì
> >> > +ìì êìì ìëë ìê ììì -ìë- íì êë ìí ëìíë ëì ìì ëìë
> >> > +ììëë êìëë. ì ííì ëëê ëìíë ìë ìê êìêëì êëíëë
> >> > +ììë ì ìê, ìëê ëëìë ììí ììë ìíê íìëì êë êëì
> >> > +ìëìë êì ëìëë.
> >> > +
> >> > +
> >> > +[!] ìëí ëìêìì ì ìíì ëëë ììë êì êê, ìë ëì í ìì
> >> > +ëíê ììë ìì ëìì ìëíê ëë ëíë íìë ìì ëìì ìëíë êê
> >> > +ëìì êì ì ëìíëë. íìí P ë íì ëíì ìì ëìì ìê, ëì B ë
> >> > +ìì ëí ìì ëìì ìëê ìêí ëìë. êë ìíìì ìê ììì íë CPU
> >> > +ì ììë ëíë í ìì ìì ëì ëììë íìë ëíë í ìì ìì ìë
> >> > +ìë íì ìê ììëë, íìí P ë ì ê (&B) ì, êëê ëì B ë ìë ê
> >> > +(2) ì êìê ìë ìíê ëìì ìë ììëë.
> >> > +
> >> > +
> >> > +ëìí ììì ëëìë ëì ììíë, ìë ëì 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, p);
> >> > + }
> >> > +
> >> > +ìíë ìììì ëí ëë íìì ëëìëê ìì ëì ììëëë. êëëê
> >> > +íë, READ_ONCE() ë ëëì ììíì íì ëë ëìíìì! READ_ONCE() ê
> >> > +ìëë, ìíìëê 'a' ëëíì ëëë 'a' ëëíì ëëë ëëì, 'b' ëì
> >> > +ìíìë 'b' ëì ëëë ìíìì ìíí ëë ëì ëìêìì êêë ìëí ì
> >> > +ììëë.
> >> > +
> >> > +ìêë ëì ìëê, ìíìëê ëì 'a' ì êì íì 0ì ìëëê ìëí ì
> >> > +ìëë, ìì ììì "if" ëì ììì ëìê êì ììí í ìë ììëë:
> >> > +
> >> > + q = a;
> >> > + b = p; /* BUG: Compiler and CPU can both reorder!!! */
> >> > +
> >> > +êëë READ_ONCE() ë ëëì ììíìì.
> >> > +
> >> > +ëìê êì "if" ëì ìêë ëëìì ëë ììíë ëìí ìíìì ëí ììë
> >> > +êìíê ìì êìê ìì ì ììëë:
> >> > +
> >> > + q = READ_ONCE(a);
> >> > + if (q) {
> >> > + barrier();
> >> > + WRITE_ONCE(b, p);
> >> > + do_something();
> >> > + } else {
> >> > + barrier();
> >> > + WRITE_ONCE(b, p);
> >> > + do_something_else();
> >> > + }
> >> > +
> >> > +ìíêêë, íìì ìíìëëì ëì ììí ëëììë ìê ëìê êì
> >> > +ëêëëëë:
> >> > +
> >> > + q = READ_ONCE(a);
> >> > + barrier();
> >> > + WRITE_ONCE(b, p); /* BUG: No ordering vs. load from a!!! */
> >> > + if (q) {
> >> > + /* WRITE_ONCE(b, p); -- moved up, BUG!!! */
> >> > + do_something();
> >> > + } else {
> >> > + /* WRITE_ONCE(b, p); -- moved up, BUG!!! */
> >> > + do_something_else();
> >> > + }
> >> > +
> >> > +ìì 'a' ììì ëëì 'b' ëì ìíì ìììë ìêì êêê ìê ëëì CPU
> >> > +ë ìëì ììë ëê ì ìê ëëë: ìë êìì ìêì êêë ëëì
> >> > +íìíë, ëë ìíìë ììíê ìëììê ë íì ììëë ìëììë
> >> > +ëìêììëë. ëëì, ì ììì ììë ìíê ìíìë smp_store_release()
> >> > +ì êì ëìì ëëë ëëìê íìíëë:
> >> > +
> >> > + q = READ_ONCE(a);
> >> > + if (q) {
> >> > + smp_store_release(&b, p);
> >> > + do_something();
> >> > + } else {
> >> > + smp_store_release(&b, p);
> >> > + do_something_else();
> >> > + }
> >> > +
> >> > +ëëì ëìì ëëë ëëìê ìëë, ìë êìì ììë ìíì ìíëììëì
> >> > +ìë ëë ëìë ëìëëë, ìë ëë ëìê êì êììëë:
> >> > +
> >> > + q = READ_ONCE(a);
> >> > + if (q) {
> >> > + WRITE_ONCE(b, p);
> >> > + do_something();
> >> > + } else {
> >> > + WRITE_ONCE(b, r);
> >> > + do_something_else();
> >> > + }
> >> > +
> >> > +ììì READ_ONCE() ë ìíìëê 'a' ì êì ìëíëë êì ëê ìí ììí
> >> > +íìíëë.
> >> > +
> >> > +ëí, ëì ëì 'q' ë êìê íë ìì ëí ììíì íëë, êëì ììë
> >> > +ìíìëë ê êì ììíê ëëì íìí ìêêêë ììëë ì ììëë.
> >> > +ìë ëë:
> >> > +
> >> > + q = READ_ONCE(a);
> >> > + if (q % MAX) {
> >> > + WRITE_ONCE(b, p);
> >> > + do_something();
> >> > + } else {
> >> > + WRITE_ONCE(b, r);
> >> > + do_something_else();
> >> > + }
> >> > +
> >> > +ëì MAX ê 1 ë ììë ììëë, ìíìëë (q % MAX) ë 0ìë êì ìììê,
> >> > +ìì ìëë ìëì êì ëêëë ì ììëë:
> >> > +
> >> > + q = READ_ONCE(a);
> >> > + WRITE_ONCE(b, p);
> >> > + 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, p);
> >> > + do_something();
> >> > + } else {
> >> > + WRITE_ONCE(b, r);
> >> > + 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() ë ìíìëìê ììì ëë
> >> > +ìíëììì ìí ìëë ìëë ëëëë íìë, ìíìëê êëê ëëìì
> >> > +ìëì ìí êêë ììíëë êìíìë ììëë.
> >> > +
> >> > +ëìëìë, ìíë ìììì ìíì (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() ì ììì ìíë
> >> > + ìììì ìëìì ìê íëë ëìì ì ì ììëë. ë ëì ìëë
> >> > + ìíì "ìíìë ëëì" ììì ìêíìê ëëëë.
> >> > +
> >> > + (*) ìíë ìììì ëí ëë íìì ëëìëê ìì ëì ììëëë.
> >> > +
> >> > + (*) ìíë ìììì ìíìì ìêíì -ììëë-. ìíìì íìíëë,
> >> > + 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_ops.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 ìíëììì ìëë íì
> >> > + ìëë ì ììëë. smp_mb__before_spinlock() ëì ACQUIRE ê ìíëë
> >> > + ìë ëëì ëë ìì ìíìë ëë ëì ëëì ìíìì ëí ìì
> >> > + ëìëë. ìê smp_mb() ëë ìíë êìì êìíìì! ëì ìííììì
> >> > + smp_mb__before_spinlock() ì ìì ìëìë íì ììëë.
> >> > +
> >> > + (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);
> >> > +
> >> > +
> >> > +ë ëì ìëë ìíì Documenataion/DocBook/deviceiobook.tmpl ì ìêíìì.
> >> > +
> >> > +
> >> > +=========================
> >> > +ëëë ëëìê íìí ê
> >> > +=========================
> >> > +
> >> > +ìë 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 ì
> >> > +ììì ìì ëìì ê ìì ëëêì ììì ìëí êëë.
> >> > +
> >> > +
> >> > +ìíë ìíëìì
> >> > +-----------------
> >> > +
> >> > +ìíë ìíëììì êìììë íëììê ìíìììë ëëëë ê ì ìëë
> >> > +ìì ëëë ëëìë ëííê ë ìëë ëííì ììë, ìëìì ìëí
> >> > +ììììë ììíë êë ì íëìëë.
> >> > +
> >> > +ëëëì ìë ìíë ììíê íë ìíì ëí (ììì ëë ììì) ìëë
> >> > +ëííë ìíë ìíëììì ëë SMP-ìêì ëì ëëë ëëì(smp_mb())ë
> >> > +ìì ìíëììì ìê ëì ëííëë. ìë ìíëììì ëìì êëì
> >> > +íííëë:
> >> > +
> >> > + xchg();
> >> > + atomic_xchg(); atomic_long_xchg();
> >> > + atomic_inc_return(); atomic_long_inc_return();
> >> > + atomic_dec_return(); atomic_long_dec_return();
> >> > + atomic_add_return(); atomic_long_add_return();
> >> > + atomic_sub_return(); atomic_long_sub_return();
> >> > + atomic_inc_and_test(); atomic_long_inc_and_test();
> >> > + atomic_dec_and_test(); atomic_long_dec_and_test();
> >> > + atomic_sub_and_test(); atomic_long_sub_and_test();
> >> > + atomic_add_negative(); atomic_long_add_negative();
> >> > + test_and_set_bit();
> >> > + test_and_clear_bit();
> >> > + test_and_change_bit();
> >> > +
> >> > + /* exchange ìêì ìêí ë */
> >> > + cmpxchg();
> >> > + atomic_cmpxchg(); atomic_long_cmpxchg();
> >> > + atomic_add_unless(); atomic_long_add_unless();
> >> > +
> >> > +ìêëì ëëë ëëì íêê íìí ACQUIRE ëëì RELEASE ëë ìíëììëì
> >> > +êíí ë, êëê êì íìë ìí ëíëì ììíë ììí ë, ìëì ëëë
> >> > +ëëì íêê íìí ê ëì ììëëë.
> >> > +
> >> > +
> >> > +ëìì ìíëììëì ëëë ëëìë ëííì _ìê_ ëëì ëìê ë ì
> >> > +ììë, RELEASE ëëì ìíëììëê êì êëì êíí ë ììë ìë
> >> > +ììëë:
> >> > +
> >> > + atomic_set();
> >> > + set_bit();
> >> > + clear_bit();
> >> > + change_bit();
> >> > +
> >> > +ìêëì ììí ëìë íìíëë ììí (ìë ëë smp_mb__before_atomic()
> >> > +êì) ëëë ëëìê ëìììë íê ììëìì íëë.
> >> > +
> >> > +
> >> > +ìëì êëë ëëë ëëìë ëííì _ìê_ ëëì, ìë íêììë (ìë
> >> > +ëë smp_mb__before_atomic() ê êì) ëììì ëëë ëëì ììì íìíëë.
> >> > +
> >> > + atomic_add();
> >> > + atomic_sub();
> >> > + atomic_inc();
> >> > + atomic_dec();
> >> > +
> >> > +ìêëì íê ììì ìí ììëëë, êëê íê ëìí ììì êêê ììíì
> >> > +ìëëë ëëë ëëìë íìì ìì êëë.
> >> > +
> >> > +êìì ìëì êëíê ìí ëíëì ììí ëììë ììëëë, ëíëì
> >> > +ììíë ëìë ëíëë ììììë ììëêë íìíë ìì ìë ìëí
> >> > +ëíëìë ìê ìì êìê ëëì ëëë ëëìë ìë íì ìì êëë.
> >> > +
> >> > +ëì ìë ëì êìíê ìí ììëëë, ë êë ëìì ìëììë ììì íì
> >> > +ììëë ìííì íëë ëëë ëëìê íìí ì ììëë.
> >> > +
> >> > +êëììë, ê ìììììë ëëë ëëìê íìíì ìëì ìëí êëíì
> >> > +íëë.
> >> > +
> >> > +ìëì ìíëììëì íëí ë êë ëìëìëë:
> >> > +
> >> > + test_and_set_bit_lock();
> >> > + clear_bit_unlock();
> >> > + __clear_bit_unlock();
> >> > +
> >> > +ìêëì ACQUIRE ëì RELEASE ëì ìíëììëì êííëë. ë êë ëêë
> >> > +êíí ëìë ìêëì ì ë ìííë íì ëìë, ìêëì êíì ëì
> >> > +ìííììì ììí ë ì ìê ëëìëë.
> >> > +
> >> > +[!] ìë ìíì ììí ì ìë íìí ëëë ëëì ëêëì ììëëë, ìë
> >> > +CPU ììë ììëë ìíë ììíëì ììì ëëë ëëìê ëíëì ììì
> >> > +ìíë ìíëììê ëëë ëëìë íê ììíë ê ëíìí ìì ë ì
> >> > +ìëë, êë êìì ì íì ëëë ëëì ëêëì no-op ì ëì ììììë
> >> > +ìëìë íì ììëë.
> >> > +
> >> > +ë ëì ëìì ìíì Documentation/atomic_ops.txt ë ìêíìì.
> >> > +
> >> > +
> >> > +ëëìì ììì
> >> > +---------------
> >> > +
> >> > +ëì ëëììê ëëë ëí êëìë ììë ì ìëë, êëê ììëë
> >> > +ëëììë CPU ìë ëì íì ëëë ììì ìíìë ëìê ëëë. ëëìëë
> >> > +êë ëëììë ììíê ìí ìíí ìëë ììë ìëë ëëë ìììë
> >> > +ëëìì íëë.
> >> > +
> >> > +íìë, ìììëì ìëì íêë ìííêë ëííëê ë íìììë íëíë
> >> > +ìëí CPU ë ìíìëëì ììíë ëëìë ìëì ìììëê ìì ëìì
> >> > +ìììëì ëëìììë ììë ììëë ëìíì ëíê í ì ìë - ëëììê
> >> > +ìëìì íê í - ììì ëìê ìê ì ììëë.
> >> > +
> >> > +ëëì ìë ëëìì, I/O ë ìëê ìììëì ììí ììììê ëë ì ìëì
> >> > +ìê ìë, - inb() ë writel() ê êì - ììí ììì ëíì íí ìëìììë
> >> > +íëë. ìêëì ëëëì êììë ëìì ëëë ëëì ì íê ììë íìê
> >> > +ììëëë, ëìì ëêì ìíììë ëìì ëëë ëëìê íìí ì ììëë:
> >> > +
> >> > + (1) ìë ììíìì I/O ìíìë ëë CPU ì ìêëê ìì ëììì ìëë,
> >> > + ëëì _ëë_ ìëìì ëëìëëì ëì ììëììë íê ì íëíì
> >> > + ììì ëìëìê ìì mmiowb() ê ê íìëìì íëë.
> >> > +
> >> > + (2) ëì ììì íìëì ìíë ëëë ììì ììì êë I/O ëëë ìëìë
> >> > + ììíëë, ììë êìíê ìíì _mandatory_ ëëë ëëìê íìíëë.
> >> > +
> >> > +ë ëì ìëë ìíì Documentation/DocBook/deviceiobook.tmpl ì ìêíììì.
> >> > +
> >> > +
> >> > +ìíëí
> >> > +--------
> >> > +
> >> > +ëëìëë ììì ìíëí ìëì ëíì ìí ìíëí ëí ì ìê ëëì
> >> > +ëëìëì ì ë ëëì ìëì ëëìì ìì ëë ììì ëëê ìí êìí ì
> >> > +ììëë.
> >> > +
> >> > +ììëìê ìíëí ëíë ê ëêëíê íê, ëëìëì íëíìí
> >> > +ìíëììëì ëë ìíëíê ëêëíê ë ììì ììëêë íë ëë (ëì
> >> > +í íí) ìë ìë ìí êìì - ììí ëëììëëë - ìì ì ììëë.
> >> > +ëëìëì ìíëí ëíì ìí ìì ëì, íë ëëìëì ììë êì 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
> >> > --
> >> > 1.9.1
> >> >