Re: [PATCH v4 3/3] Doc/memory-barriers: Add Korean translation
From: Byungchul Park
Date: Tue Jul 05 2016 - 08:36:05 EST
On Mon, Jul 04, 2016 at 08:27:08AM +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.
Hello,
Thank you for making it much better to read.
At a glance, I found some words e.g. load and store were translated in some
sentences while they were not translated in some sentences. Please keep
them consistantly. IMHO, it's better to leave e.g. load and store unchanged,
but it's on you.
I will add my opinions line by line as soon as possible.
Thank you,
Byungchul
>
> [1] https://github.com/sjp38/linux.doc_trans_membarrier
>
> Signed-off-by: SeongJae Park <sj38.park@xxxxxxxxx>
> Acked-by: David Howells <dhowells@xxxxxxxxxx>
> Signed-off-by: Parl E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
> Acked-by: Minchan Kim <minchan@xxxxxxxxxx>
>
> Signed-off-by: SeongJae Park <sj38.park@xxxxxxxxx>
> ---
> Documentation/ko_KR/memory-barriers.txt | 3123 +++++++++++++++++++++++++++++++
> 1 file changed, 3123 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..39b4885
> --- /dev/null
> +++ b/Documentation/ko_KR/memory-barriers.txt
> @@ -0,0 +1,3123 @@
> +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.
> +
> +===================================
> +ì ëìë
> +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 ë ììëë
> +ìì ììì ììíìì.
> +
> +
> +ëëìì ìíëìì
> +-------------------
> +
> +ìë ëëììëì ìì ìííììë ëëë ììì ìíìë ìêíëë, íë
> +ìíë ëììíì ìêíë ììë ëì ììíëë. ìë ëì, ìëëì íí
> +ëììí (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};
> +
> +êëê ëììíëì ëíë êëì ììëë:
> +
> + (*) ì ëììíëì bitfield ìë ììëì ìëë, ìíìëëì bitfield ë
> + ììíë ìëë ììíëëì ììì ìë read-modify-write ëëëì
> + ììíë êìê ëê ëëìëë. ëë ìêëìì ëêíì bitfield ë
> + ììíë íì ëììì.
> +
> + (*) bitfield ëì ìë ëìë ëíëë êìë íëëë, íëì bitfield ì
> + ëë íëëì íëì ëìë ëíëìì íëë. ëì í bitfield ì ë
> + íëê ìë ëë ëìë ëíëëë, ìíìëì ììì ìë
> + read-modify-write ëëìëì í íëìì ìëìíê êìì íëìë ìíì
> + ëìê í ì ììëë.
> +
> + (*) ì ëììíëì ììíê ìëëê íêê ìí ììë ëìëì ëíìë
> + ììëëë. "ììíê íêê ìí" ìëíì íìëìë "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 ëê ëë ëëììëì ìëì ìëê ìí ìëì, ìì êëê
> +ëëë ìíëììëì ìí; ììì ëë; íêì ëëì ìì êëê ìë ìì
> +ëì ëìí íëì ììí ì ìê ëëì ìë êìëì ììíëë. ëëë
> +ëëìëì ìë íëëì ëíë íêë ììíê ìí ììëììì ìëê ìë
> +CPU ì ëëììë êì ìíììì ìëíëë ëë ì ìê íìëë.
> +
> +
> +ëëë ëëìì ìë
> +--------------------
> +
> +ëëë ëëìë ëêì êë ìëë ëëëëë:
> +
> + (1) ìê (ëë ìíì) ëëë ëëìë.
> +
> + ìê ëëë ëëìë ììíì ëë ìíëíëì íë ëëì ìì ëìë
> + ëë STORE ìíëììëì íë ëëì ëì ëìë ëë STORE
> + ìíëììëëë ëì ìíë êê êì ëì êì ëìíëë.
> +
> + ìê ëëìë ìíì ìíëììëëì ëí ëëì ìì ììêìëë; ëë
> + ìíëììëì ëíìë ìë ìíë ëìì ììëë.
> +
> + CPU ë ìêì íëì ëë ëëë ììíì ìëì ìíì ìíëììëì
> + íëì ììëìëë. ëë ìê ëëì ììì ìíì ìíëììëì ê
> + ìê ëëì ëì ëë ìíì ìíëììëëë _ìì_ ìíë êìëë.
> +
> + [!] ìê ëëìëì ìê ëë ëìí ììì ëëìì íê ìì ëì
> + ììëìììë íì ììëìì; "SMP ëëì ìëìê" ìëììì
> + ìêíìì.
> +
> +
> + (2) ëìí ììì ëëì.
> +
> + ëìí ììì ëëìë ìê ëëìì ëë ìíë ííìëë. ëêì ëë
> + ìíëììì ìê ëëì êì ìëì êì êêì ììíê ìì ë(ì:
> + ëëì ëëê ììí ììë ìëì ëëê ìë êì), ëëì ëëê ììì
> + ëìíë ìëì ëëì ìí ê ììê ìììê ìì ìëìí ëì ììì
> + ëìíê ìíì ëìí ììì ëëìê íìí êìëë.
> +
> + ëìí ììì ëëìë ìí ìììì ëë ìíëììë ììì ëëì ìì
> + ììêìëë; ìíì ìíëììëìë ëëìì ëëë, ëë ìëëë
> + ëëëì ëíìë ìë ìíë ëìì ììëë.
> +
> + (1) ìì ìêíëì, ììíì CPU ëì ëëë ììíì ìëì ìíì
> + ìíëììëì ëìê ììë, êêì êìì ìë ëë CPU ë ê êêë
> + ììí ì ìë êìë ë ì ììëë. ìì êì ëë CPU ì ìíì
> + ìíëììì êêì êìì ëê ìë CPU ê ììíë ëìí ììì
> + ëëìë, ëëì ìì ìë ëë ìíëììì ëë CPU ìì ëì ìíì
> + ìíëììê êì ììì ííëë, êë ìíì ìíëììëì ëëìëë
> + êêê ëìí ììì ëëì íì ëë ìíëììëìêë ëì êì
> + ëìíëë.
> +
> + ì ìì ììê ììì ëí ëììêëì ìíì "ëëë ëëì ëìì ì"
> + ìëììì ìêíìê ëëëë.
> +
> + [!] ìëì ëëë ëëì _ëìí_ ìììì êììì ìíë ìììì êìì
> + íëê ìëì ììëììì. ëì ëëì ëëë ìí ììê ìëì ëëì
> + ìììììë ê ìììì ìêììì ê ìì ììë êììëê ìëëë,
> + êêì _ìíë_ ììììê ììí ìê ëëìë êëë ìêí ëìêê
> + íìíëë. ë ììí ëìì ìíìë "ìíë ììì" ìëììì
> + ìêíìê ëëëë.
> +
> + [!] ëìí ììì ëëìë ëí ìê ëëìëê íê ìì ëì ììëìì
> + íëë; "SMP ëëì ìëìê" ìëììì ìêíìì.
> +
> +
> + (3) ìê (ëë ëë) ëëë ëëìë.
> +
> + ìê ëëìë ëìí ììì ëëì êëì ìêë ëëì ììì ëìë ëë
> + LOAD ìíëììëì ëëì ìíì ëìëë ëë LOAD ìíëììëëë ëì
> + ííì êìë ììíì ëë ìíëíëì ëìì êì ëìíëë.
> +
> + ìê ëëìë ëë ìíëììì ííìë ëëì ìì ììêìëë; ìíì
> + ìíëììì ëíìë ìë ìíë ëìì ììëë.
> +
> + ìê ëëë ëëìëì ëìí ììì ëëìë ëìíëë ëìí ììì
> + ëëìëì ëìí ì ììëë.
> +
> + [!] ìê ëëìëì ìëììë ìê ëëìëê ìì ëì ììëìì
> + íëë; "SMP ëëì ìëìê" ìëììì ìêíìì.
> +
> +
> + (4) ëì ëëë ëëìë.
> +
> + ëì ëëë ëëìë ììíì ëëì ìíëíëì ëëìëë ìì ëìë
> + ëë LOAD ì STORE ìíëììëì ëëì ìíì ëìë ëë LOAD ì STORE
> + ìíëììëëë ëì ìíë êìë ììíì ëëì ìíëíëì ëìê
> + ëì ëìíëë.
> +
> + ëì ëëë ëëìë ëëì ìíì ëëì ëí ëëì ìì ììêìëë.
> +
> + ëì ëëë ëëìë ìê ëëë ëëì, ìê ëëë ëëì ëëë
> + ëìíëë, ê ëëì ëëë ëìí ì ììëë.
> +
> +
> +êëê ëêìì ëìììì ìì ìëëì ììëë:
> +
> + (5) ACQUIRE ìíëììë.
> +
> + ì ìíëììëì ëëíì íêì ëëììë ëìíëë. ACQUIRE
> + ìíëìì ëì ëë ëëë ìíëììëì ACQUIRE ìíëìì íì
> + ììë êìë ììíì ëëì ìíëíëì ëìê ë êì ëìëëë.
> + LOCK ìíëììê smp_load_acquire(), smp_cond_acquire() ìíëììë
> + ACQUIRE ìíëììì ííëëë. ëì ìíëììì ìíë ìììê
> + smp_rmb() ë ììíì ACQUIRE ì ìëì ìêìíì ìììíëë.
> +
> + ACQUIRE ìíëìì ììì ëìë ëëë ìíëììëì ACQUIRE ìíëìì
> + ìë íì ìíë êìë ëì ìë ììëë.
> +
> + ACQUIRE ìíëììì êì íì RELEASE ìíëììê ìì ìì ììëìì
> + íëë.
> +
> +
> + (6) RELEASE ìíëììë.
> +
> + ìêëë ëëí íêì ëëììë ëìíëë. RELEASE ìíëìì ìì
> + ëë ëëë ìíëììëì RELEASE ìíëìì ìì ìëë êìë ììíì
> + ëë ìíëíëì ëìì êì ëìëëë. UNLOCK ìíëììëê
> + smp_store_release() ìíëììëë RELEASE ìíëììì ìììëë.
> +
> + RELEASE ìíëìì ëìì ëìë ëëë ìíëììëì RELEASE
> + ìíëììì ìëëê ìì ííì êìë ëì ì ììëë.
> +
> + ACQUIRE ì RELEASE ìíëììì ììì ìëììë ëë ëëë ëëìì
> + íììì ììëë (íìë "MMIO ìê ëëì" ìëìììì ìëëë ììë
> + ììëìì). ëí, RELEASE+ACQUIRE ìíì ìì ëëë ëëììë ëìí
> + êì ëìíì -ììëë-. íìë, ìë ëìì ACQUIRE ìíëììì í
> + í, êì ëìì ëí 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 êêë 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() ë READ_ONCE() ëë WRITE_ONCE() ë íìë
> +ìììëì ëíìë ëìíë barrier() ì ìíë ííë ë ì ììëë.
> +
> +barrier() íìë ëìê êì íêë êìëë:
> +
> + (*) ìíìëê barrier() ëì ìììëì barrier() ìì ìììëë ììë
> + ìëìëì ëíê íëë. ìììë ëìëìë, ìíëí íëë ìëì
> + ìíëíë ìë ììì íìì ììí íê ìí ììë ì ììëë.
> +
> + (*) ëí ëìì, ìíìëê ëí ìêì ììë ëìë ë ìíëììëë
> + ëëíëë íëë.
> +
> +READ_ONCE() ì WRITE_ONCE() íìë ìê ìëë ìëììë ëì ììë ëìì
> +ìëììë ìëìì ì ìë ëë ììíë ëìëë. ìë ëì ììíëì ëí
> +ìë ëêì ëìëë ëìê êìëë:
> +
> + (*) ìíìëë êì ëìì ëí ëëì ìíìë ìëì í ì ììë, ìë
> + êììë êì ëìì ëí ëëëì ìëìí ìë ììëë. ì ëì ëìì
> + ìëê:
> +
> + 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)"ì
> + ëìíëë. ìë ëì, ììì ìííìê 16-bit ìíì ììíëìì
> + ìêíê 7-bit immediate field ë êìê ìëë, ìíìëë ëìì 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 ëëë ëëìë êìê ììëë:
> +
> + íì íì SMP ìêì
> + =============== ======================= ===========================
> + ëì 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 ëëë
> +ëëìë _ëëì_ ììëìì íì êìíìì, ëë ëì ëì ììíë êìëë
> +ìëíê íëë.
> +
> +íì ëëìëì SMP ììíììë UP ììíììë SMP íêë íìíêìë
> +ëíìí ìëíëë êê ëëì SMP íêë íìíë ëë êì ììëìì
> +ìëëë. íìë, ëìí ëëë I/O ìëìë íí MMIO íêë íìí ëìë
> +ììë ìë ììëë. ì ëëìëì SMP ê ìë ììíììë ììë ì ìëë,
> +ìíìëì CPU ì ëëë ìíëìì ìëìë ëë ëìì ëëë ìíëììì
> +ëëììì ëìë ììêìë ìíì ìê ëëìëë.
> +
> +
> +ìë êê ëëì íìëë ììëë:
> +
> + (*) 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 ëìë ìêíìì.
> + ìëì ìêëì ììíì íì êêíëë "Atomic operations" ìëììì
> + ìêíìì.
> +
> +
> + (*) lockless_dereference();
> +
> + ì íìë smp_read_barrier_depends() ëìí ììì ëëìë ììíë
> + íìí ìì ëí íìë ë ì ììëë.
> +
> + êìì ëìííìì 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();
> +
> +ìêì íì ìê ëëìì ëììë, ìì êìì ìí I/O ìììì ìêê
> +ëëììë ììë ëìëë íìëë. ì íìì íêë CPU->íëìì
> +ìííììë ëìì ìì íëììì ìë ììêìë ìíì ëìëë.
> +
> +ë ëì ìëë ìíì "ë vs I/O ììì" ìëììì ìêíìì.
> +
> +
> +=========================
> +ìëì ìë ëëë ëëì
> +=========================
> +
> +ëëì ìëì ìë ëë íìëì ëëë ëëìë ëìíê ìëë, ëê ììì
> +êë íìëì ëëëìëë.
> +
> +ìêì _ììíì_ ëìì ìëíëë; íì ìííìììë ì ìëëë ë ëì
> +ëìì ìêí ìë ììëëë íë ìííìììë ëìêëë ëì ìë ìë
> +ìì ëëììë êë ëìì êëíì ëìì í êëë.
> +
> +
> +ë 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 ìíëììì ìë ë ëìì ëì êëë ìëë ìííêë ëì
> + íë êëíìëë êëëë ëì ìêëì ëêë íì ìíí ì ììëë.
> + ìíí ëì ìë ëëìë ëííì ììëë.
> +
> +[!] ìê: ë 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 ëê ìíëììì ììì ìí
> +ìì ìì ëëë ëëìë ëííì ììëë. ëëì, íëíì ììëì 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) ë ìì ì ìêìëëë, ë êë ëêëì êë êì ìíì ìë
> + êììë ìëë íêí ì ìëë íì íëë.
> +
> +ëê ìëíìë ìë íëììë ìíìë ììíììì ììì ëí ëìì íì
> +ìê ëëì, êë ìíìì ìíëí ëíìí ìíëììê íêê ìëëë ìë
> +ììë - íí 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ê ëìí ëì ëìì ììíë êìì ëë 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 ëëìì ìí êììë
> +êìë ëìê ë ì ìëë, 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 íìíê ìêí ëê êëëëë.
> +ëìëë ëê íëììì ìíì ìê ëëì, ììì task íìíê ëìíì next
> +íìíê ìíìê _ìì_ ìíìëë, ëë 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 ëëë ìëìë
> + ìêíëë, ììë êìíê ìíì _íì_ ëëë ëëìëì íìíëë.
> +
> +ë ëì ìëë ìíì 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 ìíëììëìë ììë ëìíì ììëë. ììê
> + íìíëë, 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 ---> : <----------- 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 ëë ëíë ììë êìê ìì ì ììëëë, íëí ëëë ìììë
> +ìíìë ì ëìí ììë (cachelet) ë ììì ììì íìë íëë. 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 íìíì
> +êëëì ëìíë ëìììëë. ì êììë íì ëëìë ììíì ëìë
> +íêí ì ìêìë êë ëëì ëëëì êì ììì íêëì ìëëë.
> +
> +ì êìë ìëíê íêíê ìí, ëì ëëì virt_mb() ëì ëíëë ììí ì
> +ììëë. ìêëì SMP ê íìí ëì ìëë smp_mb() ëê ëìí íêë
> +êìëëë, SMP ì SMP ìë ììí ëëì ëí ëìí ìëë ëëìëëë.
> +ìë ëì, êì ëì êìíëì (ìëë SMP ì) íìíì ëêíë í ëìë
> +smp_mb() ê ìëë virt_mb() ë ììíì íëë.
> +
> +ìêëì smp_mb() ëì êëê ëë ëëìì ëìíë, íí, MMIO ì ìíì
> +ëíìë êìíì ììëë: MMIO ì ìíì ììíëë, íì ëëìëì
> +ììíìê ëëëë.
> +
> +
> +=======
> +ìì ì
> +=======
> +
> +ìíì ëí
> +-----------
> +
> +ëëë ëëìë ìíì ëíë ììì(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