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

From: SeongJae Park
Date: Wed Jun 15 2016 - 02:48:15 EST


2016-06-09 5:45 GMT+09:00 SeongJae Park <sj38.park@xxxxxxxxx>:
> 2016-06-09 2:24 GMT+09:00 Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>:
>> On Wed, Jun 08, 2016 at 05:58:41PM +0900, SeongJae Park wrote:
>>> This commit adds Korean version of memory-barriers.txt document. The
>>> header is refered to HOWTO Korean version.
>>>
>>> The translator, SeongJae Park, is interested in parallel programming and
>>> translating[1] a book[2] about the topic.
>>>
>>> The translation has started from Feb, 2016 and using a github public
>>> repository[3] to maintain the work. The work is following[4] updates to
>>> the original document as well.
>>>
>>> Because the translator has knowledge about the topic and already
>>> following up the upstream changes, one would sure that this translation
>>> will keep reasonable quality and freshness.
>>>
>>> [1] https://git.kernel.org/cgit/linux/kernel/git/paulmck/perfbook.git/commit/FAQ.txt?id=edbfcdee0460
>>> [2] https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html
>>> [3] https://github.com/sjp38/linux.doc_trans_membarrier
>>> [4] https://github.com/sjp38/linux.doc_trans_membarrier/commit/06bd12d390f164fd253b861fc3aa8006d6d19ed9
>>>
>>> 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>
>>
>> I cannot judge this, so I must defer to Minchan. That said, the diffstat
>> since your version of April 18 is as follows:
>>
>> memory-barriers.txt | 303 ++++++++++++++++++++++++++++++----------------------
>> 1 file changed, 175 insertions(+), 128 deletions(-)
>>
>> I cannot tell which mainline version these patches correspond to, but the
>> English version has this diffstat since v4.5:
>>
>> memory-barriers.txt | 293 +++++++++++++++++++++++++++++++++++++++++-----------
>> 1 file changed, 234 insertions(+), 59 deletions(-)
>>
>> So your level of change thus far seems plausible.
>
> I agree that Minchan deserves to judge that since he is the Korean translations
> maintainer.

Minchan, may I ask your opinion about this patch?


Thanks,
SeongJae Park

> Also, thank you for let us know the diffstat. In particular, mainline
> changes since Jan, 2016 and my following commit in my tree[1] is as below:
>
> 3cfe2e8 (Will Deacon): locking/Documentation: Clarify that ACQUIRE
> applies to loads, RELEASE applies to stores
> Documentation/memory-barriers.txt | 5 +++++
> 1 file changed, 5 insertions(+)
>
> 65f95ff (SeongJae Park): documentation: Clarify compiler store-fusion example
> Documentation/memory-barriers.txt | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
>
> 8d4840e (David Howells): locking/Documentation: State purpose of
> memory-barriers.txt
> Documentation/memory-barriers.txt | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> 56db9f (SeongJae Park): ko_KR: State purpose of memory-barriers.txt
> Documentation/ko_KR/memory-barriers.txt | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
>
> e7720af (Peter Zijlstra): locking/Documentation: Add disclaimer
> Documentation/memory-barriers.txt | 18 +++++++++++++++++-
> 1 file changed, 17 insertions(+), 1 deletion(-)
>
> fb78604 (SeongJae Park): ko_KR/memory-barriers: Add disclaimer
> Documentation/ko_KR/memory-barriers.txt | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
>
> 787df63 (Davidlohr Bueso): locking/Documentation: Mention smp_cond_acquire()
> Documentation/memory-barriers.txt | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> 58faa44 (SeongJae Park): ko_KR/memory-barriers: Mention smp_cond_acquire()
> Documentation/ko_KR/memory-barriers.txt | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
>
> a505265 (Paul E. McKenney): locking/Documentation: Clarify
> relationship of barrier() to control dependencies
> Documentation/memory-barriers.txt | 7 ++++---
> 1 file changed, 4 insertions(+), 3 deletions(-)
>
> 919db2b (SeongJae Park): ko_KR/memory-barriers: apply "Clarify
> relationship of barrier() ..."
> Documentation/ko_KR/memory-barriers.txt | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> [1] https://github.com/sjp38/linux.doc_trans_membarrier
>
> Thanks,
> SeongJae Park
>
>>
>> Thanx, Paul
>>
>>> ---
>>> Documentation/ko_KR/memory-barriers.txt | 3095 +++++++++++++++++++++++++++++++
>>> 1 file changed, 3095 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..e98a16a
>>> --- /dev/null
>>> +++ b/Documentation/ko_KR/memory-barriers.txt
>>> @@ -0,0 +1,3095 @@
>>> +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};
>>> +
>>> +êëê ìí-ëììíëì ììëë:
>>> +
>>> + (*) ì ëììíëì bitfields ìë ììëì ìëë, ìíìëëì bitfields ë
>>> + ììíë ìëë ììì ìë read-modify-write ëëì ììíì ììíë
>>> + êìê ëê ëëìëë. ëë ìêëìì ëêíì bitfields ë ììíë
>>> + íì ëììì.
>>> +
>>> + (*) bitfields ê ìë ëìë ëíëë êìë íëëë, ììì 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ê ììí ìíì ìíëììëê êìë ììì ííëë, ëëìê
>>> + ìëëë ììììë ê ìì ëëì êìë ëë ìíì ìíëììëì
>>> + ëëìëë êêê ëìí ììì ëëì ìíì ëë ìíëììëìê ëì
>>> + ì ììì ëìíëë.
>>> +
>>> + ì ìì ììê ììì ëí ëììêëì ìíì "ëëë ëëì ëìì ì"
>>> + ìëììì ìêíìê ëëëë.
>>> +
>>> + [!] ìëì ëëë ëëì _ëìí_ ìììì êììì ìíë ìììì êìì
>>> + íëê ìëì ììëììì. ëì ëëì ëëë ìí ììê ìëì ëëì
>>> + ìììììë ê ìììì ìêììì ê ìì ììë êììëê ìëëë,
>>> + êêì _ìíë_ ììììê ììí ëë ëëìë êëë êí ëìì
>>> + íìíëë. ë ììí ëìì ìíìë "ìíë ììì" ìëììì
>>> + ìêíìê ëëëë.
>>> +
>>> + [!] ëìí ììì ëëìë ëí ìê ëëìëê íê ìì ëì ììëìì
>>> + íëë; "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 ë ììíì "ìë" ëììë, êëê 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 ì P ììì ììì B ìì ììì ëìì ìë ìê, ëëì ëìì
>>> +ìíì êëíëë:
>>> +
>>> + (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() ë ìêíê ìêìë, êê ëìì
>>> +ìëëë. ìê êêë ìëìê, ëëìë êê ëëëì ëíëë. ëëì, ì
>>> +ììë ììì íëë, 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() ê ìíìëìê ììì
>>> +ëë ìíëììì ëí ìëë ëëëë êìíê íìë, ìíìëê ê êêë
>>> +ììíëë êìíìë ììëë.
>>> +
>>> +ëìëìë, ìíë ìììì íëìì ìêíì -ììëë-. ìê 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
>>> +ê ìêëë êëë ìêì ëìí êëë:
>>> +
>>> + 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 ììë ëì ììíê
>>> +ììì ìììë íëë.
>>> +
>>> +ì ëêì ììë ëì ëëì ëì LB ì WWC ëíëì íìíëìëë:
>>> +http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf ì ì ììí:
>>> +https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html.
>>> +
>>> +ììíìë:
>>> +
>>> + (*) ìíë ìììì ìì ëëëì ëì ìíìëì ëí ììë ìììëë.
>>> + íìë, ê ìì ìë ììë ëìíì -ììëë-: ìì ëëì ëì ëëë
>>> + ìììë, ìì ìíìì ëì ìë êë ìììëì. ìë ëë ííì
>>> + ììê íìíëë, smp_rmb() ë smp_wmb(), ëë ìì ìíìëê ëì
>>> + ëëë ììëë, smp_mb() ë ììíì í êëë.
>>> +
>>> + (*) "if" ëì ì ëëìê êì ëììì ëìí ìíìëë ììíëë, ê
>>> + ìíìëì ê ìíì ìì smp_mb() ë ëêë smp_store_release() ë
>>> + ììíì ìíìë íë ììë ììë ëììì íëë. ìíìë ììíë
>>> + ì êìì barrier() ê ìëíë ëë ìíëìë ìíë ìììì ìì ìê
>>> + ìê ëëì "if" ëì ì ëëìì ììììì 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)) {
>>> + <implicit control dependency>
>>> + 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) íëë: ëëëìì ìë ëìíë
>>> +ëëíì íê ëì ììì íê, ììë íë ëìíë ëëíë ììíëìì ìì
>>> +ëëì ììëëë ëë ëë ììì ìì ëìê ììëê ìì ìì ë, ê
>>> +ëìíë ëëíëë. ìë ìí ìì ëë ììíëìì 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);
>>> +
>>> + ìë ëì, ììíë ì ìëë íë ëìê ëë 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 íêë íìíëë ììëìì ìëëë. íìë, ëìí ëëë 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_dereference() ìë êìì ëìííìì RCU ììì ëìëììë
>>> + êëëëë ìì ììíë ììíë, ìë ëë êìê ììíì êì ëìë
>>> + ìêëë êì ëìëë. ëí, lockless_dereference() RCU ì íêë, RCU
>>> + ììë ììë ì ìë ìë ëìí êìì ììëê ììëë.
>>> +
>>> +
>>> + (*) dma_wmb();
>>> + (*) dma_rmb();
>>> +
>>> + ìêëì CPU ì DMA êëí ëëìììì ììì êëí êì ëëëì ìêì
>>> + ìê ëìì ëí ììë ëìíê ìí ìêì ìë ëëëìì ììíê ìí
>>> + êëìëë.
>>> +
>>> + ìë ëì, ëëììì ëëëë êìíë, ëìíëí ìí êì ììí
>>> + ëìíëíê ëëììì ìí ìëì 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) ìêê ìëëììì
>>> + ëìíìê ìí íìíëë.
>>> +
>>> + ìêì ìë ëëëì ëí ë ìëê íìíë 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 ë ììêë (ììëë ìëììë ëì
>>> + ììë) ìë ìíëììì ìííëë, ì ìë ìíëììì ììì
>>> + ëëëì íêíê, ë ìíëììë ëìì ìêíê ëëë.
>>> +
>>> + íìë ëì ëì ìì ìë íìììëëì? êë êìì ìëë
>>> + ìììëë ëìêë í êê, ìêì êêì ëëë ëëìë ëëê
>>> + ëëë, ì ëëë ëëìë ìì ìë ìíëììì ìëëëë ëëê,
>>> + ëëëì ìëìë íêëëë. ìì ìë ìë êììíë ìì ì
>>> + ìêìëëë, ë êë ëêëì êë êììíì ìë êììë ìëë
>>> + íêí ì ìëë íì íëë.
>>> +
>>> +ëê ìëíìë ìë íëììë ìíìë ììíììì ììì ëí ëìì íì
>>> +ìê ëëì, êë ìíìì ìíëí ëíìí ìíëììê íêê ìëëë ìë
>>> +ììë - íí I/O ìììì êëíìë - ìëë ììë ì ìì êëë.
>>> +
>>> +"CPU ê ëí ëëì íê" ììë ìêíìê ëëëë.
>>> +
>>> +
>>> +ìë ëì, ëìê êì ìëë ìêí ëìë:
>>> +
>>> + *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 ììì ê ë ììì ìí ëíëì ìë ììì ììíêë ìë
>>> +ëìë ììíì ììëë. ìë ëì, ëìê êì ììëì ìíì êëíëë:
>>> +
>>> + *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 ìëíìì ëë ìíêëë ìêí ëìë. êëëë íëììë
>>> +ìëíìì ëê íëììë ëìíì ììë ëíëì ìëìë ìëíìì ììì
>>> +ì ììëë:
>>> +
>>> + 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();
>>> +
>>> + /* ìêíì ë */
>>> + 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 ë ìëí ìíìëëì ëì íë 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 ëììíìì ëêíë ëë ìíëììì íííê ëëì
>>> +ìëììëë ìëê ëìê ëì ììëë. ëì ìêëë ìëì ìëë 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 ëììíë
>>> + ìë ììíëë.
>>> +
>>> + ìëììëë, íëíì êëí ëëììë ììì íëê ìëëë, ìêëì
>>> + ììí ììê ëììê êíëì ìê ëìë êëë.
>>> +
>>> + íìë, (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 ë ììì íëêëì ëí íëêë ê ìììë ìêìì ìíë
>>> +êìë ëìê íìë ìëììëë ììë êì ìììì ìëëê êìëììë
>>> +íëë. (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 ëì ìê ëëìë ììí 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 ëë ëíë ììë êìê ìì ì ììëëë ìëìì ëëë ìììë
>>> +ìí ì ëìí ììëë ììì ììì íìíëë. Alpha ì êì ìí ëëë
>>> +ììì ëí ìëí (semantic) ì ëëë ëëìê ëìììë ììëì ììì
>>> +ëì êë ììì íìì ììë ìêíìëë.
>>> +
>>> +
>>> +ìì ìêì VS DMA
>>> +------------------
>>> +
>>> +ëë ììíì DMA ë íë ëëììì ëíìêì ìì ìêìì ììíìë
>>> +ììëë. êë êì, DMA ë ìëíë ëëììë RAM ìëëí ìëë ëìíë
>>> +ìì ìë ìëë, ëí ìì ëìì ìë CPU ì ììì ëëëê ìê ìì RAM ì
>>> +ëë êì ììì ììì ì ìê ëëìëë. ì ëìë íêíê ìíì, ìëì
>>> +ììí ëëìì ê CPU ììì ëìëë ëíëì íëì ìììë íëë (êëê
>>> +êêëì ëíí - invalidation - ë ìí ì ìêì).
>>> +
>>> +ëí, ëëììì ìí RAM ì DMA ë ììì êì ëëììê ìêë ìëí ìíì
>>> +CPU ì ìììì RAM ìë ìììë ëí ìì ëìì ìí ëììì ìë ìê, CPU
>>> +ì ììì ììíë ìì ëìì íë ììëìì 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() ë ìêì ëê ìí ëê ëë íìí ìì íê ëëë, ìë
>>> +ëì, 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 ì ìíì ììíëë, íì ëëìëì
>>> +ììíìê ëëëë.
>>> +
>>> +
>>> +=======
>>> +ìì ì
>>> +=======
>>> +
>>> +ìíì ëí
>>> +-----------
>>> +
>>> +ëëë ëëìëì ìíì ëíë ìììì ìëì ììì ëêíì ëì ììíì
>>> +ìê êííëë ììë ì ììëë. ë ììí ëìì ìíì ëìì ìêíìì:
>>> +
>>> + 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
>>>
>>>
>>