Re: [PATCH v5 2/2] Doc/memory-barriers: Add Korean translation
From: Paul E. McKenney
Date: Thu Jul 21 2016 - 10:24:04 EST
On Thu, Jul 21, 2016 at 10:10:58AM +0900, SeongJae Park wrote:
> This commit adds Korean version of memory-barriers.txt document. The
> header is refered 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>
If Minchan is OK with this version, if Ingo and Jon have no objections,
and given the small change below, I will take it.
Please note that if the translation is not keeping up with the English
version, it will be removed. (Going forward, of course, given that the
older versions will still be available in older versions of the kernel.)
Thanx, Paul
> ---
> Documentation/ko_KR/memory-barriers.txt | 3134 +++++++++++++++++++++++++++++++
> 1 file changed, 3134 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..1bc5a40
> --- /dev/null
> +++ b/Documentation/ko_KR/memory-barriers.txt
> @@ -0,0 +1,3134 @@
> +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
> +try to update the original English file first.
Please remove "try to" from the above sentence, and add something like this:
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
>