Re: [PATCH v4 3/3] Doc/memory-barriers: Add Korean translation

From: SeongJae Park
Date: Tue Jul 05 2016 - 17:58:22 EST


Hello,

2016-07-05 21:34 GMT+09:00 Byungchul Park <byungchul.park@xxxxxxx>:
> 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 intended to use the word using Hangul in usual while leave it as is
represented in English for code citation and uppercase ones to emphasize it.
Except the rule, I pursue consistency, too. I will search and fix such
inconsistency if found.

>
> I will add my opinions line by line as soon as possible.

Appreciate your devoted review.


Thanks,
SeongJae Park

>
> 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