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

From: Byungchul Park
Date: Tue Jun 28 2016 - 04:15:40 EST


On Wed, Jun 08, 2016 at 05:58:41PM +0900, SeongJae Park wrote:
> 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>

Hello,

IMHO, a translation would be worth _only_ if the translated version is
more readable than the original one, and thus it should be translated
liberally rather than literally.

However, I am sorry to say that some parts were harder to be read than
english version, of course, most parts look very good though. Could you
check the whole again and make it more readable using liberal
translation?

Additionally, I will add my opinion line by line in korean below.

> +
> +========
> +ëììí
> +========
> +
> +ì ëìë ëììê ìëëë; ì ëìë (ëëê ìíê ìí) ìëììëë
> +(ìëì ìí ììëëë) ìëììì ìêë ìëíì ììëë. ì ëìë

ìê ë ìììëê ìí ìëë ëêë ê ìëêì?

> +ëëììì ìêíë ëìí ëëë ëëìëì ììíê ìí ìëììëëë ëê
> +ìëì ëëë (êëê ëì êëë) ëìë ììê ëëëë.
> +
> +ëì ëíìë, ì ëìë ëëìê íëììì êëíë ìíì ëí ëììê
> +ìëëë.
> +
> +ì ëìì ëìì ëêììëë:
> +
> + (1) ìë íì ëëìì ëí êëí ì ìë ììíì êëì ëìíê ìíì,
> + êëê
> +
> + (2) ìì êëí ëëìëì ëí ìëê ììíì íëì ìëë ìêíê ìíì.
> +
> +ìë ìííìì ëìëì íìí ëëìëì ëíìë ìêì ììêíë ììíì
> +ìêìíëëë ëì êëì ìêí ìë ììëëë, ìêì ììêíë
> +ìêìíëì ììíì ìë ìííìê ìëë ê ìííìê ìííì ëí
> +êìëë.

ëììëë ëìë êì ìêí íìê ìì ê êìëë.

> +
> +ìë ëëìë íì ìííìììë no-op ì ì ìëë íë ìííìê ëìíë
> +ëìììëë êëì ììë ëíìí ëëìë ìííê ëìë ìê ëëìëë.

ìííê ëìëì ììêë ëë ììì ë ê êìëë.
ìë ëì, ìëê ëêë ê ìëêì?

"ìë ëëìê íì ìííìììë 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ê ìëë CPUë ììííì ëëëí êìì CPU)
ëëë ìì ììë ëì ìíëì ììëë. ì, íëêëì ìêêêê ììëë
ëì ëìì, CPUê ìíë ììëë ëëë ììì ìíë ì ììëë."

---

I showed you several liberal translation examples. I think you translated
it very well, and the only thing I expect to be changed is the readability,
using liberal translation, in order to make this work valuable.

Could you enhance it next spin?

Thank you,
Byungchul

> +ììíê, ìíìë ëí íëêëì ììì ëìì ëêëëì ìë íë ëììë
> +ììì ìíëëë ìë ììëë ëëìëì ìëì í êìëë.
> +
> +ëëì ìì ëìêëìì, í 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