162306a36Sopenharmony_ciNOTE:
262306a36Sopenharmony_ciThis is a version of Documentation/memory-barriers.txt translated into
362306a36Sopenharmony_ciSpanish by Carlos Bilbao <carlos.bilbao@amd.com>. If you find any
462306a36Sopenharmony_cidifference between this document and the original file or a problem with
562306a36Sopenharmony_cithe translation, please contact the maintainer of this file. Please also
662306a36Sopenharmony_cinote that the purpose of this file is to be easier to read for non English
762306a36Sopenharmony_ci(read: Spanish) speakers and is not intended as a fork. So if you have any
862306a36Sopenharmony_cicomments or updates for this file please update the original English file
962306a36Sopenharmony_cifirst. The English version is definitive, and readers should look there if
1062306a36Sopenharmony_cithey have any doubt.
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci			 ======================================
1362306a36Sopenharmony_ci			 BARRERAS DE MEMORIA EN EL KERNEL LINUX
1462306a36Sopenharmony_ci			 ======================================
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciDocumento original: David Howells <dhowells@redhat.com>
1762306a36Sopenharmony_ci    Paul E. McKenney <paulmck@linux.ibm.com>
1862306a36Sopenharmony_ci    Will Deacon <will.deacon@arm.com>
1962306a36Sopenharmony_ci    Peter Zijlstra <peterz@infradead.org>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciTraducido por: Carlos Bilbao <carlos.bilbao@amd.com>
2262306a36Sopenharmony_ciNota: Si tiene alguna duda sobre la exactitud del contenido de esta
2362306a36Sopenharmony_citraducción, la única referencia válida es la documentación oficial en
2462306a36Sopenharmony_ciinglés.
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci===========
2762306a36Sopenharmony_ciADVERTENCIA
2862306a36Sopenharmony_ci===========
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciEste documento no es una especificación; es intencionalmente (por motivos
3162306a36Sopenharmony_cide brevedad) y sin querer (por ser humanos) incompleta. Este documento
3262306a36Sopenharmony_cipretende ser una guía para usar las diversas barreras de memoria
3362306a36Sopenharmony_ciproporcionadas por Linux, pero ante cualquier duda (y hay muchas) por favor
3462306a36Sopenharmony_cipregunte. Algunas dudas pueden ser resueltas refiriéndose al modelo de
3562306a36Sopenharmony_ciconsistencia de memoria formal y documentación en tools/memory-model/. Sin
3662306a36Sopenharmony_ciembargo, incluso este modelo debe ser visto como la opinión colectiva de
3762306a36Sopenharmony_cisus maintainers en lugar de que como un oráculo infalible.
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciDe nuevo, este documento no es una especificación de lo que Linux espera
4062306a36Sopenharmony_cidel hardware.
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciEl propósito de este documento es doble:
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci (1) especificar la funcionalidad mínima en la que se puede confiar para
4562306a36Sopenharmony_ci     cualquier barrera en concreto, y
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci (2) proporcionar una guía sobre cómo utilizar las barreras disponibles.
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciTenga en cuenta que una arquitectura puede proporcionar más que el
5062306a36Sopenharmony_cirequisito mínimo para cualquier barrera en particular, pero si la
5162306a36Sopenharmony_ciarquitectura proporciona menos de eso, dicha arquitectura es incorrecta.
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciTenga en cuenta también que es posible que una barrera no valga (sea no-op)
5462306a36Sopenharmony_cipara alguna arquitectura porque por la forma en que funcione dicha
5562306a36Sopenharmony_ciarquitectura, la barrera explícita resulte innecesaria en ese caso.
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci==========
5862306a36Sopenharmony_ciCONTENIDOS
5962306a36Sopenharmony_ci==========
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci (*) Modelo abstracto de acceso a memoria.
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci     - Operaciones del dispositivo.
6462306a36Sopenharmony_ci     - Garantías.
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci (*) ¿Qué son las barreras de memoria?
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci     - Variedades de barrera de memoria.
6962306a36Sopenharmony_ci     - ¿Qué no se puede asumir sobre las barreras de memoria?
7062306a36Sopenharmony_ci     - Barreras de dirección-dependencia (históricas).
7162306a36Sopenharmony_ci     - Dependencias de control.
7262306a36Sopenharmony_ci     - Emparejamiento de barreras smp.
7362306a36Sopenharmony_ci     - Ejemplos de secuencias de barrera de memoria.
7462306a36Sopenharmony_ci     - Barreras de memoria de lectura frente a especulación de carga.
7562306a36Sopenharmony_ci     - Atomicidad multicopia.
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci (*) Barreras explícitas del kernel.
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci     - Barrera del compilador.
8062306a36Sopenharmony_ci     - Barreras de memoria de la CPU.
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci (*) Barreras de memoria implícitas del kernel.
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci     - Funciones de adquisición de cerrojo.
8562306a36Sopenharmony_ci     - Funciones de desactivación de interrupciones.
8662306a36Sopenharmony_ci     - Funciones de dormir y despertar.
8762306a36Sopenharmony_ci     - Funciones varias.
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci (*) Efectos de barrera adquiriendo intra-CPU.
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci     - Adquisición vs accesos a memoria.
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci (*) ¿Dónde se necesitan barreras de memoria?
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci     - Interacción entre procesadores.
9662306a36Sopenharmony_ci     - Operaciones atómicas.
9762306a36Sopenharmony_ci     - Acceso a dispositivos.
9862306a36Sopenharmony_ci     - Interrupciones.
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci (*) Efectos de barrera de E/S del kernel.
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci (*) Modelo de orden mínimo de ejecución asumido.
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci (*) Efectos de la memoria caché de la CPU.
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci     - Coherencia de caché.
10762306a36Sopenharmony_ci     - Coherencia de caché frente a DMA.
10862306a36Sopenharmony_ci     - Coherencia de caché frente a MMIO.
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci (*) Cosas que hacen las CPU.
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci     - Y luego está el Alfa.
11362306a36Sopenharmony_ci     - Guests de máquinas virtuales.
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci (*) Ejemplos de usos.
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci     - Buffers circulares.
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci (*) Referencias.
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci====================================
12362306a36Sopenharmony_ciMODELO ABSTRACTO DE ACCESO A MEMORIA
12462306a36Sopenharmony_ci====================================
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciConsidere el siguiente modelo abstracto del sistema:
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		            :                :
12962306a36Sopenharmony_ci		            :                :
13062306a36Sopenharmony_ci		            :                :
13162306a36Sopenharmony_ci		+-------+   :   +--------+   :   +-------+
13262306a36Sopenharmony_ci		|       |   :   |        |   :   |       |
13362306a36Sopenharmony_ci		|       |   :   |        |   :   |       |
13462306a36Sopenharmony_ci		| CPU 1 |<----->| Memoria|<----->| CPU 2 |
13562306a36Sopenharmony_ci		|       |   :   |        |   :   |       |
13662306a36Sopenharmony_ci		|       |   :   |        |   :   |       |
13762306a36Sopenharmony_ci		+-------+   :   +--------+   :   +-------+
13862306a36Sopenharmony_ci		    ^       :       ^        :       ^
13962306a36Sopenharmony_ci		    |       :       |        :       |
14062306a36Sopenharmony_ci		    |       :       |        :       |
14162306a36Sopenharmony_ci		    |       :       v        :       |
14262306a36Sopenharmony_ci		    |       :   +--------+   :       |
14362306a36Sopenharmony_ci		    |       :   |        |   :       |
14462306a36Sopenharmony_ci		    |       :   | Disposi|   :       |
14562306a36Sopenharmony_ci		    +---------->| tivo   |<----------+
14662306a36Sopenharmony_ci		            :   |        |   :
14762306a36Sopenharmony_ci		            :   |        |   :
14862306a36Sopenharmony_ci		            :   +--------+   :
14962306a36Sopenharmony_ci		            :                :
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciCada CPU ejecuta un programa que genera operaciones de acceso a la memoria.
15262306a36Sopenharmony_ciEn la CPU abstracta, el orden de las operaciones de memoria es muy
15362306a36Sopenharmony_cirelajado, y una CPU en realidad puede realizar las operaciones de memoria
15462306a36Sopenharmony_cien el orden que desee, siempre que la causalidad del programa parezca
15562306a36Sopenharmony_cimantenerse. De manera similar, el compilador también puede organizar las
15662306a36Sopenharmony_ciinstrucciones que emite en el orden que quiera, siempre que no afecte al
15762306a36Sopenharmony_cifuncionamiento aparente del programa.
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciEntonces, en el diagrama anterior, los efectos de las operaciones de
16062306a36Sopenharmony_cimemoria realizadas por un CPU son percibidos por el resto del sistema a
16162306a36Sopenharmony_cimedida que las operaciones cruzan la interfaz entre la CPU y el resto del
16262306a36Sopenharmony_cisistema (las líneas discontinuas a puntos).
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ciPor ejemplo, considere la siguiente secuencia de eventos:
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	CPU 1		CPU 2
16762306a36Sopenharmony_ci	===============	===============
16862306a36Sopenharmony_ci	{ A == 1; B == 2 }
16962306a36Sopenharmony_ci	A = 3;		x = B;
17062306a36Sopenharmony_ci	B = 4;		y = A;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciEl conjunto de accesos visto por el sistema de memoria en el medio se puede
17362306a36Sopenharmony_ciorganizar en 24 combinaciones diferentes (donde LOAD es cargar y STORE es
17462306a36Sopenharmony_ciguardar):
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ciSTORE A=3,	STORE B=4,	y=LOAD A->3,	x=LOAD B->4
17762306a36Sopenharmony_ciSTORE A=3,	STORE B=4,	x=LOAD B->4,	y=LOAD A->3
17862306a36Sopenharmony_ciSTORE A=3,	y=LOAD A->3,	STORE B=4,	x=LOAD B->4
17962306a36Sopenharmony_ciSTORE A=3,	y=LOAD A->3,	x=LOAD B->2,	STORE B=4
18062306a36Sopenharmony_ciSTORE A=3,	x=LOAD B->2,	STORE B=4,	y=LOAD A->3
18162306a36Sopenharmony_ciSTORE A=3,	x=LOAD B->2,	y=LOAD A->3,	STORE B=4
18262306a36Sopenharmony_ciSTORE B=4,	STORE A=3,	y=LOAD A->3,	x=LOAD B->4
18362306a36Sopenharmony_ciSTORE B=4, ...
18462306a36Sopenharmony_ci...
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ciy por lo tanto puede resultar en cuatro combinaciones diferentes de
18762306a36Sopenharmony_civalores:
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cix == 2, y == 1
19062306a36Sopenharmony_cix == 2, y == 3
19162306a36Sopenharmony_cix == 4, y == 1
19262306a36Sopenharmony_cix == 4, y == 3
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciAdemás, los stores asignados por una CPU al sistema de memoria pueden no
19562306a36Sopenharmony_ciser percibidos por los loads realizados por otra CPU en el mismo orden en
19662306a36Sopenharmony_cique fueron realizados.
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ciComo otro ejemplo, considere esta secuencia de eventos:
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	CPU 1		CPU 2
20162306a36Sopenharmony_ci	===============	===============
20262306a36Sopenharmony_ci	{ A == 1, B == 2, C == 3, P == &A, Q == &C }
20362306a36Sopenharmony_ci	B = 4;		Q = P;
20462306a36Sopenharmony_ci	P = &B;		D = *Q;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ciAquí hay una dependencia obvia de la dirección, ya que el valor cargado en
20762306a36Sopenharmony_ciD depende en la dirección recuperada de P por la CPU 2. Al final de la
20862306a36Sopenharmony_cisecuencia, cualquiera de los siguientes resultados son posibles:
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci  (Q == &A) y (D == 1)
21162306a36Sopenharmony_ci  (Q == &B) y (D == 2)
21262306a36Sopenharmony_ci  (Q == &B) y (D == 4)
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciTenga en cuenta que la CPU 2 nunca intentará cargar C en D porque la CPU
21562306a36Sopenharmony_cicargará P en Q antes de emitir la carga de *Q.
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ciOPERACIONES DEL DISPOSITIVO
21862306a36Sopenharmony_ci---------------------------
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ciAlgunos dispositivos presentan sus interfaces de control como colecciones
22162306a36Sopenharmony_cide ubicaciones de memoria, pero el orden en que se accede a los registros
22262306a36Sopenharmony_cide control es muy importante. Por ejemplo, imagine una tarjeta ethernet con
22362306a36Sopenharmony_ciun conjunto de registros a los que se accede a través de un registro de
22462306a36Sopenharmony_cipuerto de dirección (A) y un registro de datos del puerto (D). Para leer el
22562306a36Sopenharmony_ciregistro interno 5, el siguiente código podría entonces ser usado:
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci  *A = 5;
22862306a36Sopenharmony_ci  x = *D;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cipero esto podría aparecer como cualquiera de las siguientes dos secuencias:
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci  STORE *A = 5, x = LOAD *D
23362306a36Sopenharmony_ci  x = LOAD *D, STORE *A = 5
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ciel segundo de las cuales casi con certeza resultará en mal funcionamiento,
23662306a36Sopenharmony_ciya que se estableció la dirección _después_ de intentar leer el registro.
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciGARANTÍAS
24062306a36Sopenharmony_ci---------
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciHay algunas garantías mínimas que se pueden esperar de una CPU:
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci (*) En cualquier CPU dada, los accesos a la memoria dependiente se
24562306a36Sopenharmony_ci     emitirán en orden, con respeto a sí mismo. Esto significa que para:
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	Q = READ_ONCE(P); D = READ_ONCE(*Q);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci     donde READ_ONCE() es LEER_UNA_VEZ(), la CPU emitirá las siguientes
25062306a36Sopenharmony_ci     operaciones de memoria:
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	Q = LOAD P, D = LOAD *Q
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci     y siempre en ese orden. Sin embargo, en DEC Alpha, READ_ONCE() también
25562306a36Sopenharmony_ci     emite una instrucción de barrera de memoria, de modo que una CPU DEC
25662306a36Sopenharmony_ci     Alpha, sin embargo emite las siguientes operaciones de memoria:
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci     Ya sea en DEC Alpha o no, READ_ONCE() también evita que el compilador
26162306a36Sopenharmony_ci     haga cosas inapropiadas.
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci (*) Los loads y stores superpuestos dentro de una CPU en particular
26462306a36Sopenharmony_ci     parecerán ser ordenados dentro de esa CPU. Esto significa que para:
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	a = READ_ONCE(*X); WRITE_ONCE(*X, b);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci     donde WRITE_ONCE() es ESCRIBIR_UNA_VEZ(), la CPU solo emitirá la
26962306a36Sopenharmony_ci     siguiente secuencia de operaciones de memoria:
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	a = LOAD *X, STORE *X = b
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci     Y para:
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	WRITE_ONCE(*X, c); d = READ_ONCE(*X);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci     la CPU solo emitirá:
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	STORE *X = c, d = LOAD *X
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci  (Los loads y stores se superponen si están destinados a piezas
28262306a36Sopenharmony_ci  superpuestas de memoria).
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ciY hay una serie de cosas que _deben_ o _no_ deben asumirse:
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci (*) _No_debe_ asumirse que el compilador hará lo que usted quiera
28762306a36Sopenharmony_ci     con referencias de memoria que no están protegidas por READ_ONCE() y
28862306a36Sopenharmony_ci     WRITE ONCE(). Sin ellos, el compilador tiene derecho a hacer todo tipo
28962306a36Sopenharmony_ci     de transformaciones "creativas", que se tratan en la sección BARRERA
29062306a36Sopenharmony_ci     DEL COMPILADOR.
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci   (*) _No_debe_ suponerse que se emitirán loads y stores independientes
29362306a36Sopenharmony_ci       en el orden dado. Esto significa que para:
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	X = *A; Y = *B; *D = Z;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci     podemos obtener cualquiera de las siguientes secuencias:
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci    X = LOAD *A,  Y = LOAD *B,  STORE *D = Z
30062306a36Sopenharmony_ci   	X = LOAD *A,  STORE *D = Z, Y = LOAD *B
30162306a36Sopenharmony_ci   	Y = LOAD *B,  X = LOAD *A,  STORE *D = Z
30262306a36Sopenharmony_ci   	Y = LOAD *B,  STORE *D = Z, X = LOAD *A
30362306a36Sopenharmony_ci   	STORE *D = Z, X = LOAD *A,  Y = LOAD *B
30462306a36Sopenharmony_ci   	STORE *D = Z, Y = LOAD *B,  X = LOAD *A
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci (*) Se _debe_ suponer que los accesos de memoria superpuestos pueden
30762306a36Sopenharmony_ci     fusionarse o ser descartados. Esto significa que para:
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	X = *A; Y = *(A + 4);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci  podemos obtener cualquiera de las siguientes secuencias:
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciX = LOAD *A; Y = LOAD *(A + 4);
31462306a36Sopenharmony_ciY = LOAD *(A + 4); X = LOAD *A;
31562306a36Sopenharmony_ci{X, Y} = LOAD {*A, *(A + 4) };
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci  Y para:
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci*A = X; *(A + 4) = Y;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci  podemos obtener cualquiera de:
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ciSTORE *A = X; STORE *(A + 4) = Y;
32462306a36Sopenharmony_ciSTORE *(A + 4) = Y; STORE *A = X;
32562306a36Sopenharmony_ciSTORE {*A, *(A + 4) } = {X, Y};
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ciY hay anti-garantías:
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci(*) Estas garantías no se aplican a los campos de bits, porque los
33062306a36Sopenharmony_ci    compiladores a menudo generan código para modificarlos usando
33162306a36Sopenharmony_ci    secuencias de lectura-modificación-escritura no atómica. No intente
33262306a36Sopenharmony_ci    utilizar campos de bits para sincronizar algoritmos paralelos.
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci(*) Incluso en los casos en que los campos de bits están protegidos por
33562306a36Sopenharmony_ci    cerrojos (o "cerrojos", o "locks"), todos los componentes en un campo
33662306a36Sopenharmony_ci    de bits dado deben estar protegidos por un candado. Si dos campos en un
33762306a36Sopenharmony_ci    campo de bits dado están protegidos por diferentes locks, las
33862306a36Sopenharmony_ci    secuencias de lectura-modificación-escritura no atómicas del lock
33962306a36Sopenharmony_ci    pueden causar una actualización a una campo para corromper el valor de
34062306a36Sopenharmony_ci    un campo adyacente.
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci(*) Estas garantías se aplican solo a escalares correctamente alineados y
34362306a36Sopenharmony_ci    dimensionados. De "tamaño adecuado" significa actualmente variables que
34462306a36Sopenharmony_ci    son del mismo tamaño que "char", "short", "int" y "long".
34562306a36Sopenharmony_ci    "Adecuadamente alineado" significa la alineación natural, por lo tanto,
34662306a36Sopenharmony_ci    no hay restricciones para "char", alineación de dos bytes para "short",
34762306a36Sopenharmony_ci    alineación de cuatro bytes para "int", y alineación de cuatro u ocho
34862306a36Sopenharmony_ci    bytes para "long", en sistemas de 32 y 64 bits, respectivamente. Tenga
34962306a36Sopenharmony_ci    en cuenta que estos garantías se introdujeron en el estándar C11, así
35062306a36Sopenharmony_ci    que tenga cuidado cuando utilice compiladores anteriores a C11 (por
35162306a36Sopenharmony_ci    ejemplo, gcc 4.6). La parte de la norma que contiene esta garantía es
35262306a36Sopenharmony_ci    la Sección 3.14, que define "ubicación de memoria" de la siguiente
35362306a36Sopenharmony_ci    manera:
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci    ubicación de memoria
35662306a36Sopenharmony_ci  ya sea un objeto de tipo escalar, o una secuencia máxima
35762306a36Sopenharmony_ci  de campos de bits adyacentes, todos con ancho distinto de cero
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci  NOTE 1: Dos hilos de ejecución pueden actualizar y acceder
36062306a36Sopenharmony_ci  ubicaciones de memoria separadas sin interferir entre
36162306a36Sopenharmony_ci  ellos.
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci  NOTE 2: Un campo de bits y un miembro adyacente que no es un campo de
36462306a36Sopenharmony_ci  bits están en ubicaciones de memoria separadas. Lo mismo sucede con
36562306a36Sopenharmony_ci  dos campos de bits, si uno se declara dentro de un declaración de
36662306a36Sopenharmony_ci  estructura anidada y el otro no, o si las dos están separados por una
36762306a36Sopenharmony_ci  declaración de campo de bits de longitud cero, o si están separados por
36862306a36Sopenharmony_ci  un miembro no declarado como campo de bits. No es seguro actualizar
36962306a36Sopenharmony_ci  simultáneamente dos campos de bits en la misma estructura si entre
37062306a36Sopenharmony_ci  todos los miembros declarados también hay campos de bits, sin importar
37162306a36Sopenharmony_ci  cuál resulta ser el tamaño de estos campos de bits intermedios.
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci==================================
37562306a36Sopenharmony_ci¿QUÉ SON LAS BARRERAS DE MEMORIA?
37662306a36Sopenharmony_ci==================================
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciComo se puede leer arriba, las operaciones independientes de memoria se
37962306a36Sopenharmony_cirealizan de manera efectiva en orden aleatorio, pero esto puede ser un
38062306a36Sopenharmony_ciproblema para la interacción CPU-CPU y para la E/S ("I/O"). Lo que se
38162306a36Sopenharmony_cirequiere es alguna forma de intervenir para instruir al compilador y al
38262306a36Sopenharmony_ciCPU para restringir el orden.
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ciLas barreras de memoria son este tipo de intervenciones. Imponen una
38562306a36Sopenharmony_cipercepción de orden parcial, sobre las operaciones de memoria a ambos lados
38662306a36Sopenharmony_cide la barrera.
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ciTal cumplimiento es importante porque las CPUs y otros dispositivos en un
38962306a36Sopenharmony_cisistema pueden usar una variedad de trucos para mejorar el rendimiento,
39062306a36Sopenharmony_ciincluido el reordenamiento, diferimiento y combinación de operaciones de
39162306a36Sopenharmony_cimemoria; cargas especulativas; predicción de "branches" especulativos y
39262306a36Sopenharmony_civarios tipos de almacenamiento en caché. Las barreras de memoria se
39362306a36Sopenharmony_ciutilizan para anular o suprimir estos trucos, permitiendo que el código
39462306a36Sopenharmony_cicontrole sensatamente la interacción de múltiples CPU y/o dispositivos.
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ciVARIEDADES DE BARRERA DE MEMORIA
39862306a36Sopenharmony_ci---------------------------------
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ciLas barreras de memoria vienen en cuatro variedades básicas:
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci (1) Barreras de memoria al escribir o almacenar (Write or store memory
40362306a36Sopenharmony_ci     barriers).
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci     Una barrera de memoria de escritura garantiza que todas las
40662306a36Sopenharmony_ci     operaciones de STORE especificadas antes de que la barrera aparezca
40762306a36Sopenharmony_ci     suceden antes de todas las operaciones STORE especificadas después
40862306a36Sopenharmony_ci     de la barrera, con respecto a los otros componentes del sistema.
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci     Una barrera de escritura es un orden parcial solo en los stores; No
41162306a36Sopenharmony_ci     es requerido que tenga ningún efecto sobre los loads.
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci     Se puede considerar que una CPU envía una secuencia de operaciones de
41462306a36Sopenharmony_ci     store al sistema de memoria a medida que pasa el tiempo. Todos los
41562306a36Sopenharmony_ci     stores _antes_ de una barrera de escritura ocurrirán _antes_ de todos
41662306a36Sopenharmony_ci     los stores después de la barrera de escritura.
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci     [!] Tenga en cuenta que las barreras de escritura normalmente deben
41962306a36Sopenharmony_ci     combinarse con read o barreras de address-dependency barriers
42062306a36Sopenharmony_ci     (dependencia de dirección); consulte la subsección
42162306a36Sopenharmony_ci     "Emparejamiento de barreras smp".
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci (2) Barrera de dependencia de dirección (histórico).
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci     Una barrera de dependencia de dirección es una forma más débil de
42762306a36Sopenharmony_ci     barrera de lectura. En el caso de que se realicen dos loads de manera
42862306a36Sopenharmony_ci     que la segunda dependa del resultado de la primera (por ejemplo: el
42962306a36Sopenharmony_ci     primer load recupera la dirección a la que se dirigirá el segundo
43062306a36Sopenharmony_ci     load), una barrera de dependencia de dirección sería necesaria para
43162306a36Sopenharmony_ci     asegurarse de que el objetivo de la segunda carga esté actualizado
43262306a36Sopenharmony_ci     después de acceder a la dirección obtenida por la primera carga.
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci     Una barrera de dependencia de direcciones es una ordenación parcial en
43562306a36Sopenharmony_ci     laods de direcciones interdependientes; no se requiere que tenga
43662306a36Sopenharmony_ci     ningún efecto en los stores, ya sean cargas de memoria o cargas
43762306a36Sopenharmony_ci     de memoria superpuestas.
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci     Como se mencionó en (1), las otras CPU en el sistema pueden verse como
44062306a36Sopenharmony_ci     secuencias de stores en el sistema de memoria que la considerada CPU
44162306a36Sopenharmony_ci     puede percibir. Una barrera de dependencia de dirección emitida por
44262306a36Sopenharmony_ci     la CPU en cuestión garantiza que para cualquier carga que la preceda,
44362306a36Sopenharmony_ci     si esa carga toca alguna secuencia de stores de otra CPU, entonces
44462306a36Sopenharmony_ci     en el momento en que la barrera se complete, los efectos de todos los
44562306a36Sopenharmony_ci     stores antes del cambio del load serán perceptibles por cualquier
44662306a36Sopenharmony_ci     carga emitida después la barrera de la dependencia de la dirección.
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci     Consulte la subsección "Ejemplos de secuencias de barrera de memoria"
44962306a36Sopenharmony_ci     para ver los diagramas mostrando las restricciones de orden.
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci     [!] Tenga en cuenta que la primera carga realmente tiene que tener una
45262306a36Sopenharmony_ci     dependencia de _dirección_ y no es una dependencia de control. Si la
45362306a36Sopenharmony_ci     dirección para la segunda carga depende de la primera carga, pero la
45462306a36Sopenharmony_ci     dependencia es a través de un condicional en lugar de -en realidad-
45562306a36Sopenharmony_ci     cargando la dirección en sí, entonces es una dependencia de _control_
45662306a36Sopenharmony_ci     y se requiere una barrera de lectura completa o superior. Consulte la
45762306a36Sopenharmony_ci     subsección "Dependencias de control" para más información.
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci     [!] Tenga en cuenta que las barreras de dependencia de dirección
46062306a36Sopenharmony_ci     normalmente deben combinarse con barreras de escritura; consulte la
46162306a36Sopenharmony_ci     subsección "Emparejamiento de barreras smp".
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci     [!] Desde el kernel v5.9, se eliminó la API del kernel para barreras
46462306a36Sopenharmony_ci     de memoria de direcciones explícitas. Hoy en día, las APIs para marcar
46562306a36Sopenharmony_ci     cargas de variables compartidas, como READ_ONCE() y rcu_dereference(),
46662306a36Sopenharmony_ci     proporcionan barreras de dependencia de dirección implícitas.
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci (3) Barreras de memoria al leer o cargar (Read or load memory
46962306a36Sopenharmony_ci    barriers).
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci     Una barrera de lectura es una barrera de dependencia de direcciones,
47262306a36Sopenharmony_ci     más una garantía de que todas las operaciones de LOAD especificadas
47362306a36Sopenharmony_ci     antes de la barrera parecerán ocurrir antes de todas las operaciones
47462306a36Sopenharmony_ci     de LOAD especificadas después de la barrera con respecto a los demás
47562306a36Sopenharmony_ci     componentes del sistema.
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci     Una barrera de lectura es un orden parcial solo en cargas; no es
47862306a36Sopenharmony_ci     necesario que tenga ningún efecto en los stores.
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci     Las barreras de memoria de lectura implican barreras de dependencia de
48162306a36Sopenharmony_ci     direcciones, y por tanto puede sustituirlas por estas.
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci     [!] Tenga en mente que las barreras de lectura normalmente deben
48462306a36Sopenharmony_ci     combinarse con barreras de escritura; consulte la subsección
48562306a36Sopenharmony_ci     "Emparejamiento de barreras smp".
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci (4) Barreras de memoria generales
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci     Una barrera de memoria general proporciona la garantía de que todas
49062306a36Sopenharmony_ci     las operaciones LOAD y STORE especificadas antes de que la barrera
49162306a36Sopenharmony_ci     aparezca suceden antes de que todas las operaciones LOAD y STORE
49262306a36Sopenharmony_ci     especificadas después de la barrera con respecto a los demás
49362306a36Sopenharmony_ci     componentes del sistema.
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci     Una barrera de memoria general es un orden parcial tanto en
49662306a36Sopenharmony_ci     operaciones de carga como de almacenamiento.
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci     Las barreras de memoria generales implican barreras de memoria tanto
49962306a36Sopenharmony_ci     de lectura como de escritura, de modo que pueden sustituir a
50062306a36Sopenharmony_ci     cualquiera.
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciY un par de variedades implícitas:
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci (5)  ACQUIRE (de adquisición).
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci     Esto actúa como una barrera permeable unidireccional. Garantiza que
50762306a36Sopenharmony_ci     toda las operaciones de memoria después de la operación ACQUIRE
50862306a36Sopenharmony_ci     parezcan suceder después de la ACQUIRE con respecto a los demás
50962306a36Sopenharmony_ci     componentes del sistema. Las operaciones ACQUIRE incluyen operaciones
51062306a36Sopenharmony_ci     LOCK y smp_load_acquire(), y operaciones smp_cond_load_acquire().
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci     Las operaciones de memoria que ocurren antes de una operación ACQUIRE
51362306a36Sopenharmony_ci     pueden parecer suceder después de que se complete.
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci     Una operación ACQUIRE casi siempre debe estar emparejada con una
51662306a36Sopenharmony_ci     operación RELEASE (de liberación).
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci (6) Operaciones RELEASE (de liberación).
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci     Esto también actúa como una barrera permeable unidireccional.
52262306a36Sopenharmony_ci     Garantiza que todas las operaciones de memoria antes de la operación
52362306a36Sopenharmony_ci     RELEASE parecerán ocurrir antes de la operación RELEASE con respecto a
52462306a36Sopenharmony_ci     los demás componentes del sistema. Las operaciones de RELEASE incluyen
52562306a36Sopenharmony_ci     operaciones de UNLOCK y operaciones smp_store_release().
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci     Las operaciones de memoria que ocurren después de una operación
52862306a36Sopenharmony_ci     RELEASE pueden parecer suceder antes de que se complete.
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci     El uso de las operaciones ACQUIRE y RELEASE generalmente excluye la
53162306a36Sopenharmony_ci     necesidad de otros tipos de barrera de memoria. Además, un par
53262306a36Sopenharmony_ci     RELEASE+ACQUIRE NO garantiza actuar como una barrera de memoria
53362306a36Sopenharmony_ci     completa. Sin embargo, después de un ACQUIRE de una variable dada,
53462306a36Sopenharmony_ci     todos los accesos a la memoria que preceden a cualquier anterior
53562306a36Sopenharmony_ci     RELEASE en esa misma variable están garantizados como visibles. En
53662306a36Sopenharmony_ci     otras palabras, dentro de la sección crítica de una variable dada,
53762306a36Sopenharmony_ci     todos los accesos de todas las secciones críticas anteriores para esa
53862306a36Sopenharmony_ci     variable habrán terminado de forma garantizada.
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci     Esto significa que ACQUIRE actúa como una operación mínima de
54162306a36Sopenharmony_ci     "adquisición" y RELEASE actúa como una operación mínima de
54262306a36Sopenharmony_ci     "liberación".
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ciUn subconjunto de las operaciones atómicas descritas en atomic_t.txt
54562306a36Sopenharmony_cicontiene variantes de ACQUIRE y RELEASE, además de definiciones
54662306a36Sopenharmony_cicompletamente ordenadas o relajadas (sin barrera semántica). Para
54762306a36Sopenharmony_cicomposiciones atómicas que realizan tanto un load como store, la semántica
54862306a36Sopenharmony_ciACQUIRE se aplica solo a la carga y la semántica RELEASE se aplica sólo a
54962306a36Sopenharmony_cila parte de la operación del store.
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ciLas barreras de memoria solo son necesarias cuando existe la posibilidad de
55262306a36Sopenharmony_ciinteracción entre dos CPU o entre una CPU y un dispositivo. Si se puede
55362306a36Sopenharmony_cigarantizar que no habrá tal interacción en ninguna pieza de código en
55462306a36Sopenharmony_ciparticular, entonces las barreras de memoria son innecesarias en ese
55562306a36Sopenharmony_cifragmento de código.
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ciTenga en cuenta que estas son las garantías _mínimas_. Diferentes
55862306a36Sopenharmony_ciarquitecturas pueden proporcionar garantías más sustanciales, pero no se
55962306a36Sopenharmony_cipuede confiar en estas fuera de esa arquitectura en específico.
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci¿QUÉ NO SE PUEDE ASUMIR SOBRE LAS BARRERAS DE LA MEMORIA?
56362306a36Sopenharmony_ci---------------------------------------------------------
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ciHay ciertas cosas que las barreras de memoria del kernel Linux no
56662306a36Sopenharmony_cigarantizan:
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci (*) No hay garantía de que ninguno de los accesos a la memoria
56962306a36Sopenharmony_ci     especificados antes de una barrera de memoria estará _completo_ al
57062306a36Sopenharmony_ci     completarse una instrucción de barrera de memoria; se puede considerar
57162306a36Sopenharmony_ci     que la barrera dibuja una línea en la cola de acceso del CPU que no
57262306a36Sopenharmony_ci     pueden cruzar los accesos del tipo correspondiente.
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci (*) No hay garantía de que la emisión de una barrera de memoria en una CPU
57562306a36Sopenharmony_ci     tenga cualquier efecto directo en otra CPU o cualquier otro hardware
57662306a36Sopenharmony_ci     en el sistema. El efecto indirecto será el orden en que la segunda CPU
57762306a36Sopenharmony_ci     ve los efectos de los primeros accesos que ocurren de la CPU, pero lea
57862306a36Sopenharmony_ci     el siguiente argumento:
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci (*) No hay garantía de que una CPU vea el orden correcto de los efectos
58162306a36Sopenharmony_ci     de los accesos de una segunda CPU, incluso _si_ la segunda CPU usa una
58262306a36Sopenharmony_ci     barrera de memoria, a menos que la primera CPU _también_ use una
58362306a36Sopenharmony_ci     barrera de memoria coincidente (vea el subapartado "Emparejamiento de
58462306a36Sopenharmony_ci     barrera SMP").
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci (*) No hay garantía de que alguna pieza intermedia fuera del hardware[*]
58762306a36Sopenharmony_ci     del CPU no reordenará los accesos a la memoria. Los mecanismos de
58862306a36Sopenharmony_ci     coherencia de caché del CPU deben propagar los efectos indirectos de
58962306a36Sopenharmony_ci     una barrera de memoria entre las CPU, pero es posible que no lo hagan
59062306a36Sopenharmony_ci     en orden.
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	[*] Para obtener información sobre bus mastering DMA y coherencia, lea:
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	    Documentation/driver-api/pci/pci.rst
59562306a36Sopenharmony_ci	    Documentation/core-api/dma-api-howto.rst
59662306a36Sopenharmony_ci	    Documentation/core-api/dma-api.rst
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ciBARRERA DE DEPENDENCIA DE DIRECCIÓN (HISTÓRICO)
60062306a36Sopenharmony_ci-----------------------------------------------
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ciA partir de la versión 4.15 del kernel Linux, se agregó un smp_mb() a
60362306a36Sopenharmony_ciREAD_ONCE() para DEC Alpha, lo que significa que las únicas personas que
60462306a36Sopenharmony_cinecesitan prestar atención a esta sección son aquellas que trabajan en el
60562306a36Sopenharmony_cicódigo específico de la arquitectura DEC Alpha y aquellas que trabajan en
60662306a36Sopenharmony_ciREAD_ONCE() por dentro. Para aquellos que lo necesitan, y para aquellos que
60762306a36Sopenharmony_ciestén interesados desde un punto de vista histórico, aquí está la historia
60862306a36Sopenharmony_cide las barreras de dependencia de dirección.
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci[!] Si bien las dependencias de direcciones se observan tanto en carga a
61162306a36Sopenharmony_cicarga como en relaciones de carga a store, las barreras de dependencia de
61262306a36Sopenharmony_cidirección no son necesarias para situaciones de carga a store.
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ciEl requisito de las barreras de dependencia de dirección es un poco sutil,
61562306a36Sopenharmony_ciy no siempre es obvio que sean necesarias. Para ilustrar, considere la
61662306a36Sopenharmony_cisiguiente secuencia de eventos:
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	CPU 1		      CPU 2
61962306a36Sopenharmony_ci	===============	      ===============
62062306a36Sopenharmony_ci	{ A == 1, B == 2, C == 3, P == &A, Q == &C }
62162306a36Sopenharmony_ci	B = 4;
62262306a36Sopenharmony_ci	<barrera de escritura>
62362306a36Sopenharmony_ci	WRITE_ONCE(P, &B);
62462306a36Sopenharmony_ci			      Q = READ_ONCE_OLD(P);
62562306a36Sopenharmony_ci			      D = *Q;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci[!] READ_ONCE_OLD() corresponde a READ_ONCE() del kernel anterior a 4.15,
62862306a36Sopenharmony_cique no implica una barrera de dependencia de direcciones.
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ciHay una clara dependencia de dirección aquí, y parecería que al final de
63162306a36Sopenharmony_cila secuencia, Q debe ser &A o &B, y que:
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	(Q == &A) implica (D == 1)
63462306a36Sopenharmony_ci	(Q == &B) implica (D == 4)
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci¡Pero! La percepción de la CPU 2 de P puede actualizarse _antes_ de su
63762306a36Sopenharmony_cipercepción de B, por lo tanto dando lugar a la siguiente situación:
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	(Q == &B) y (D == 2) ????
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ciSi bien esto puede parecer una falla en el mantenimiento de la coherencia
64262306a36Sopenharmony_cio la causalidad, no lo es, y este comportamiento se puede observar en
64362306a36Sopenharmony_ciciertas CPU reales (como DEC Alfa).
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ciPara lidiar con esto, READ_ONCE() proporciona una barrera de dependencia
64662306a36Sopenharmony_cide dirección implícita desde el lanzamiento del kernel v4.15:
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	CPU 1		      CPU 2
64962306a36Sopenharmony_ci	===============	      ===============
65062306a36Sopenharmony_ci	{ A == 1, B == 2, C == 3, P == &A, Q == &C }
65162306a36Sopenharmony_ci	B = 4;
65262306a36Sopenharmony_ci	<barrera de escritura>
65362306a36Sopenharmony_ci	WRITE_ONCE(P, &B);
65462306a36Sopenharmony_ci			      Q = READ_ONCE(P);
65562306a36Sopenharmony_ci			      <barrera de dependencia de dirección implícita>
65662306a36Sopenharmony_ci			      D = *Q;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ciEsto refuerza la ocurrencia de una de las dos implicaciones, y previene la
65962306a36Sopenharmony_citercera posibilidad de surgir.
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci[!] Tenga en cuenta que esta situación extremadamente contraria a la
66362306a36Sopenharmony_ciintuición surge más fácilmente en máquinas con cachés divididos, de modo
66462306a36Sopenharmony_cique, por ejemplo, un banco de caché procesa líneas de caché pares y el otro
66562306a36Sopenharmony_cibanco procesa líneas impares de caché. El puntero P podría almacenarse en
66662306a36Sopenharmony_ciuna línea de caché impar y la variable B podría almacenarse en una línea de
66762306a36Sopenharmony_cicaché con número par. Entonces, si el banco de números pares de la memoria
66862306a36Sopenharmony_cicaché de la CPU de lectura está extremadamente ocupado mientras que el
66962306a36Sopenharmony_cibanco impar está inactivo, uno podría ver el nuevo valor del puntero P
67062306a36Sopenharmony_ci(&B), pero el antiguo valor de la variable B (2).
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ciNo se requiere una barrera de dependencia de dirección para ordenar
67462306a36Sopenharmony_ciescrituras dependientes porque las CPU que admite el kernel Linux no
67562306a36Sopenharmony_ciescriben hasta que están seguros (1) de que la escritura realmente
67662306a36Sopenharmony_cisucederá, (2) de la ubicación de la escritura, y (3) del valor a escribir.
67762306a36Sopenharmony_ciPero, por favor, lea atentamente la sección "DEPENDENCIAS DEL CONTROL" y el
67862306a36Sopenharmony_ciarchivo Documentation/RCU/rcu_dereference.rst: el compilador puede romperse
67962306a36Sopenharmony_ciy romper dependencias en muchas formas altamente creativas.
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	CPU 1		      CPU 2
68262306a36Sopenharmony_ci	===============	      ===============
68362306a36Sopenharmony_ci	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
68462306a36Sopenharmony_ci	B = 4;
68562306a36Sopenharmony_ci	<barrera de escritura>
68662306a36Sopenharmony_ci	WRITE_ONCE(P, &B);
68762306a36Sopenharmony_ci			      Q = READ_ONCE_OLD(P);
68862306a36Sopenharmony_ci			      WRITE_ONCE(*Q, 5);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ciPor lo tanto, no se requiere ninguna barrera de dependencia de direcciones
69162306a36Sopenharmony_cipara ordenar la lectura en Q con el load en *Q. En otras palabras, este
69262306a36Sopenharmony_ciresultado está prohibido, incluso sin una barrera de dependencia de
69362306a36Sopenharmony_cidirección implícita del READ_ONCE() moderno:
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	(Q == &B) && (B == 4)
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ciTenga en cuenta que este patrón debe ser raro. Después de todo, el objetivo
69862306a36Sopenharmony_cidel orden de dependencia es -prevenir- escrituras en la estructura de
69962306a36Sopenharmony_cidatos, junto con los costosos errores de caché asociados con tales
70062306a36Sopenharmony_ciescrituras. Este patrón se puede utilizar para registrar raras condiciones
70162306a36Sopenharmony_cide error y similares, y el orden natural de las CPUs evita que se pierdan
70262306a36Sopenharmony_citales registros.
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ciTenga en cuenta que el orden proporcionado por una dependencia de dirección
70662306a36Sopenharmony_cies local para la CPU que lo contiene. Lea la sección sobre "Atomicidad
70762306a36Sopenharmony_cimulticopia" para más información.
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ciLa barrera de dependencia de dirección es muy importante para el sistema
71162306a36Sopenharmony_ciRCU, por ejemplo. Vea rcu_assign_pointer() y rcu_dereference() en
71262306a36Sopenharmony_ciinclude/linux/rcupdate.h. Esto permite que el objetivo actual de un puntero
71362306a36Sopenharmony_ciRCU sea reemplazado con un nuevo objetivo modificado, sin que el objetivo
71462306a36Sopenharmony_cidel reemplazo parezca estar inicializado de manera incompleta.
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ciConsulte también la subsección sobre "Coherencia de caché" para obtener un
71762306a36Sopenharmony_ciejemplo más completo.
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ciDEPENDENCIAS DE CONTROL
72062306a36Sopenharmony_ci-----------------------
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ciLas dependencias de control pueden ser un poco complicadas porque los
72362306a36Sopenharmony_cicompiladores actuales no las entienden. El propósito de esta sección es
72462306a36Sopenharmony_ciayudarle a prevenir que la ignorancia del compilador rompa su código.
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ciUna dependencia de control load-load (de carga a carga) requiere una
72762306a36Sopenharmony_cibarrera de memoria de lectura completa, no simplemente una barrera
72862306a36Sopenharmony_ci(implícita) de dependencia de direcciones para que funcione correctamente.
72962306a36Sopenharmony_ciConsidere el siguiente fragmento de código:
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	q = READ_ONCE(a);
73262306a36Sopenharmony_ci	<barrera implícita de dependencia de direcciones>
73362306a36Sopenharmony_ci	if (q) {
73462306a36Sopenharmony_ci		/* BUG: No hay dependencia de dirección!!! */
73562306a36Sopenharmony_ci		p = READ_ONCE(b);
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ciEsto no tendrá el efecto deseado porque no hay una dependencia de dirección
73962306a36Sopenharmony_cireal, sino más bien una dependencia de control que la CPU puede
74062306a36Sopenharmony_cicortocircuitar al intentar predecir el resultado por adelantado, para que
74162306a36Sopenharmony_ciotras CPU vean la carga de b como si hubiera ocurrido antes que la carga de
74262306a36Sopenharmony_cia. En cuyo caso lo que realmente se requiere es:
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci  	q = READ_ONCE(a);
74562306a36Sopenharmony_ci  	if (q) {
74662306a36Sopenharmony_ci  		<barrera de lectura>
74762306a36Sopenharmony_ci  		p = READ_ONCE(b);
74862306a36Sopenharmony_ci  	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ciSin embargo, los stores no se especulan. Esto significa que ordenar -es-
75162306a36Sopenharmony_ciprovisto para dependencias de control de load-store, como en el siguiente
75262306a36Sopenharmony_ciejemplo:
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	q = READ_ONCE(a);
75562306a36Sopenharmony_ci	if (q) {
75662306a36Sopenharmony_ci		WRITE_ONCE(b, 1);
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ciLas dependencias de control se emparejan normalmente con otros tipos de
76062306a36Sopenharmony_cibarreras. Dicho esto, tenga en cuenta que ni READ_ONCE() ni WRITE_ONCE()
76162306a36Sopenharmony_cison opcionales! Sin READ_ONCE(), el compilador podría combinar la carga de
76262306a36Sopenharmony_ci'a' con otras cargas de 'a'. Sin WRITE_ONCE(), el compilador podría
76362306a36Sopenharmony_cicombinar el store de 'b' con otros stores de 'b'. Cualquiera de estos casos
76462306a36Sopenharmony_cipuede dar lugar a efectos en el orden muy contrarios a la intuición.
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ciPeor aún, si el compilador puede probar (decir) que el valor de la
76762306a36Sopenharmony_civariable 'a' siempre es distinta de cero, estaría dentro de sus derechos
76862306a36Sopenharmony_cipara optimizar el ejemplo original eliminando la declaración "if", como:
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	q = a;
77162306a36Sopenharmony_ci	b = 1;  /* BUG: Compilador y CPU pueden ambos reordernar!!! */
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ciAsí que no deje de lado READ_ONCE().
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ciEs tentador tratar de hacer cumplir el orden en stores idénticos en ambos
77662306a36Sopenharmony_cicaminos del "if" de la siguiente manera:
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	q = READ_ONCE(a);
77962306a36Sopenharmony_ci	if (q) {
78062306a36Sopenharmony_ci		barrier();
78162306a36Sopenharmony_ci		WRITE_ONCE(b, 1);
78262306a36Sopenharmony_ci		hacer_algo();
78362306a36Sopenharmony_ci	} else {
78462306a36Sopenharmony_ci		barrier();
78562306a36Sopenharmony_ci		WRITE_ONCE(b, 1);
78662306a36Sopenharmony_ci		hacer_otra_cosa();
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ciDesafortunadamente, los compiladores actuales transformarán esto de la
79062306a36Sopenharmony_cisiguiente manera en casos de alto nivel de optimización:
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci  	q = READ_ONCE(a);
79362306a36Sopenharmony_ci  	barrier();
79462306a36Sopenharmony_ci  	WRITE_ONCE(b, 1);  /* BUG: No hay orden en load de a!!! */
79562306a36Sopenharmony_ci  	if (q) {
79662306a36Sopenharmony_ci  		/* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
79762306a36Sopenharmony_ci  		hacer_algo();
79862306a36Sopenharmony_ci  	} else {
79962306a36Sopenharmony_ci  		/* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
80062306a36Sopenharmony_ci  		hacer_otra_cosa();
80162306a36Sopenharmony_ci  	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ciAhora no hay condicional entre la carga de 'a' y el store de 'b', lo que
80462306a36Sopenharmony_cisignifica que la CPU está en su derecho de reordenarlos: El condicional es
80562306a36Sopenharmony_ciabsolutamente necesario y debe estar presente en el código ensamblador
80662306a36Sopenharmony_ciincluso después de que se hayan aplicado todas las optimizaciones del
80762306a36Sopenharmony_cicompilador. Por lo tanto, si necesita ordenar en este ejemplo, necesita
80862306a36Sopenharmony_ciexplícitamente barreras de memoria, por ejemplo, smp_store_release():
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	q = READ_ONCE(a);
81262306a36Sopenharmony_ci	if (q) {
81362306a36Sopenharmony_ci		smp_store_release(&b, 1);
81462306a36Sopenharmony_ci		hacer_algo();
81562306a36Sopenharmony_ci	} else {
81662306a36Sopenharmony_ci		smp_store_release(&b, 1);
81762306a36Sopenharmony_ci		hacer_otra_cosa();
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ciPor el contrario, sin barreras de memoria explícita, el control de un if
82162306a36Sopenharmony_cicon dos opciones está garantizado solo cuando los stores difieren, por
82262306a36Sopenharmony_ciejemplo:
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci  	q = READ_ONCE(a);
82562306a36Sopenharmony_ci  	if (q) {
82662306a36Sopenharmony_ci  		WRITE_ONCE(b, 1);
82762306a36Sopenharmony_ci  		hacer_algo();
82862306a36Sopenharmony_ci  	} else {
82962306a36Sopenharmony_ci  		WRITE_ONCE(b, 2);
83062306a36Sopenharmony_ci  		hacer_otra_cosa();
83162306a36Sopenharmony_ci  	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ciAún se requiere el inicial READ_ONCE() para evitar que el compilador toque
83462306a36Sopenharmony_ciel valor de 'a'.
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ciAdemás, debe tener cuidado con lo que hace con la variable local 'q', de lo
83762306a36Sopenharmony_cicontrario, el compilador podría adivinar el valor y volver a eliminar el
83862306a36Sopenharmony_cinecesario condicional. Por ejemplo:
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci  	q = READ_ONCE(a);
84162306a36Sopenharmony_ci  	if (q % MAX) {
84262306a36Sopenharmony_ci  		WRITE_ONCE(b, 1);
84362306a36Sopenharmony_ci  		hacer_algo();
84462306a36Sopenharmony_ci  	} else {
84562306a36Sopenharmony_ci  		WRITE_ONCE(b, 2);
84662306a36Sopenharmony_ci  		hacer_otra_cosa();
84762306a36Sopenharmony_ci  	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ciSi MAX se define como 1, entonces el compilador sabe que (q % MAX) es igual
85062306a36Sopenharmony_cia cero, en cuyo caso el compilador tiene derecho a transformar el código
85162306a36Sopenharmony_cianterior en el siguiente:
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci  	q = READ_ONCE(a);
85462306a36Sopenharmony_ci  	WRITE_ONCE(b, 2);
85562306a36Sopenharmony_ci  	hacer_otra_cosa();
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ciDada esta transformación, la CPU no está obligada a respetar el orden entre
85862306a36Sopenharmony_cila carga de la variable 'a' y el store de la variable 'b'. Es tentador
85962306a36Sopenharmony_ciagregar una barrier(), pero esto no ayuda. El condicional se ha ido, y la
86062306a36Sopenharmony_cibarrera no lo traerá de vuelta. Por lo tanto, si confia en este orden, debe
86162306a36Sopenharmony_ciasegurarse de que MAX sea mayor que uno, tal vez de la siguiente manera:
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci  	q = READ_ONCE(a);
86462306a36Sopenharmony_ci  	BUILD_BUG_ON(MAX <= 1); /* Orden de carga de a con store de b */
86562306a36Sopenharmony_ci  	if (q % MAX) {
86662306a36Sopenharmony_ci  		WRITE_ONCE(b, 1);
86762306a36Sopenharmony_ci  		hacer_algo();
86862306a36Sopenharmony_ci  	} else {
86962306a36Sopenharmony_ci  		WRITE_ONCE(b, 2);
87062306a36Sopenharmony_ci  		hacer_otra_cosa();
87162306a36Sopenharmony_ci  	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ciTenga en cuenta una vez más que los stores de 'b' difieren. Si fueran
87462306a36Sopenharmony_ciidénticos, como se señaló anteriormente, el compilador podría sacar ese
87562306a36Sopenharmony_cistore fuera de la declaración 'if'.
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ciTambién debe tener cuidado de no confiar demasiado en el cortocircuito
87862306a36Sopenharmony_cide la evaluación booleana. Considere este ejemplo:
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci  	q = READ_ONCE(a);
88162306a36Sopenharmony_ci  	if (q || 1 > 0)
88262306a36Sopenharmony_ci  	WRITE_ONCE(b, 1);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ciDebido a que la primera condición no puede fallar y la segunda condición es
88562306a36Sopenharmony_cisiempre cierta, el compilador puede transformar este ejemplo de la
88662306a36Sopenharmony_cisiguiente manera, rompiendo la dependencia del control:
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci  	q = READ_ONCE(a);
88962306a36Sopenharmony_ci  	WRITE_ONCE(b, 1);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ciEste ejemplo subraya la necesidad de asegurarse de que el compilador no
89262306a36Sopenharmony_cipueda adivinar su código. Más generalmente, aunque READ_ONCE() fuerza
89362306a36Sopenharmony_cial compilador para emitir código para una carga dada, no fuerza al
89462306a36Sopenharmony_cicompilador para usar los resultados.
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ciAdemás, las dependencias de control se aplican solo a la cláusula then y
89762306a36Sopenharmony_cila cláusula else de la sentencia if en cuestión. En particular, no se
89862306a36Sopenharmony_ciaplica necesariamente al código que sigue a la declaración if:
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci  	q = READ_ONCE(a);
90162306a36Sopenharmony_ci  	if (q) {
90262306a36Sopenharmony_ci  		WRITE_ONCE(b, 1);
90362306a36Sopenharmony_ci  	} else {
90462306a36Sopenharmony_ci  		WRITE_ONCE(b, 2);
90562306a36Sopenharmony_ci  	}
90662306a36Sopenharmony_ci  	WRITE_ONCE(c, 1);  /* BUG: No hay orden para la lectura de 'a'. */
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ciEs tentador argumentar que, de hecho, existe un orden porque el compilador
90962306a36Sopenharmony_cino puede reordenar accesos volátiles y tampoco puede reordenar escrituras
91062306a36Sopenharmony_cien 'b' con la condición. Desafortunadamente para esta línea de
91162306a36Sopenharmony_cirazonamiento, el compilador podría compilar las dos escrituras en 'b' como
91262306a36Sopenharmony_ciinstrucciones de movimiento condicional, como en este fantástico idioma
91362306a36Sopenharmony_cipseudo-ensamblador:
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci        	ld r1,a
91662306a36Sopenharmony_ci        	cmp r1,$0
91762306a36Sopenharmony_ci        	cmov,ne r4,$1
91862306a36Sopenharmony_ci        	cmov,eq r4,$2
91962306a36Sopenharmony_ci        	st r4,b
92062306a36Sopenharmony_ci        	st $1,c
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ciUna CPU débilmente ordenada no tendría dependencia de ningún tipo entre la
92362306a36Sopenharmony_cicarga de 'a' y el store de 'c'. Las dependencias de control se extenderían
92462306a36Sopenharmony_cisolo al par de instrucciones cmov y el store dependiente de ellas. En
92562306a36Sopenharmony_ciresumen, las dependencias de control se aplican solo a los stores en la
92662306a36Sopenharmony_cicláusula then y la cláusula else de la sentencia if en cuestión (incluidas
92762306a36Sopenharmony_cilas funciones invocado por esas dos cláusulas), no al código que sigue a
92862306a36Sopenharmony_ciesa declaración if.
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ciTenga muy en cuenta que el orden proporcionado por una dependencia de
93262306a36Sopenharmony_cicontrol es local a la CPU que lo contiene. Vea el apartado de "Atomicidad
93362306a36Sopenharmony_cimulticopia" para más información.
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ciEn resumen:
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci  (*) Las dependencias de control pueden ordenar cargas anteriores para
93962306a36Sopenharmony_ci      stores posteriores. Sin embargo, no garantizan ningún otro tipo de
94062306a36Sopenharmony_ci      orden: No cargas previas contra cargas posteriores, ni
94162306a36Sopenharmony_ci      almacenamientos previos y luego nada. Si necesita tales formas de
94262306a36Sopenharmony_ci      orden, use smp_rmb(), smp_wmb() o, en el caso de stores anteriores y
94362306a36Sopenharmony_ci      cargas posteriores, smp_mb().
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci  (*) Si ambos caminos de la declaración "if" comienzan con stores
94662306a36Sopenharmony_ci      idénticos de la misma variable, entonces esos stores deben ser
94762306a36Sopenharmony_ci      ordenados, ya sea precediéndoles a ambos con smp_mb() o usando
94862306a36Sopenharmony_ci      smp_store_release() para realizar el store. Tenga en cuenta que -no-
94962306a36Sopenharmony_ci      es suficiente usar barrier() al comienzo de cada caso de la
95062306a36Sopenharmony_ci      declaración "if" porque, como se muestra en el ejemplo anterior, la
95162306a36Sopenharmony_ci      optimización de los compiladores puede destruir la dependencia de
95262306a36Sopenharmony_ci      control respetando al pie de la letra la ley de barrier().
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci  (*) Las dependencias de control requieren al menos un condicional en
95562306a36Sopenharmony_ci      tiempo de ejecución entre la carga anterior y el almacenamiento
95662306a36Sopenharmony_ci      posterior, y este condicional debe implicar la carga previa. Si el
95762306a36Sopenharmony_ci      compilador es capaz de optimizar el condicional y quitarlo, también
95862306a36Sopenharmony_ci      habrá optimizado el ordenar. El uso cuidadoso de READ_ONCE() y
95962306a36Sopenharmony_ci      WRITE_ONCE() puede ayudar a preservar el necesario condicional.
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci  (*) Las dependencias de control requieren que el compilador evite
96262306a36Sopenharmony_ci      reordenar las dependencia hasta su inexistencia. El uso cuidadoso de
96362306a36Sopenharmony_ci      READ_ONCE() o atomic{,64}_read() puede ayudarle a preservar la
96462306a36Sopenharmony_ci      dependencia de control. Consulte la sección BARRERA DEL COMPILADOR
96562306a36Sopenharmony_ci      para obtener más información al respecto.
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci  (*) Las dependencias de control se aplican solo a la cláusula then y la
96862306a36Sopenharmony_ci      cláusula else de la sentencia "if" que contiene la dependencia de
96962306a36Sopenharmony_ci      control, incluyendo cualquier función a la que llamen dichas dos
97062306a36Sopenharmony_ci      cláusulas. Las dependencias de control no se aplican al código que
97162306a36Sopenharmony_ci      sigue a la instrucción if que contiene la dependencia de control.
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci  (*) Las dependencias de control se emparejan normalmente con otros tipos
97462306a36Sopenharmony_ci      de barreras.
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci  (*) Las dependencias de control no proporcionan atomicidad multicopia. Si
97762306a36Sopenharmony_ci      usted necesita todas las CPU para ver un store dado al mismo tiempo,
97862306a36Sopenharmony_ci      emplee smp_mb().
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci  (*) Los compiladores no entienden las dependencias de control. Por lo
98162306a36Sopenharmony_ci      tanto es su trabajo asegurarse de que no rompan su código.
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ciEMPAREJAMIENTO DE BARRERAS SMP
98562306a36Sopenharmony_ci------------------------------
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ciCuando se trata de interacciones CPU-CPU, ciertos tipos de barrera de
98862306a36Sopenharmony_cimemoria deben estar siempre emparejados. La falta del apropiado
98962306a36Sopenharmony_ciemparejamiento es casi seguro un error.
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ciLas barreras generales se emparejan entre sí, aunque también se emparejan
99262306a36Sopenharmony_cicon la mayoría de otro tipo de barreras, aunque sin atomicidad multicopia.
99362306a36Sopenharmony_ciUna barrera de adquisición se empareja con una barrera de liberación, pero
99462306a36Sopenharmony_ciambas también pueden emparejarse con otras barreras, incluidas, por
99562306a36Sopenharmony_cisupuesto, las barreras generales. Una barrera de escritura se empareja con
99662306a36Sopenharmony_ciuna barrera de dependencia de dirección, una dependencia de control, una
99762306a36Sopenharmony_cibarrera de adquisición, una barrera de liberación, una barrera de lectura
99862306a36Sopenharmony_cio una barrera general. Del mismo modo, una barrera de lectura se empareja
99962306a36Sopenharmony_cicon una de dependencia de control o barrera de dependencia de dirección con
100062306a36Sopenharmony_ciuna barrera de escritura, una barrera de adquisición, una barrera de
100162306a36Sopenharmony_ciliberación o una barrera general:
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	CPU 1		      CPU 2
100462306a36Sopenharmony_ci	===============	      ===============
100562306a36Sopenharmony_ci	WRITE_ONCE(a, 1);
100662306a36Sopenharmony_ci	<barrera de escritura>
100762306a36Sopenharmony_ci	WRITE_ONCE(b, 2);     x = READ_ONCE(b);
100862306a36Sopenharmony_ci			      <barrera de lectura>
100962306a36Sopenharmony_ci			      y = READ_ONCE(a);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ciO bien:
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	CPU 1		      CPU 2
101462306a36Sopenharmony_ci	===============	      ===============================
101562306a36Sopenharmony_ci	a = 1;
101662306a36Sopenharmony_ci	<barrera de escritura>
101762306a36Sopenharmony_ci	WRITE_ONCE(b, &a);    x = READ_ONCE(b);
101862306a36Sopenharmony_ci			      <barrera de dependencia de dirección implícita>
101962306a36Sopenharmony_ci			      y = *x;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ciO incluso:
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	CPU 1		      CPU 2
102462306a36Sopenharmony_ci	===============	      ===============================
102562306a36Sopenharmony_ci	r1 = READ_ONCE(y);
102662306a36Sopenharmony_ci	<barrera general>
102762306a36Sopenharmony_ci	WRITE_ONCE(x, 1);     if (r2 = READ_ONCE(x)) {
102862306a36Sopenharmony_ci			         <barrera de control implícita>
102962306a36Sopenharmony_ci			         WRITE_ONCE(y, 1);
103062306a36Sopenharmony_ci			      }
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	assert(r1 == 0 || r2 == 0);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ciBásicamente, la barrera de lectura siempre tiene que estar ahí, aunque
103562306a36Sopenharmony_cipuede ser del tipo "más débil".
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci[!] Tenga en cuenta que normalmente se esperaría que los stores antes de la
103862306a36Sopenharmony_cibarrera de escritura se hagan coincidir con los stores después de la
103962306a36Sopenharmony_cibarrera de lectura o la barrera de dependencia de dirección, y viceversa:
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	CPU 1                               CPU 2
104262306a36Sopenharmony_ci	===================                 ===================
104362306a36Sopenharmony_ci	WRITE_ONCE(a, 1);    }----   --->{  v = READ_ONCE(c);
104462306a36Sopenharmony_ci	WRITE_ONCE(b, 2);    }    \ /    {  w = READ_ONCE(d);
104562306a36Sopenharmony_ci	<barrera de escritura>            \        <barrera de lectura>
104662306a36Sopenharmony_ci	WRITE_ONCE(c, 3);    }    / \    {  x = READ_ONCE(a);
104762306a36Sopenharmony_ci	WRITE_ONCE(d, 4);    }----   --->{  y = READ_ONCE(b);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ciEJEMPLOS DE SECUENCIAS DE BARRERA DE MEMORIA
105162306a36Sopenharmony_ci--------------------------------------------
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ciEn primer lugar, las barreras de escritura actúan como orden parcial en las
105462306a36Sopenharmony_cioperaciones de store. Considere la siguiente secuencia de eventos:
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	CPU 1
105762306a36Sopenharmony_ci	=======================
105862306a36Sopenharmony_ci	STORE A = 1
105962306a36Sopenharmony_ci	STORE B = 2
106062306a36Sopenharmony_ci	STORE C = 3
106162306a36Sopenharmony_ci	<barrera de escritura>
106262306a36Sopenharmony_ci	STORE D = 4
106362306a36Sopenharmony_ci	STORE E = 5
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ciEsta secuencia de eventos es finalizado para con el sistema de coherencia
106662306a36Sopenharmony_cide memoria en un orden que el resto del sistema podría percibir como el
106762306a36Sopenharmony_ciconjunto desordenado { STORE A, STORE B, STORE C} todo ocurriendo antes del
106862306a36Sopenharmony_ciconjunto desordenado { STORE D, STORE E}:
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	+-------+       :      :
107262306a36Sopenharmony_ci	|       |       +------+
107362306a36Sopenharmony_ci	|       |------>| C=3  |     }     /\
107462306a36Sopenharmony_ci	|       |  :    +------+     }-----  \  -----> Eventos perceptibles para
107562306a36Sopenharmony_ci	|       |  :    | A=1  |     }        \/       el resto del sistema
107662306a36Sopenharmony_ci	|       |  :    +------+     }
107762306a36Sopenharmony_ci	| CPU 1 |  :    | B=2  |     }
107862306a36Sopenharmony_ci	|       |       +------+     }
107962306a36Sopenharmony_ci	|       |   wwwwwwwwwwwwwwww }   <--- En este momento la barrera de
108062306a36Sopenharmony_ci	|       |       +------+     }        escritura requiere que todos los
108162306a36Sopenharmony_ci	|       |  :    | E=5  |     }        stores anteriores a la barrera
108262306a36Sopenharmony_ci	|       |  :    +------+     }        sean confirmados antes de que otros
108362306a36Sopenharmony_ci	|       |------>| D=4  |     }        store puedan suceder
108462306a36Sopenharmony_ci	|       |       +------+
108562306a36Sopenharmony_ci	+-------+       :      :
108662306a36Sopenharmony_ci	                   |
108762306a36Sopenharmony_ci	                   | Secuencia por la cual los stores son confirmados al
108862306a36Sopenharmony_ci	                   | sistema de memoria por parte del CPU 1
108962306a36Sopenharmony_ci	                   V
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ciEn segundo lugar, las barreras de dependencia de dirección actúan como
109262306a36Sopenharmony_ciórdenes parciales sobre la dirección de cargas dependientes. Considere la
109362306a36Sopenharmony_cisiguiente secuencia de eventos:
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	CPU 1			CPU 2
109662306a36Sopenharmony_ci	=======================	=======================
109762306a36Sopenharmony_ci		{ B = 7; X = 9; Y = 8; C = &Y }
109862306a36Sopenharmony_ci	STORE A = 1
109962306a36Sopenharmony_ci	STORE B = 2
110062306a36Sopenharmony_ci	<barrera de escritura>
110162306a36Sopenharmony_ci	STORE C = &B		LOAD X
110262306a36Sopenharmony_ci	STORE D = 4		LOAD C (consigue &B)
110362306a36Sopenharmony_ci				LOAD *C (lee B)
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ciSin intervención, la CPU 2 puede percibir los eventos en la CPU 1 en orden
110662306a36Sopenharmony_cialeatorio a efectos prácticos, a pesar de la barrera de escritura emitida
110762306a36Sopenharmony_cipor la CPU 1:
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	+-------+       :      :                :       :
111062306a36Sopenharmony_ci	|       |       +------+                +-------+  | Secuencia de
111162306a36Sopenharmony_ci	|       |------>| B=2  |-----       --->| Y->8  |  | actualizado de
111262306a36Sopenharmony_ci	|       |  :    +------+     \          +-------+  | percepción en CPU 2
111362306a36Sopenharmony_ci	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |  V
111462306a36Sopenharmony_ci	|       |       +------+       |        +-------+
111562306a36Sopenharmony_ci	|       |   wwwwwwwwwwwwwwww   |        :       :
111662306a36Sopenharmony_ci	|       |       +------+       |        :       :
111762306a36Sopenharmony_ci	|       |  :    | C=&B |---    |        :       :       +-------+
111862306a36Sopenharmony_ci	|       |  :    +------+   \   |        +-------+       |       |
111962306a36Sopenharmony_ci	|       |------>| D=4  |    ----------->| C->&B |------>|       |
112062306a36Sopenharmony_ci	|       |       +------+       |        +-------+       |       |
112162306a36Sopenharmony_ci	+-------+       :      :       |        :       :       |       |
112262306a36Sopenharmony_ci	                               |        :       :       |       |
112362306a36Sopenharmony_ci	                               |        :       :       | CPU 2 |
112462306a36Sopenharmony_ci	                               |        +-------+       |       |
112562306a36Sopenharmony_ci	    Percepción de B      --->  |        | B->7  |------>|       |
112662306a36Sopenharmony_ci	    aparentemente incorrecta!  |        +-------+       |       |
112762306a36Sopenharmony_ci	                               |        :       :       |       |
112862306a36Sopenharmony_ci	                               |        +-------+       |       |
112962306a36Sopenharmony_ci	    La carga de X frena --->    \       | X->9  |------>|       |
113062306a36Sopenharmony_ci	    el mantenimiento de          \      +-------+       |       |
113162306a36Sopenharmony_ci	    la coherencia de B            ----->| B->2  |       +-------+
113262306a36Sopenharmony_ci	                                        +-------+
113362306a36Sopenharmony_ci	                                        :       :
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ciEn el ejemplo anterior, la CPU 2 percibe que B es 7, a pesar de la carga de
113762306a36Sopenharmony_ci*C (que sería B) viniendo después del LOAD de C.
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ciSin embargo, si se colocara una barrera de dependencia de dirección entre
114062306a36Sopenharmony_cila carga de C y la carga de *C (es decir: B) en la CPU 2:
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	CPU 1			CPU 2
114362306a36Sopenharmony_ci	=======================	=======================
114462306a36Sopenharmony_ci		{ B = 7; X = 9; Y = 8; C = &Y }
114562306a36Sopenharmony_ci	STORE A = 1
114662306a36Sopenharmony_ci	STORE B = 2
114762306a36Sopenharmony_ci	<barrera de escritura>
114862306a36Sopenharmony_ci	STORE C = &B		LOAD X
114962306a36Sopenharmony_ci	STORE D = 4		LOAD C (consigue &B)
115062306a36Sopenharmony_ci				<barrera de dependencia de dirección>
115162306a36Sopenharmony_ci				LOAD *C (reads B)
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cientonces ocurrirá lo siguiente:
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	+-------+       :      :                :       :
115662306a36Sopenharmony_ci	|       |       +------+                +-------+
115762306a36Sopenharmony_ci	|       |------>| B=2  |-----       --->| Y->8  |
115862306a36Sopenharmony_ci	|       |  :    +------+     \          +-------+
115962306a36Sopenharmony_ci	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |
116062306a36Sopenharmony_ci	|       |       +------+       |        +-------+
116162306a36Sopenharmony_ci	|       |   wwwwwwwwwwwwwwww   |        :       :
116262306a36Sopenharmony_ci	|       |       +------+       |        :       :
116362306a36Sopenharmony_ci	|       |  :    | C=&B |---    |        :       :       +-------+
116462306a36Sopenharmony_ci	|       |  :    +------+   \   |        +-------+       |       |
116562306a36Sopenharmony_ci	|       |------>| D=4  |    ----------->| C->&B |------>|       |
116662306a36Sopenharmony_ci	|       |       +------+       |        +-------+       |       |
116762306a36Sopenharmony_ci	+-------+       :      :       |        :       :       |       |
116862306a36Sopenharmony_ci	                               |        :       :       |       |
116962306a36Sopenharmony_ci	                               |        :       :       | CPU 2 |
117062306a36Sopenharmony_ci	                               |        +-------+       |       |
117162306a36Sopenharmony_ci	                               |        | X->9  |------>|       |
117262306a36Sopenharmony_ci	                               |        +-------+       |       |
117362306a36Sopenharmony_ci	  Se asegura de que      --->   \   aaaaaaaaaaaaaaaaa   |       |
117462306a36Sopenharmony_ci	  los efectos anteriores al      \      +-------+       |       |
117562306a36Sopenharmony_ci	  store de C sean percibidos      ----->| B->2  |------>|       |
117662306a36Sopenharmony_ci	  por los siguientes loads              +-------+       |       |
117762306a36Sopenharmony_ci	                                        :       :       +-------+
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ciY en tercer lugar, una barrera de lectura actúa como un orden parcial sobre
118162306a36Sopenharmony_cilas cargas. Considere la siguiente secuencia de eventos:
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	CPU 1			CPU 2
118462306a36Sopenharmony_ci	=======================	=======================
118562306a36Sopenharmony_ci		{ A = 0, B = 9 }
118662306a36Sopenharmony_ci	STORE A=1
118762306a36Sopenharmony_ci	<barrera de escritura>
118862306a36Sopenharmony_ci	STORE B=2
118962306a36Sopenharmony_ci				LOAD B
119062306a36Sopenharmony_ci				LOAD A
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ciSin intervención, la CPU 2 puede elegir percibir los eventos en la CPU 1 en
119362306a36Sopenharmony_cialgún orden aleatorio a efectos prácticos, a pesar de la barrera de
119462306a36Sopenharmony_ciescritura emitida por la CPU 1:
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	+-------+       :      :                :       :
119762306a36Sopenharmony_ci	|       |       +------+                +-------+
119862306a36Sopenharmony_ci	|       |------>| A=1  |------      --->| A->0  |
119962306a36Sopenharmony_ci	|       |       +------+      \         +-------+
120062306a36Sopenharmony_ci	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
120162306a36Sopenharmony_ci	|       |       +------+        |       +-------+
120262306a36Sopenharmony_ci	|       |------>| B=2  |---     |       :       :
120362306a36Sopenharmony_ci	|       |       +------+   \    |       :       :       +-------+
120462306a36Sopenharmony_ci	+-------+       :      :    \   |       +-------+       |       |
120562306a36Sopenharmony_ci	                             ---------->| B->2  |------>|       |
120662306a36Sopenharmony_ci	                                |       +-------+       | CPU 2 |
120762306a36Sopenharmony_ci	                                |       | A->0  |------>|       |
120862306a36Sopenharmony_ci	                                |       +-------+       |       |
120962306a36Sopenharmony_ci	                                |       :       :       +-------+
121062306a36Sopenharmony_ci	                                 \      :       :
121162306a36Sopenharmony_ci	                                  \     +-------+
121262306a36Sopenharmony_ci	                                   ---->| A->1  |
121362306a36Sopenharmony_ci	                                        +-------+
121462306a36Sopenharmony_ci	                                        :       :
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ciSin embargo, si se colocara una barrera de lectura entre la carga de B y la
121762306a36Sopenharmony_cicarga de A en la CPU 2:
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	CPU 1			CPU 2
122062306a36Sopenharmony_ci	=======================	=======================
122162306a36Sopenharmony_ci		{ A = 0, B = 9 }
122262306a36Sopenharmony_ci	STORE A=1
122362306a36Sopenharmony_ci	<barrera de escritura>
122462306a36Sopenharmony_ci	STORE B=2
122562306a36Sopenharmony_ci				LOAD B
122662306a36Sopenharmony_ci				<barrera de lectura>
122762306a36Sopenharmony_ci				LOAD A
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cientonces el orden parcial impuesto por la CPU 1 será percibido
123062306a36Sopenharmony_cicorrectamente por la CPU 2:
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	+-------+       :      :                :       :
123362306a36Sopenharmony_ci	|       |       +------+                +-------+
123462306a36Sopenharmony_ci	|       |------>| A=1  |------      --->| A->0  |
123562306a36Sopenharmony_ci	|       |       +------+      \         +-------+
123662306a36Sopenharmony_ci	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
123762306a36Sopenharmony_ci	|       |       +------+        |       +-------+
123862306a36Sopenharmony_ci	|       |------>| B=2  |---     |       :       :
123962306a36Sopenharmony_ci	|       |       +------+   \    |       :       :       +-------+
124062306a36Sopenharmony_ci	+-------+       :      :    \   |       +-------+       |       |
124162306a36Sopenharmony_ci	                             ---------->| B->2  |------>|       |
124262306a36Sopenharmony_ci	                                |       +-------+       | CPU 2 |
124362306a36Sopenharmony_ci	                                |       :       :       |       |
124462306a36Sopenharmony_ci	                                |       :       :       |       |
124562306a36Sopenharmony_ci	  En este punto la barrera ----> \  rrrrrrrrrrrrrrrrr   |       |
124662306a36Sopenharmony_ci	  de lectura consigue que         \     +-------+       |       |
124762306a36Sopenharmony_ci	  todos los efectos anteriores     ---->| A->1  |------>|       |
124862306a36Sopenharmony_ci	  al almacenamiento de B sean           +-------+       |       |
124962306a36Sopenharmony_ci	  perceptibles por la CPU 2             :       :       +-------+
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ciPara ilustrar esto de manera más completa, considere lo que podría pasar si
125362306a36Sopenharmony_ciel código contenía una carga de A a cada lado de la barrera de lectura:
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	CPU 1			CPU 2
125662306a36Sopenharmony_ci	=======================	=======================
125762306a36Sopenharmony_ci		{ A = 0, B = 9 }
125862306a36Sopenharmony_ci	STORE A=1
125962306a36Sopenharmony_ci	<barrera de escritura>
126062306a36Sopenharmony_ci	STORE B=2
126162306a36Sopenharmony_ci				LOAD B
126262306a36Sopenharmony_ci				LOAD A [primer load de A]
126362306a36Sopenharmony_ci				<rbarrera de lectura>
126462306a36Sopenharmony_ci				LOAD A [segundo load de A]
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ciAunque las dos cargas de A ocurren después de la carga de B, ambas pueden
126762306a36Sopenharmony_ciobtener diferentes valores:
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	+-------+       :      :                :       :
127062306a36Sopenharmony_ci	|       |       +------+                +-------+
127162306a36Sopenharmony_ci	|       |------>| A=1  |------      --->| A->0  |
127262306a36Sopenharmony_ci	|       |       +------+      \         +-------+
127362306a36Sopenharmony_ci	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
127462306a36Sopenharmony_ci	|       |       +------+        |       +-------+
127562306a36Sopenharmony_ci	|       |------>| B=2  |---     |       :       :
127662306a36Sopenharmony_ci	|       |       +------+   \    |       :       :       +-------+
127762306a36Sopenharmony_ci	+-------+       :      :    \   |       +-------+       |       |
127862306a36Sopenharmony_ci	                             ---------->| B->2  |------>|       |
127962306a36Sopenharmony_ci	                                |       +-------+       | CPU 2 |
128062306a36Sopenharmony_ci	                                |       :       :       |       |
128162306a36Sopenharmony_ci	                                |       :       :       |       |
128262306a36Sopenharmony_ci	                                |       +-------+       |       |
128362306a36Sopenharmony_ci	                                |       | A->0  |------>| 1st   |
128462306a36Sopenharmony_ci	                                |       +-------+       |       |
128562306a36Sopenharmony_ci	  En este punto la barrera ----> \  rrrrrrrrrrrrrrrrr   |       |
128662306a36Sopenharmony_ci	  de lectura consigue que         \     +-------+       |       |
128762306a36Sopenharmony_ci	  todos los efectos anteriores     ---->| A->1  |------>|       |
128862306a36Sopenharmony_ci	  al almacenamiento de B sean           +-------+       |       |
128962306a36Sopenharmony_ci	  perceptibles por la CPU 2             :       :       +-------+
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ciPero puede ser que la actualización a A desde la CPU 1 se vuelva
129262306a36Sopenharmony_ciperceptible para la CPU 2 antes de que la barrera de lectura se complete de
129362306a36Sopenharmony_citodos modos:
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	+-------+       :      :                :       :
129662306a36Sopenharmony_ci	|       |       +------+                +-------+
129762306a36Sopenharmony_ci	|       |------>| A=1  |------      --->| A->0  |
129862306a36Sopenharmony_ci	|       |       +------+      \         +-------+
129962306a36Sopenharmony_ci	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
130062306a36Sopenharmony_ci	|       |       +------+        |       +-------+
130162306a36Sopenharmony_ci	|       |------>| B=2  |---     |       :       :
130262306a36Sopenharmony_ci	|       |       +------+   \    |       :       :       +-------+
130362306a36Sopenharmony_ci	+-------+       :      :    \   |       +-------+       |       |
130462306a36Sopenharmony_ci	                             ---------->| B->2  |------>|       |
130562306a36Sopenharmony_ci	                                |       +-------+       | CPU 2 |
130662306a36Sopenharmony_ci	                                |       :       :       |       |
130762306a36Sopenharmony_ci	                                 \      :       :       |       |
130862306a36Sopenharmony_ci	                                  \     +-------+       |       |
130962306a36Sopenharmony_ci	                                   ---->| A->1  |------>| 1st   |
131062306a36Sopenharmony_ci	                                        +-------+       |       |
131162306a36Sopenharmony_ci	                                    rrrrrrrrrrrrrrrrr   |       |
131262306a36Sopenharmony_ci	                                        +-------+       |       |
131362306a36Sopenharmony_ci	                                        | A->1  |------>| 2nd   |
131462306a36Sopenharmony_ci	                                        +-------+       |       |
131562306a36Sopenharmony_ci	                                        :       :       +-------+
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ciLa garantía es que la segunda carga siempre dará como resultado A == 1 si
131862306a36Sopenharmony_cila carga de B resultó en B == 2. No existe tal garantía para la primera
131962306a36Sopenharmony_cicarga de A; esto puede dar como resultado A == 0 o A == 1.
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ciBARRERAS DE MEMORIA DE LECTURA FRENTE A ESPECULACIÓN DE CARGA
132362306a36Sopenharmony_ci-------------------------------------------------------------
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ciMuchas CPU especulan con las cargas: es decir, ven que necesitarán cargar
132662306a36Sopenharmony_ciun elemento de la memoria, y encuentran un momento en el que no están
132762306a36Sopenharmony_ciusando el bus para ningún otra carga, y también en la carga por adelantado,
132862306a36Sopenharmony_ciaunque en realidad no lo hayan llegado a ese punto en el flujo de ejecución
132962306a36Sopenharmony_cide instrucciones todavía. Esto permite que la instrucción de carga real
133062306a36Sopenharmony_cipotencialmente complete de inmediato, porque la CPU ya tiene el valor a
133162306a36Sopenharmony_cimano.
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ciPuede resultar que la CPU en realidad no necesitara el valor, tal vez
133462306a36Sopenharmony_ciporque una condición eludió la carga, en cuyo caso puede descartar el valor
133562306a36Sopenharmony_cio simplemente almacenar en caché para su uso posterior.
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ciConsidere:
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	CPU 1			CPU 2
134062306a36Sopenharmony_ci	=======================	=======================
134162306a36Sopenharmony_ci				LOAD B
134262306a36Sopenharmony_ci				DIVIDE		} Instrucciones de división
134362306a36Sopenharmony_ci				DIVIDE		} tardan mucho en terminar
134462306a36Sopenharmony_ci				LOAD A
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cidonde DIVIDE es DIVIDIR. Que podría aparecer como esto:
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	                                        :       :       +-------+
134962306a36Sopenharmony_ci	                                        +-------+       |       |
135062306a36Sopenharmony_ci	                                    --->| B->2  |------>|       |
135162306a36Sopenharmony_ci	                                        +-------+       | CPU 2 |
135262306a36Sopenharmony_ci	                                        :       :DIVIDE |       |
135362306a36Sopenharmony_ci	                                        +-------+       |       |
135462306a36Sopenharmony_ci	La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |
135562306a36Sopenharmony_ci	especula sobre el LOAD de A             +-------+   ~   |       |
135662306a36Sopenharmony_ci	                                        :       :   ~   |       |
135762306a36Sopenharmony_ci	                                        :       :DIVIDE |       |
135862306a36Sopenharmony_ci	                                        :       :   ~   |       |
135962306a36Sopenharmony_ci	Una vez completadas las divisiones  --> :       :   ~-->|       |
136062306a36Sopenharmony_ci	la CPU puede realizar el                :       :       |       |
136162306a36Sopenharmony_ci	LOAD con efecto inmediato               :       :       +-------+
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ciColocando una barrera de lectura o una barrera de dependencia de dirección
136562306a36Sopenharmony_cijusto antes de la segundo carga:
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	CPU 1			CPU 2
137062306a36Sopenharmony_ci	=======================	=======================
137162306a36Sopenharmony_ci				LOAD B
137262306a36Sopenharmony_ci				DIVIDE
137362306a36Sopenharmony_ci				DIVIDE
137462306a36Sopenharmony_ci				<rbarrera de lectura>
137562306a36Sopenharmony_ci				LOAD A
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ciobligará a reconsiderar cualquier valor obtenido especulativamente en una
137862306a36Sopenharmony_cimedida dependiente del tipo de barrera utilizada. Si no se hizo ningún
137962306a36Sopenharmony_cicambio en la ubicación de memoria especulada, entonces el valor especulado
138062306a36Sopenharmony_cisolo se usará:
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	                                        :       :       +-------+
138362306a36Sopenharmony_ci	                                        +-------+       |       |
138462306a36Sopenharmony_ci	                                    --->| B->2  |------>|       |
138562306a36Sopenharmony_ci	                                        +-------+       | CPU 2 |
138662306a36Sopenharmony_ci	                                        :       :DIVIDE |       |
138762306a36Sopenharmony_ci	                                        +-------+       |       |
138862306a36Sopenharmony_ci  La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |
138962306a36Sopenharmony_ci  especula sobre el LOAD de A             +-------+   ~   |       |
139062306a36Sopenharmony_ci	                                        :       :   ~   |       |
139162306a36Sopenharmony_ci	                                        :       :DIVIDE |       |
139262306a36Sopenharmony_ci	                                        :       :   ~   |       |
139362306a36Sopenharmony_ci	                                        :       :   ~   |       |
139462306a36Sopenharmony_ci	                                    rrrrrrrrrrrrrrrr~   |       |
139562306a36Sopenharmony_ci	                                        :       :   ~   |       |
139662306a36Sopenharmony_ci	                                        :       :   ~-->|       |
139762306a36Sopenharmony_ci	                                        :       :       |       |
139862306a36Sopenharmony_ci	                                        :       :       +-------+
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cipero si había una actualización o una invalidación de otra CPU pendiente,
140262306a36Sopenharmony_cientonces la especulación será cancelada y el valor recargado:
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	                                        :       :       +-------+
140562306a36Sopenharmony_ci	                                        +-------+       |       |
140662306a36Sopenharmony_ci	                                    --->| B->2  |------>|       |
140762306a36Sopenharmony_ci	                                        +-------+       | CPU 2 |
140862306a36Sopenharmony_ci	                                        :       :DIVIDE |       |
140962306a36Sopenharmony_ci	                                        +-------+       |       |
141062306a36Sopenharmony_ci  La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |
141162306a36Sopenharmony_ci  especula sobre el LOAD de A             +-------+   ~   |       |
141262306a36Sopenharmony_ci	                                        :       :   ~   |       |
141362306a36Sopenharmony_ci	                                        :       :DIVIDE |       |
141462306a36Sopenharmony_ci	                                        :       :   ~   |       |
141562306a36Sopenharmony_ci	                                        :       :   ~   |       |
141662306a36Sopenharmony_ci	                                    rrrrrrrrrrrrrrrrr   |       |
141762306a36Sopenharmony_ci	                                        +-------+       |       |
141862306a36Sopenharmony_ci	La especulación es descartada --->  --->| A->1  |------>|       |
141962306a36Sopenharmony_ci	y un valor actualizado                  +-------+       |       |
142062306a36Sopenharmony_ci	es conseguido                           :       :       +-------+
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ciATOMICIDAD MULTICOPIA
142362306a36Sopenharmony_ci---------------------
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ciLa atomicidad multicopia es una noción profundamente intuitiva sobre el
142662306a36Sopenharmony_ciorden que no es siempre proporcionada por los sistemas informáticos reales,
142762306a36Sopenharmony_cia saber, que un determinada store se vuelve visible al mismo tiempo para
142862306a36Sopenharmony_citodos las CPU o, alternativamente, que todas las CPU acuerdan el orden en
142962306a36Sopenharmony_cique todos los stores se vuelven visibles. Sin embargo, el soporte para
143062306a36Sopenharmony_ciatomicidad multicopia completa descartaría valiosas optimizaciones
143162306a36Sopenharmony_cihardware, por lo que una versión más débil conocida como ``otra atomicidad
143262306a36Sopenharmony_cimulticopia'' en cambio, solo garantiza que un store dado se vuelva visible
143362306a36Sopenharmony_cial mismo tiempo en todas las -otras- CPUs. El resto de este documento
143462306a36Sopenharmony_cidiscute esta versión más débil, pero por brevedad lo llamaremos simplemente
143562306a36Sopenharmony_ci``atomicidad multicopia''.
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ciEl siguiente ejemplo demuestra la atomicidad multicopia:
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	CPU 1			CPU 2			CPU 3
144062306a36Sopenharmony_ci	=======================	=======================	=======================
144162306a36Sopenharmony_ci		{ X = 0, Y = 0 }
144262306a36Sopenharmony_ci	STORE X=1		r1=LOAD X (reads 1)	LOAD Y (reads 1)
144362306a36Sopenharmony_ci				<barrera general>	<barrera de lectura>
144462306a36Sopenharmony_ci				STORE Y=r1		LOAD X
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ciSuponga que la carga de la CPU 2 desde X devuelve 1, que luego almacena en
144762306a36Sopenharmony_ciY, y la carga de la CPU 3 desde Y devuelve 1. Esto indica que el store de
144862306a36Sopenharmony_cila CPU 1 a X precede a la carga de la CPU 2 desde X y el store de esa CPU 2
144962306a36Sopenharmony_cia Y precede la carga de la CPU 3 desde Y. Además, las barreras de memoria
145062306a36Sopenharmony_cigarantizan que la CPU 2 ejecuta su carga antes que su almacenamiento, y la
145162306a36Sopenharmony_ciCPU 3 carga desde Y antes de cargar desde X. La pregunta entonces es
145262306a36Sopenharmony_ci"¿Puede la carga de la CPU 3 desde X devolver 0?"
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ciDebido a que la carga de la CPU 3 desde X en cierto sentido viene después
145562306a36Sopenharmony_cide la carga de la CPU 2, es natural esperar que la carga de la CPU 3 desde
145662306a36Sopenharmony_ciX deba devolver 1. Esta expectativa se deriva de la atomicidad multicopia:
145762306a36Sopenharmony_cisi una carga que se ejecuta en la CPU B sigue una carga de la misma
145862306a36Sopenharmony_civariable que se ejecuta en la CPU A (y la CPU A no almacenó originalmente
145962306a36Sopenharmony_ciel valor que leyó), entonces en sistemas atómicos multicopia, la carga de
146062306a36Sopenharmony_cila CPU B debe devolver el mismo valor que hizo la carga de la CPU A o algún
146162306a36Sopenharmony_civalor posterior. Sin embargo, el kernel Linux no requiere que los sistemas
146262306a36Sopenharmony_cisean atómicos multicopia.
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ciEl uso de una barrera de memoria general en el ejemplo anterior compensa
146562306a36Sopenharmony_cicualquier falta de atomicidad multicopia. En el ejemplo, si la carga de la
146662306a36Sopenharmony_ciCPU 2 de X devuelve 1 y la carga de la CPU 3 de Y devuelve 1, entonces la
146762306a36Sopenharmony_cicarga de la CPU 3 desde X debe de hecho también devolver 1.
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ciSin embargo, las dependencias, las barreras de lectura y las barreras de
147062306a36Sopenharmony_ciescritura no siempre son capaces de compensar la atomicidad no multicopia.
147162306a36Sopenharmony_ciPor ejemplo, supongamos que la barrera general de la CPU 2 se elimina del
147262306a36Sopenharmony_ciejemplo anterior, dejando solo la dependencia de datos que se muestra a
147362306a36Sopenharmony_cicontinuación:
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	CPU 1			CPU 2			CPU 3
147662306a36Sopenharmony_ci	=======================	=======================	=======================
147762306a36Sopenharmony_ci		{ X = 0, Y = 0 }
147862306a36Sopenharmony_ci	STORE X=1		r1=LOAD X (escribe 1)	LOAD Y (lee 1)
147962306a36Sopenharmony_ci				<dependencia de datos>	<barrera de lectura>
148062306a36Sopenharmony_ci				STORE Y=r1		LOAD X (lee 0)
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ciEsta sustitución permite que la atomicidad no multicopia se desenfrene: en
148362306a36Sopenharmony_cieste ejemplo, es perfectamente legal que la carga de la CPU 2 desde X
148462306a36Sopenharmony_cidevuelva 1, la carga de la CPU 3 desde Y devuelva 1, y su carga desde X
148562306a36Sopenharmony_citenga valor 0.
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ciEl punto clave es que aunque la dependencia de datos de la CPU 2 ordena su
148862306a36Sopenharmony_cicarga y store, no garantiza ordenar el store de la CPU 1. De forma que, si
148962306a36Sopenharmony_cieste ejemplo se ejecuta en un sistema atómico no multicopia donde las CPU 1
149062306a36Sopenharmony_ciy 2 comparten un buffer de almacenamiento o un nivel de caché, la CPU 2
149162306a36Sopenharmony_cipodría tener acceso anticipado de escritura a CPU 1. Por lo tanto, se
149262306a36Sopenharmony_cirequieren barreras generales para garantizar que todas las CPU acurden el
149362306a36Sopenharmony_ciorden combinado de accesos múltiples.
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ciLas barreras generales pueden compensar no solo la atomicidad no
149662306a36Sopenharmony_cimulticopia, pero también pueden generar orden adicional que puede asegurar
149762306a36Sopenharmony_cique -todas- las CPU percibirán el mismo orden de -todas- las operaciones.
149862306a36Sopenharmony_ciPor el contrario, una cadena de parejas de liberación-adquisición no
149962306a36Sopenharmony_ciproporciona este orden adicional, lo que significa que solo se garantiza
150062306a36Sopenharmony_cique las CPU de la cadena estén de acuerdo en el orden combinado de los
150162306a36Sopenharmony_ciaccesos. Por ejemplo, cambiando a código C en deferencia al fantasma de
150262306a36Sopenharmony_ciHerman Hollerith:
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	int u, v, x, y, z;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	void cpu0(void)
150762306a36Sopenharmony_ci	{
150862306a36Sopenharmony_ci		r0 = smp_load_acquire(&x);
150962306a36Sopenharmony_ci		WRITE_ONCE(u, 1);
151062306a36Sopenharmony_ci		smp_store_release(&y, 1);
151162306a36Sopenharmony_ci	}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	void cpu1(void)
151462306a36Sopenharmony_ci	{
151562306a36Sopenharmony_ci		r1 = smp_load_acquire(&y);
151662306a36Sopenharmony_ci		r4 = READ_ONCE(v);
151762306a36Sopenharmony_ci		r5 = READ_ONCE(u);
151862306a36Sopenharmony_ci		smp_store_release(&z, 1);
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	void cpu2(void)
152262306a36Sopenharmony_ci	{
152362306a36Sopenharmony_ci		r2 = smp_load_acquire(&z);
152462306a36Sopenharmony_ci		smp_store_release(&x, 1);
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	void cpu3(void)
152862306a36Sopenharmony_ci	{
152962306a36Sopenharmony_ci		WRITE_ONCE(v, 1);
153062306a36Sopenharmony_ci		smp_mb();
153162306a36Sopenharmony_ci		r3 = READ_ONCE(u);
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ciDado que cpu0(), cpu1() y cpu2() participan en una cadena de parejas
153562306a36Sopenharmony_cismp_store_release()/smp_load_acquire(), el siguiente resultado estaría
153662306a36Sopenharmony_ciprohibido:
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	r0 == 1 && r1 == 1 && r2 == 1
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ciAdemás, debido a la relación liberación-adquisición entre cpu0() y cpu1(),
154162306a36Sopenharmony_cicpu1() debe ver las escrituras de cpu0(), de modo que el siguiente
154262306a36Sopenharmony_ciresultado estaría prohibido:
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	r1 == 1 && r5 == 0
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ciSin embargo, el orden proporcionado por una cadena de
154762306a36Sopenharmony_ciliberación-adquisición es local a las CPU que participan en esa cadena y no
154862306a36Sopenharmony_cise aplica a cpu3(), al menos aparte de los stores. Por lo tanto, es posible
154962306a36Sopenharmony_ciel siguiente resultado:
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ciPor otro lado, también el siguiente resultado es posible:
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 && r5 == 1
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ciAunque cpu0(), cpu1() y cpu2() verán sus respectivas lecturas y escrituras
155862306a36Sopenharmony_cien orden, las CPU que no participan en la cadena de liberación-adquisición
155962306a36Sopenharmony_cipueden estar en desacuerdo con el orden. Este desacuerdo se debe al hecho
156062306a36Sopenharmony_cide que las instrucciones de barrera de memoria débiles utilizadas para
156162306a36Sopenharmony_ciimplementar smp_load_acquire() y smp_store_release() no son necesarios para
156262306a36Sopenharmony_ciordenar stores anteriores contra cargas posteriores en todos los casos.
156362306a36Sopenharmony_ciEsto significa que cpu3() puede ver el store de cpu0() suceder -después- de
156462306a36Sopenharmony_cila carga de cpu1() desde v, aunque tanto cpu0() como cpu1() están de
156562306a36Sopenharmony_ciacuerdo en que estas dos operaciones ocurrieron en el orden previsto.
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ciSin embargo, tenga en cuenta que smp_load_acquire() no es mágico. En
156862306a36Sopenharmony_ciparticular, simplemente lee de su argumento en orden. Es decir, -no-
156962306a36Sopenharmony_ciasegura que se leerá cualquier valor en particular. Por lo tanto, los
157062306a36Sopenharmony_cisiguiente resultados son posibles:
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	r0 == 0 && r1 == 0 && r2 == 0 && r5 == 0
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ciTenga en cuenta que este resultado puede ocurrir incluso en un mítico
157562306a36Sopenharmony_cisistema, consistente en secuencia, donde nunca se reordena nada.
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ciPara reiterar, si su código requiere un orden completo de todas las
157862306a36Sopenharmony_cioperaciones, utilice barreras generales en todo momento.
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci==============================
158262306a36Sopenharmony_ciBARRERAS EXPLÍCITAS DEL KERNEL
158362306a36Sopenharmony_ci==============================
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ciEl kernel Linux tiene una variedad de diferentes barreras que actúan a
158662306a36Sopenharmony_cidiferentes niveles:
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci  (*) Barrera del compilador.
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci  (*) Barreras de memoria de la CPU.
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ciBARRERA DEL COMPILADOR
159462306a36Sopenharmony_ci-----------------------
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ciEl kernel de Linux tiene una función de barrera del compilador explícita
159762306a36Sopenharmony_cique evita que el el compilador mueva los accesos a la memoria de cualquier
159862306a36Sopenharmony_cilado al otro:
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	barrier();
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ciEsta es una barrera general: no hay variantes de barrier() para casos de
160362306a36Sopenharmony_cilectura-lectura o escritura-escritura. Sin embargo, READ_ONCE() y
160462306a36Sopenharmony_ciWRITE_ONCE() pueden ser considerado como formas débiles de barrier() que
160562306a36Sopenharmony_ciafectan solo específicos accesos marcados por READ_ONCE() o WRITE_ONCE().
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ciLa función barrier() produce los siguientes efectos:
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci (*) Evita que el compilador reordene los accesos tras barrier() para
161062306a36Sopenharmony_ci     preceder a cualquier acceso que preceda a barrier(). Un ejemplo de uso
161162306a36Sopenharmony_ci     de esta propiedad es facilitar la comunicación entre código del
161262306a36Sopenharmony_ci     interrupt-handler (encargo de gestionar interrupciones) y el código
161362306a36Sopenharmony_ci     que fue interrumpido.
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci (*) Dentro de un bucle ("loop"), obliga al compilador a cargar las
161662306a36Sopenharmony_ci     variables utilizadas en ese loop condicional en cada paso a través de
161762306a36Sopenharmony_ci     ese loop.
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ciLas funciones READ_ONCE() y WRITE_ONCE() pueden evitar cualquier cantidad
162062306a36Sopenharmony_cide optimizaciones que, si bien son perfectamente seguras en código de un
162162306a36Sopenharmony_cisolo subproceso, pueden resultar fatales en código concurrente. Aquí hay
162262306a36Sopenharmony_cialgunos ejemplos de tal tipo de optimizaciones:
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci(*) El compilador está en su derecho de reordenar cargas y stores de la
162562306a36Sopenharmony_ci    misma variable, y en algunos casos, la CPU está dentro de su
162662306a36Sopenharmony_ci    derecho de reordenar cargas a la misma variable. Esto significa que
162762306a36Sopenharmony_ci    el siguiente código:
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci a[0] = x;
163062306a36Sopenharmony_ci a[1] = x;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci     Podría resultar en un valor más antiguo de x almacenado en a[1] que en
163362306a36Sopenharmony_ci     a[0]. Evite que tanto el compilador como la CPU hagan esto de la
163462306a36Sopenharmony_ci     siguiente manera:
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	a[0] = READ_ONCE(x);
163762306a36Sopenharmony_ci	a[1] = READ_ONCE(x);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci     En resumen, READ_ONCE() y WRITE_ONCE() proporcionan coherencia de
164062306a36Sopenharmony_ci     caché para accesos desde múltiples CPUs a una sola variable.
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci     (*) El compilador tiene derecho a juntar cargas sucesivas de la misma
164362306a36Sopenharmony_ci         variable. Tal fusión puede hacer que el compilador "optimice" el
164462306a36Sopenharmony_ci         siguiente código:
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci    	while (tmp = a)
164762306a36Sopenharmony_ci    		hacer_algo_con(tmp);
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci        en el siguiente código, que, aunque en cierto sentido es legítimo
165062306a36Sopenharmony_ci        para un código de un solo subproceso, es casi seguro que no es lo
165162306a36Sopenharmony_ci        que el desarrollador pretendía:
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci   	if (tmp = a)
165462306a36Sopenharmony_ci   		for (;;)
165562306a36Sopenharmony_ci   			hacer_algo_con(tmp);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci        Use READ_ONCE() para evitar que el compilador le haga esto:
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci   	while (tmp = READ_ONCE(a))
166062306a36Sopenharmony_ci   		hacer_algo_con(tmp);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci (*) El compilador tiene derecho a recargar una variable, por ejemplo,
166362306a36Sopenharmony_ci    en los casos en que la alta presión de los registros impida que el
166462306a36Sopenharmony_ci    compilador mantenga todos los datos de interés en registros. El
166562306a36Sopenharmony_ci    compilador podría por lo tanto, optimizar la variable 'tmp' de nuestro
166662306a36Sopenharmony_ci    ejemplo anterior:
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	while (tmp = a)
166962306a36Sopenharmony_ci		hacer_algo_con(tmp);
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci     Esto podría resultar en el siguiente código, que es perfectamente
167262306a36Sopenharmony_ci     seguro en código de subproceso único, pero puede ser fatal en código
167362306a36Sopenharmony_ci     concurrente:
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	while (a)
167662306a36Sopenharmony_ci		hacer_algo_con(a);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci    Por ejemplo, la versión optimizada de este código podría resultar en
167962306a36Sopenharmony_ci    pasar un cero a hacer_algo_con() en el caso de que la variable a sea
168062306a36Sopenharmony_ci    modificada por alguna otra CPU, entre la instrucción "while" y la
168162306a36Sopenharmony_ci    llamada a hacer_algo_con().
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci    De nuevo, use READ_ONCE() para evitar que el compilador haga esto:
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	while (tmp = READ_ONCE(a))
168662306a36Sopenharmony_ci		hacer_algo_con(tmp);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci     Tenga en cuenta que si el compilador se queda sin registros, podría
168962306a36Sopenharmony_ci     guardar tmp en la pila ("stack"). El overhead (coste en eficiencia) de
169062306a36Sopenharmony_ci     este guardado y posterior restauración es por lo que los compiladores
169162306a36Sopenharmony_ci     recargan las variables. Hacerlo es perfectamente seguro para código de
169262306a36Sopenharmony_ci     subproceso único, por lo que debe informar al compilador sobre los
169362306a36Sopenharmony_ci     casos donde no sea seguro.
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci (*) El compilador está en su derecho de omitir una carga por completo si
169662306a36Sopenharmony_ci     sabe cual será su valor. Por ejemplo, si el compilador puede probar
169762306a36Sopenharmony_ci     que el valor de la variable 'a' siempre es cero, puede optimizar este
169862306a36Sopenharmony_ci     código:
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	while (tmp = a)
170162306a36Sopenharmony_ci		hacer_algo_con(tmp);
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci     En esto:
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	do { } while (0);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci     Esta transformación es una victoria para un código de un solo
170862306a36Sopenharmony_ci     subproceso, porque se deshace de una carga y un branch. El problema es
170962306a36Sopenharmony_ci     que el compilador llevará a cabo su prueba asumiendo que la CPU actual
171062306a36Sopenharmony_ci     es la única actualizando la variable 'a'. Si la variable 'a' es
171162306a36Sopenharmony_ci     compartida, entonces la prueba del compilador será errónea. Use
171262306a36Sopenharmony_ci     READ_ONCE() para decirle al compilador que no sabe tanto como cree:
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	while (tmp = READ_ONCE(a))
171562306a36Sopenharmony_ci		hacer_algo_con(tmp);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci     Pero, por favor, tenga en cuenta que el compilador también está
171862306a36Sopenharmony_ci     observando de cerca lo que usted hace con el valor después de
171962306a36Sopenharmony_ci     READ_ONCE(). Por ejemplo, suponga que Ud. hace lo siguiente y MAX es
172062306a36Sopenharmony_ci     una macro de preprocesador con el valor 1:
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	while ((tmp = READ_ONCE(a)) % MAX)
172362306a36Sopenharmony_ci		hacer_algo_con(tmp);
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci     Entonces el compilador sabe que el resultado del operador "%" aplicado
172662306a36Sopenharmony_ci     a MAX siempre será cero, nuevamente permitiendo que el compilador
172762306a36Sopenharmony_ci     optimice el código hasta su casi inexistencia. (Aún se cargará desde
172862306a36Sopenharmony_ci     la variable 'a'.)
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci (*) De manera similar, el compilador tiene derecho a omitir un store por
173162306a36Sopenharmony_ci     completo si sabe que la variable ya tiene el valor almacenado.
173262306a36Sopenharmony_ci     Nuevamente, el compilador asume que la CPU actual es la única que
173362306a36Sopenharmony_ci     almacena la variable, lo que puede hacer que el compilador haga
173462306a36Sopenharmony_ci     algo incorrecto para las variables compartidas. Por ejemplo, suponga
173562306a36Sopenharmony_ci     que tiene lo siguiente:
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	a = 0;
173862306a36Sopenharmony_ci	... Código que no almacena la variable a ...
173962306a36Sopenharmony_ci	a = 0;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci     El compilador observa que el valor de la variable 'a' ya es cero, por
174262306a36Sopenharmony_ci     lo que bien podría omitir el segundo store. Esto supondría una fatal
174362306a36Sopenharmony_ci     sorpresa, si alguna otra CPU hubiera almacenado la variable 'a'
174462306a36Sopenharmony_ci     mientras tanto.
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci     Use WRITE_ONCE() para evitar que el compilador haga este tipo de
174762306a36Sopenharmony_ci     suposición equivocada:
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	WRITE_ONCE(a, 0);
175062306a36Sopenharmony_ci	... Código que no almacena la variable a  ...
175162306a36Sopenharmony_ci	WRITE_ONCE(a, 0);
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci  (*) El compilador tiene derecho a reordenar los accesos a memoria a menos
175462306a36Sopenharmony_ci     que le diga que no. Por ejemplo, considere la siguiente interacción
175562306a36Sopenharmony_ci     entre el código de nivel de proceso y un controlador de interrupción:
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	void nivel_de_procesamiento(void)
175862306a36Sopenharmony_ci	{
175962306a36Sopenharmony_ci		msg = ACQUIRE_mensaje();
176062306a36Sopenharmony_ci		flag = true;
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	void controlador_interrupcion(void)
176462306a36Sopenharmony_ci	{
176562306a36Sopenharmony_ci		if (flag)
176662306a36Sopenharmony_ci			procesar_mensaje(msg);
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci     No hay nada que impida que el compilador transforme
177062306a36Sopenharmony_ci     nivel_de_procesamiento() a lo siguiente, que de hecho, bien podría ser
177162306a36Sopenharmony_ci     una victoria para código de un solo subproceso:
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	void nivel_de_procesamiento(void)
177462306a36Sopenharmony_ci	{
177562306a36Sopenharmony_ci		flag = true;
177662306a36Sopenharmony_ci		msg = ACQUIRE_mensaje();
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci     Si la interrupción ocurre entre estas dos declaraciones, entonces
178062306a36Sopenharmony_ci     controlador_interrupcion() podría recibir un mensaje ilegible. Use
178162306a36Sopenharmony_ci     READ_ONCE() para evitar esto de la siguiente manera:
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	void nivel_de_procesamiento(void)
178462306a36Sopenharmony_ci	{
178562306a36Sopenharmony_ci		WRITE_ONCE(msg, ACQUIRE_mensaje());
178662306a36Sopenharmony_ci		WRITE_ONCE(flag, true);
178762306a36Sopenharmony_ci	}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	void controlador_interrupcion(void)
179062306a36Sopenharmony_ci	{
179162306a36Sopenharmony_ci		if (READ_ONCE(flag))
179262306a36Sopenharmony_ci			procesar_mensaje(READ_ONCE(msg));
179362306a36Sopenharmony_ci	}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci     Tenga en cuenta que los envoltorios ("wrappers") READ_ONCE() y
179662306a36Sopenharmony_ci     WRITE_ONCE() en controlador_interrupcion() son necesarios si este
179762306a36Sopenharmony_ci     controlador de interrupciones puede ser interrumpido por algo que
179862306a36Sopenharmony_ci     también accede a 'flag' y 'msg', por ejemplo, una interrupción anidada
179962306a36Sopenharmony_ci     o un NMI. De lo contrario, READ_ONCE() y WRITE_ONCE() no son
180062306a36Sopenharmony_ci     necesarios en controlador_interrupcion() aparte de con fines de
180162306a36Sopenharmony_ci     documentación. (Tenga también en cuenta que las interrupciones
180262306a36Sopenharmony_ci     anidadas no ocurren típicamente en los kernels Linux modernos, de
180362306a36Sopenharmony_ci     hecho, si un controlador de interrupciones regresa con interrupciones
180462306a36Sopenharmony_ci     habilitadas, obtendrá un WARN_ONCE().)
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci     Debe suponer que el compilador puede mover READ_ONCE() y WRITE_ONCE()
180762306a36Sopenharmony_ci     a código que no contiene READ_ONCE(), WRITE_ONCE(), barrier(), o
180862306a36Sopenharmony_ci     primitivas similares.
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci     Este efecto también podría lograrse usando barrier(), pero READ_ONCE()
181162306a36Sopenharmony_ci     y WRITE_ONCE() son más selectivos: Con READ_ONCE() y WRITE_ONCE(), el
181262306a36Sopenharmony_ci     compilador solo necesita olvidar el contenido de ubicaciones de
181362306a36Sopenharmony_ci     memoria indicadas, mientras que con barrier() el compilador debe
181462306a36Sopenharmony_ci     descartar el valor de todas las ubicaciones de memoria que tiene
181562306a36Sopenharmony_ci     actualmente almacenadas en caché, en cualquier registro de la máquina.
181662306a36Sopenharmony_ci     Por supuesto, el compilador también debe respetar el orden en que
181762306a36Sopenharmony_ci     ocurren READ_ONCE() y WRITE_ONCE(), aunque la CPU, efectivamente, no
181862306a36Sopenharmony_ci     necesita hacerlo.
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci (*) El compilador tiene derecho a inventar stores para una variable,
182162306a36Sopenharmony_ci     como en el siguiente ejemplo:
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	if (a)
182462306a36Sopenharmony_ci		b = a;
182562306a36Sopenharmony_ci	else
182662306a36Sopenharmony_ci		b = 42;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci    El compilador podría ahorrar un branch al optimizar esto de la
182962306a36Sopenharmony_ci    siguiente manera:
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci    	b = 42;
183262306a36Sopenharmony_ci    	if (a)
183362306a36Sopenharmony_ci    		b = a;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci     En el código de un solo subproceso, esto no solo es seguro, sino que
183662306a36Sopenharmony_ci     también ahorra un branch. Desafortunadamente, en código concurrente,
183762306a36Sopenharmony_ci     esta optimización podría causar que alguna otra CPU vea un valor falso
183862306a36Sopenharmony_ci     de 42, incluso si la variable 'a' nunca fue cero, al cargar la
183962306a36Sopenharmony_ci     variable 'b'. Use WRITE_ONCE() para evitar esto de la siguiente
184062306a36Sopenharmony_ci     manera:
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	if (a)
184362306a36Sopenharmony_ci		WRITE_ONCE(b, a);
184462306a36Sopenharmony_ci	else
184562306a36Sopenharmony_ci		WRITE_ONCE(b, 42);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci    El compilador también puede inventar cargas. Estos casos suelen ser
184862306a36Sopenharmony_ci    menos perjudiciales, pero pueden dar como resultado "bouncing" de la
184962306a36Sopenharmony_ci    línea de caché y, por lo tanto, bajo rendimiento y escalabilidad.
185062306a36Sopenharmony_ci    Utilice READ_ONCE() para evitar cargas inventadas.
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci (*) Para ubicaciones de memoria alineadas cuyo tamaño les permita
185362306a36Sopenharmony_ci     acceder con una sola instrucción de referencia de memoria, evite el
185462306a36Sopenharmony_ci     "desgarro de la carga" (load tearing) y "desgarro del store" (store
185562306a36Sopenharmony_ci     tearing), en el que un solo gran acceso es reemplazado por múltiples
185662306a36Sopenharmony_ci     accesos menores. Por ejemplo, dada una arquitectura que tiene
185762306a36Sopenharmony_ci     instrucciones de almacenamiento de 16 bits con campos inmediatos de 7
185862306a36Sopenharmony_ci     bits, el compilador podría tener la tentación de usar dos
185962306a36Sopenharmony_ci     instrucciones inmediatas de almacenamiento de 16 bits para implementar
186062306a36Sopenharmony_ci     el siguiente store de 32 bits:
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	p = 0x00010002;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci     Tenga en cuenta que GCC realmente usa este tipo de optimización, lo
186562306a36Sopenharmony_ci     cual no es sorprendente dado que probablemente costaría más de dos
186662306a36Sopenharmony_ci     instrucciones el construir la constante y luego almacenarla. Por lo
186762306a36Sopenharmony_ci     tanto, esta optimización puede ser una victoria en un código de un
186862306a36Sopenharmony_ci     solo subproceso. De hecho, un error reciente (desde que se solucionó)
186962306a36Sopenharmony_ci     hizo que GCC usara incorrectamente esta optimización en un store
187062306a36Sopenharmony_ci     volátil. En ausencia de tales errores, el uso de WRITE_ONCE() evita el
187162306a36Sopenharmony_ci     desgarro del store en el siguiente ejemplo:
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	struct __attribute__((__packed__)) foo {
187462306a36Sopenharmony_ci		short a;
187562306a36Sopenharmony_ci		int b;
187662306a36Sopenharmony_ci		short c;
187762306a36Sopenharmony_ci	};
187862306a36Sopenharmony_ci	struct foo foo1, foo2;
187962306a36Sopenharmony_ci	...
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	foo2.a = foo1.a;
188262306a36Sopenharmony_ci	foo2.b = foo1.b;
188362306a36Sopenharmony_ci	foo2.c = foo1.c;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci     Debido a que no hay envoltorios READ_ONCE() o WRITE_ONCE() y no
188662306a36Sopenharmony_ci     hay markings volátiles, el compilador estaría en su derecho de
188762306a36Sopenharmony_ci     implementar estas tres declaraciones de asignación como un par de
188862306a36Sopenharmony_ci     cargas de 32 bits, seguido de un par de stores de 32 bits. Esto
188962306a36Sopenharmony_ci     resultaría en una carga con desgarro en 'foo1.b' y store del desgarro
189062306a36Sopenharmony_ci     en 'foo2.b'. READ_ONCE() y WRITE_ONCE() nuevamente evitan el desgarro
189162306a36Sopenharmony_ci     en este ejemplo:
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	foo2.a = foo1.a;
189462306a36Sopenharmony_ci	WRITE_ONCE(foo2.b, READ_ONCE(foo1.b));
189562306a36Sopenharmony_ci	foo2.c = foo1.c;
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ciAparte de esto, nunca es necesario usar READ_ONCE() y WRITE_ONCE() en una
189862306a36Sopenharmony_civariable que se ha marcado como volátil. Por ejemplo, dado que 'jiffies'
189962306a36Sopenharmony_ciestá marcado como volátil, nunca es necesario usar READ_ONCE(jiffies). La
190062306a36Sopenharmony_cirazón de esto es que READ_ONCE() y WRITE_ONCE() se implementan como
190162306a36Sopenharmony_ciconversiones volátiles, lo que no tiene efecto cuando su argumento ya está
190262306a36Sopenharmony_cimarcado como volátil.
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ciTenga en cuenta que estas barreras del compilador no tienen un efecto
190562306a36Sopenharmony_cidirecto en la CPU, que luego puede reordenar las cosas como quiera.
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ciBARRERAS DE MEMORIA DE LA CPU
190962306a36Sopenharmony_ci-----------------------------
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ciEl kernel de Linux tiene siete barreras básicas de memoria de CPU:
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ciTIPO			OBLIGATORIO	SMP CONDICIONAL
191462306a36Sopenharmony_ci=======================	===============	===============
191562306a36Sopenharmony_ciGENERAL			mb()		smp_mb()
191662306a36Sopenharmony_ciWRITE			wmb()		smp_wmb()
191762306a36Sopenharmony_ciREAD			rmb()		smp_rmb()
191862306a36Sopenharmony_ciDEPEDENCIA DE DIRECCIÓN			READ_ONCE()
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ciTodas las barreras de memoria, excepto las barreras de dependencia de
192262306a36Sopenharmony_cidirecciones, implican una barrera del compilador. Las dependencias de
192362306a36Sopenharmony_cidirecciones no imponen ningún orden de compilación adicional.
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ciAdemás: en el caso de las dependencias de direcciones, se esperaría que el
192662306a36Sopenharmony_cicompilador emita las cargas en el orden correcto (por ejemplo, `a[b]`
192762306a36Sopenharmony_citendría que cargar el valor de b antes de cargar a[b]), sin embargo, no hay
192862306a36Sopenharmony_cigarantía alguna en la especificación de C sobre que el compilador no puede
192962306a36Sopenharmony_ciespecular el valor de b (por ejemplo, es igual a 1) y carga a[b] antes que
193062306a36Sopenharmony_cib (ej. tmp = a[1]; if (b != 1) tmp = a[b]; ). También existe el problema de
193162306a36Sopenharmony_cique un compilador vuelva a cargar b después de haber cargado a[b], teniendo
193262306a36Sopenharmony_ciasí una copia más nueva de b que a[b]. Aún no se ha conseguido un consenso
193362306a36Sopenharmony_ciacerca de estos problemas, sin embargo, el macro READ_ONCE() es un buen
193462306a36Sopenharmony_cilugar para empezar a buscar.
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ciLas barreras de memoria SMP se reducen a barreras de compilador cuando se
193762306a36Sopenharmony_cicompila a monoprocesador, porque se supone que una CPU parecerá ser
193862306a36Sopenharmony_ciauto-consistente, y ordenará correctamente los accesos superpuestos
193962306a36Sopenharmony_cirespecto a sí misma. Sin embargo, consulte la subsección "Guests de
194062306a36Sopenharmony_cimáquinas virtuales" mas adelante.
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci[!] Tenga en cuenta que las barreras de memoria SMP _deben_ usarse para
194362306a36Sopenharmony_cicontrolar el orden de referencias a memoria compartida en sistemas SMP,
194462306a36Sopenharmony_ciaunque el uso de bloqueo en su lugar sea suficiente.
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ciLas barreras obligatorias no deben usarse para controlar los efectos de
194762306a36Sopenharmony_ciSMP, ya que dichas barreras imponen una sobrecarga innecesaria en los
194862306a36Sopenharmony_cisistemas SMP y UP. Se pueden, sin embargo, usar para controlar los efectos
194962306a36Sopenharmony_ciMMIO en los accesos a través de ventanas E/S de memoria relajada. Estas
195062306a36Sopenharmony_cibarreras son necesarias incluso en sistemas que no son SMP, ya que afectan
195162306a36Sopenharmony_cial orden en que las operaciones de memoria aparecen en un dispositivo, al
195262306a36Sopenharmony_ciprohibir tanto al compilador como a la CPU que sean reordenados.
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ciHay algunas funciones de barrera más avanzadas:
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci (*) smp_store_mb(var, valor)
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci     Asigna el valor a la variable y luego inserta una barrera de memoria
196062306a36Sopenharmony_ci     completa después de ella. No se garantiza insertar nada más que una
196162306a36Sopenharmony_ci     barrera del compilador en una compilación UP.
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci (*) smp_mb__before_atomic();
196562306a36Sopenharmony_ci (*) smp_mb__after_atomic();
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci     Estos se pueden usar con funciones RMW atómicas que no implican
196862306a36Sopenharmony_ci     barreras de memoria, pero donde el código necesita una barrera de
196962306a36Sopenharmony_ci     memoria. Ejemplos de funciones RMW atómicas que no implican una
197062306a36Sopenharmony_ci     barrera de memoria son, por ejemplo, agregar, restar, operaciones
197162306a36Sopenharmony_ci     condicionales (fallidas), funciones _relaxed, pero no atomic_read o
197262306a36Sopenharmony_ci     atomic_set. Un ejemplo común donde se puede requerir una barrera es
197362306a36Sopenharmony_ci     cuando se usan operaciones atómicas como referencia de contador.
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci     Estos también se utilizan para funciones atómicas RMW bitop que no
197662306a36Sopenharmony_ci     implican una barrera de memoria (como set_bit y clear_bit).
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci     Como ejemplo, considere una pieza de código que marca un objeto como
197962306a36Sopenharmony_ci     muerto y luego disminuye el contador de referencias del objeto:
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	obj->dead = 1;
198262306a36Sopenharmony_ci	smp_mb__before_atomic();
198362306a36Sopenharmony_ci	atomic_dec(&obj->ref_count);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci     Esto asegura que la marca de muerte en el objeto se perciba como
198662306a36Sopenharmony_ci     fijada *antes* de que disminuya el contador de referencia.
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci     Consulte Documentation/atomic_{t,bitops}.txt para obtener más
198962306a36Sopenharmony_ci     información.
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci (*) dma_wmb();
199362306a36Sopenharmony_ci (*) dma_rmb();
199462306a36Sopenharmony_ci (*) dma_mb();
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci     Estos son usados con memoria consistente para garantizar el orden de
199762306a36Sopenharmony_ci     escrituras o lecturas de memoria compartida accesible tanto para la
199862306a36Sopenharmony_ci     CPU como para un dispositivo compatible con DMA.
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci     Por ejemplo, considere un controlador de dispositivo que comparte
200162306a36Sopenharmony_ci     memoria con otro dispositivo y usa un valor de estado del descriptor
200262306a36Sopenharmony_ci     para indicar si el descriptor pertenece al dispositivo o a la CPU, y
200362306a36Sopenharmony_ci     un "doorbell" (timbre, punto de acceso) para avisarle cuando haya
200462306a36Sopenharmony_ci     nuevos descriptores disponibles:
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	if (desc->status != DEVICE_OWN) {
200762306a36Sopenharmony_ci		/* no leer los datos hasta que tengamos el descriptor */
200862306a36Sopenharmony_ci		dma_rmb();
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci		/* leer/modificar datos */
201162306a36Sopenharmony_ci		read_data = desc->data;
201262306a36Sopenharmony_ci		desc->data = write_data;
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci		/* flush de modificaciones antes de la actualización de estado */
201562306a36Sopenharmony_ci		dma_wmb();
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci		/* asignar propiedad */
201862306a36Sopenharmony_ci		desc->status = DEVICE_OWN;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci		/* notificar al dispositivo de nuevos descriptores */
202162306a36Sopenharmony_ci		writel(DESC_NOTIFY, doorbell);
202262306a36Sopenharmony_ci	}
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci     El dma_rmb() nos permite garantizar que el dispositivo ha liberado su
202562306a36Sopenharmony_ci     propiedad antes de que leamos los datos del descriptor, y el dma_wmb()
202662306a36Sopenharmony_ci     permite garantizar que los datos se escriben en el descriptor antes de
202762306a36Sopenharmony_ci     que el dispositivo pueda ver que ahora tiene la propiedad. El dma_mb()
202862306a36Sopenharmony_ci     implica tanto un dma_rmb() como un dma_wmb(). Tenga en cuenta que, al
202962306a36Sopenharmony_ci     usar writel(), no se necesita un wmb() anterior para garantizar que
203062306a36Sopenharmony_ci     las escrituras de la memoria caché coherente se hayan completado antes
203162306a36Sopenharmony_ci     escribiendo a la región MMIO. El writel_relaxed() más barato no
203262306a36Sopenharmony_ci     proporciona esta garantía y no debe utilizarse aquí.
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci     Consulte la subsección "Efectos de barrera de E/S del kernel" para
203562306a36Sopenharmony_ci     obtener más información sobre accesorios de E/S relajados y el archivo
203662306a36Sopenharmony_ci     Documentation/core-api/dma-api.rst para más información sobre memoria
203762306a36Sopenharmony_ci     consistente.
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci (*) pmem_wmb();
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci     Es es para uso con memoria persistente para garantizar que los stores
204262306a36Sopenharmony_ci     para los que las modificaciones se escriben en el almacenamiento
204362306a36Sopenharmony_ci     persistente llegaron a dominio de durabilidad de la plataforma.
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci     Por ejemplo, después de una escritura no temporal en la región pmem,
204662306a36Sopenharmony_ci     usamos pmem_wmb() para garantizar que los stores hayan alcanzado el
204762306a36Sopenharmony_ci     dominio de durabilidad de la plataforma. Esto garantiza que los stores
204862306a36Sopenharmony_ci     han actualizado el almacenamiento persistente antes de cualquier
204962306a36Sopenharmony_ci     acceso a datos o transferencia de datos causada por instrucciones
205062306a36Sopenharmony_ci     posteriores. Esto es además del orden realizado por wmb().
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci     Para la carga desde memoria persistente, las barreras de memoria de
205362306a36Sopenharmony_ci     lectura existentes son suficientes para garantizar el orden de
205462306a36Sopenharmony_ci     lectura.
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci (*) io_stop_wc();
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci     Para accesos a memoria con atributos de combinación de escritura (por
205962306a36Sopenharmony_ci     ejemplo, los devueltos por ioremap_wc(), la CPU puede esperar a que
206062306a36Sopenharmony_ci     los accesos anteriores se junten con posteriores. io_stop_wc() se
206162306a36Sopenharmony_ci     puede utilizar para evitar la combinación de accesos a memoria de
206262306a36Sopenharmony_ci     de escritura antes de esta macro, con los posteriores, cuando dicha
206362306a36Sopenharmony_ci     espera tenga implicaciones en el rendimiento.
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci=========================================
206662306a36Sopenharmony_ciBARRERAS DE MEMORIA IMPLÍCITAS DEL KERNEL
206762306a36Sopenharmony_ci=========================================
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ciAlgunas de las otras funciones en el kernel Linux implican barreras de
207062306a36Sopenharmony_cimemoria, entre estas encontramos funciones de bloqueo y planificación
207162306a36Sopenharmony_ci("scheduling").
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ciEsta especificación es una garantía _mínima_; cualquier arquitectura
207462306a36Sopenharmony_ciparticular puede proporcionar garantías más sustanciales, pero no se puede
207562306a36Sopenharmony_ciconfiar en estas fuera de código específico de arquitectura.
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ciFUNCIONES DE ADQUISICIÓN DE CERROJO
207962306a36Sopenharmony_ci-----------------------------------
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ciEl kernel Linux tiene una serie de abstracciones de bloqueo:
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci (*) spin locks (cerrojos en loop)
208462306a36Sopenharmony_ci (*) R/W spin lock (cerrojos de escritura/lectura)
208562306a36Sopenharmony_ci (*) mutex
208662306a36Sopenharmony_ci (*) semáforos
208762306a36Sopenharmony_ci (*) R/W semáforos
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ciEn todos los casos existen variantes de las operaciones "ACQUIRE" y
209062306a36Sopenharmony_ci"RELEASE" para cada uno de ellos. Todas estas operaciones implican ciertas
209162306a36Sopenharmony_cibarreras:
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci (1) Implicaciones de la operación ACQUIRE:
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci     Las operaciones de memoria emitidas después del ACQUIRE se completarán
209662306a36Sopenharmony_ci     después de que la operación ACQUIRE haya finalizado.
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci     Las operaciones de memoria emitidas antes de ACQUIRE pueden
209962306a36Sopenharmony_ci     completarse después que la operación ACQUIRE se ha completado.
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci (2) Implicaciones de la operación RELEASE:
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci     Las operaciones de memoria emitidas antes de la RELEASE se
210462306a36Sopenharmony_ci     completarán antes de que la operación de RELEASE se haya completado.
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci     Las operaciones de memoria emitidas después de la RELEASE pueden
210762306a36Sopenharmony_ci     completarse antes de que la operación de RELEASE se haya completado.
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci (3) Implicación de ACQUIRE vs ACQUIRE:
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci     Todas las operaciones ACQUIRE emitidas antes de otra operación
211262306a36Sopenharmony_ci     ACQUIRE serán completadas antes de esa operación ACQUIRE.
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci (4) Implicación de ACQUIRE vs RELEASE:
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci     Todas las operaciones ACQUIRE emitidas antes de una operación RELEASE
211762306a36Sopenharmony_ci     serán completadas antes de la operación RELEASE.
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci (5) Implicación de ACQUIRE condicional fallido:
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci     Ciertas variantes de bloqueo de la operación ACQUIRE pueden fallar, ya
212262306a36Sopenharmony_ci     sea debido a no poder obtener el bloqueo de inmediato, o debido a que
212362306a36Sopenharmony_ci     recibieron una señal de desbloqueo mientras dormían esperando que el
212462306a36Sopenharmony_ci     cerrojo estuviera disponible. Los fallos en cerrojos no implican
212562306a36Sopenharmony_ci     ningún tipo de barrera.
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci[!] Nota: una de las consecuencias de que los cerrojos en ACQUIRE y RELEASE
212862306a36Sopenharmony_cisean barreras unidireccionales, es que los efectos de las instrucciones
212962306a36Sopenharmony_cifuera de una sección crítica pueden filtrarse al interior de la sección
213062306a36Sopenharmony_cicrítica.
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ciNo se puede suponer que un ACQUIRE seguido de una RELEASE sea una barrera
213362306a36Sopenharmony_cide memoria completa dado que es posible que un acceso anterior a ACQUIRE
213462306a36Sopenharmony_cisuceda después del ACQUIRE, y un acceso posterior a la RELEASE suceda antes
213562306a36Sopenharmony_cidel RELEASE, y los dos accesos puedan entonces cruzarse:
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	*A = a;
213862306a36Sopenharmony_ci	ACQUIRE M
213962306a36Sopenharmony_ci	RELEASE M
214062306a36Sopenharmony_ci	*B = b;
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_cipuede ocurrir como:
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	ACQUIRE M, STORE *B, STORE *A, RELEASE M
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ciCuando ACQUIRE y RELEASE son bloqueo de adquisición y liberación,
214762306a36Sopenharmony_cirespectivamente, este mismo orden puede ocurrir si el cerrojo ACQUIRE y
214862306a36Sopenharmony_ciRELEASE son para la misma variable de bloqueo, pero solo desde la
214962306a36Sopenharmony_ciperspectiva de otra CPU que no tiene ese bloqueo. En resumen, un ACQUIRE
215062306a36Sopenharmony_ciseguido de un RELEASE NO puede entenderse como una barrera de memoria
215162306a36Sopenharmony_cicompleta.
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ciDe manera similar, el caso inverso de un RELEASE seguido de un ACQUIRE no
215462306a36Sopenharmony_ciimplica una barrera de memoria completa. Por lo tanto, la ejecución de la
215562306a36Sopenharmony_ciCPU de los tramos críticos correspondientes a la RELEASE y la ACQUIRE
215662306a36Sopenharmony_cipueden cruzarse, de modo que:
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	*A = a;
215962306a36Sopenharmony_ci	RELEASE M
216062306a36Sopenharmony_ci	ACQUIRE N
216162306a36Sopenharmony_ci	*B = b;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cipuede ocurrir como:
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	ACQUIRE N, STORE *B, STORE *A, RELEASE M
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ciPodría parecer que este nuevo orden podría introducir un punto muerto.
216862306a36Sopenharmony_ciSin embargo, esto no puede suceder porque si tal punto muerto amenazara
216962306a36Sopenharmony_cicon suceder, el RELEASE simplemente se completaría, evitando así el
217062306a36Sopenharmony_ciinterbloqueo ("deadlock", punto muerto).
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	¿Por qué funciona esto?
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	Un punto clave es que solo estamos hablando de la CPU re-haciendo el
217562306a36Sopenharmony_ci  orden, no el compilador. Si el compilador (o, ya puestos, el
217662306a36Sopenharmony_ci  desarrollador) cambió las operaciones, un deadlock -podría- ocurrir.
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	Pero supongamos que la CPU reordenó las operaciones. En este caso, el
217962306a36Sopenharmony_ci	desbloqueo precede al bloqueo en el código ensamblador. La CPU
218062306a36Sopenharmony_ci  simplemente eligió intentar ejecutar primero la última operación de
218162306a36Sopenharmony_ci  bloqueo. Si hay un interbloqueo, esta operación de bloqueo simplemente
218262306a36Sopenharmony_ci  esperará (o tratará de dormir, pero hablaremos de eso más adelante). La
218362306a36Sopenharmony_ci  CPU eventualmente ejecutará la operación de desbloqueo (que precedió a la
218462306a36Sopenharmony_ci	operación de bloqueo en el código ensamblador), lo que desenmascará el
218562306a36Sopenharmony_ci  potencial punto muerto, permitiendo que la operación de bloqueo tenga
218662306a36Sopenharmony_ci  éxito.
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	Pero, ¿y si el cerrojo es un cerrojo que duerme ("sleeplock")? En tal
218962306a36Sopenharmony_ci  caso, el código intentará entrar al scheduler, donde eventualmente
219062306a36Sopenharmony_ci  encontrará una barrera de memoria, que forzará la operación de desbloqueo
219162306a36Sopenharmony_ci  anterior para completar, nuevamente desentrañando el punto muerto. Podría
219262306a36Sopenharmony_ci	haber una carrera de desbloqueo del sueño ("sleep-unlock race"), pero la
219362306a36Sopenharmony_ci  primitiva de bloqueo necesita resolver tales carreras correctamente en
219462306a36Sopenharmony_ci  cualquier caso.
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ciEs posible que los cerrojos y los semáforos no proporcionen ninguna
219762306a36Sopenharmony_cigarantía de orden en sistemas compilados en UP, por lo que no se puede
219862306a36Sopenharmony_cicontar con tal situación para lograr realmente nada en absoluto,
219962306a36Sopenharmony_ciespecialmente con respecto a los accesos de E/S, a menos que se combinen
220062306a36Sopenharmony_cicon operaciones de inhabilitación de interrupciones.
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ciConsulte también la sección "Efectos de barrera adquiriendo intra-CPU".
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ciComo ejemplo, considere lo siguiente:
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	*A = a;
220862306a36Sopenharmony_ci	*B = b;
220962306a36Sopenharmony_ci	ACQUIRE
221062306a36Sopenharmony_ci	*C = c;
221162306a36Sopenharmony_ci	*D = d;
221262306a36Sopenharmony_ci	RELEASE
221362306a36Sopenharmony_ci	*E = e;
221462306a36Sopenharmony_ci	*F = f;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ciLa siguiente secuencia de eventos es aceptable:
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci  [+] Tenga en cuenta que {*F,*A} indica un acceso combinado.
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ciPero ninguno de los siguientes lo son:
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	{*F,*A}, *B,	ACQUIRE, *C, *D,	RELEASE, *E
222562306a36Sopenharmony_ci	*A, *B, *C,	ACQUIRE, *D,		RELEASE, *E, *F
222662306a36Sopenharmony_ci	*A, *B,		ACQUIRE, *C,		RELEASE, *D, *E, *F
222762306a36Sopenharmony_ci	*B,		ACQUIRE, *C, *D,	RELEASE, {*F,*A}, *E
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ciFUNCIONES DE DESACTIVACIÓN DE INTERRUPCIONES
223262306a36Sopenharmony_ci--------------------------------------------
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ciLas funciones que deshabilitan interrupciones (equivalentes a ACQUIRE) y
223562306a36Sopenharmony_cihabilitan interrupciones (equivalentes a RELEASE) actuarán únicamente como
223662306a36Sopenharmony_cibarrera del compilador. Por consiguiente, si la memoria o la E/S requieren
223762306a36Sopenharmony_cibarreras en tal situación, deben ser provistas por algún otro medio.
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ciFUNCIONES DE DORMIR Y DESPERTAR
224162306a36Sopenharmony_ci-------------------------------
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ciDormir y despertar son eventos marcados ("flagged") en los datos globales
224462306a36Sopenharmony_cique se pueden ver como una interacción entre dos piezas de datos: el estado
224562306a36Sopenharmony_cide la task (hilo, proceso, tarea) que espera el evento y los datos globales
224662306a36Sopenharmony_ciutilizados para indicar el evento. Para asegurarse de que estos parezcan
224762306a36Sopenharmony_cisuceder en el orden correcto, las primitivas para comenzar el proceso de ir
224862306a36Sopenharmony_cia dormir, y las primitivas para iniciar un despertar implican ciertas
224962306a36Sopenharmony_cibarreras.
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ciEn primer lugar, el agente durmiente normalmente sigue algo similar a esta
225262306a36Sopenharmony_cisecuencia de eventos:
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	for (;;) {
225562306a36Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
225662306a36Sopenharmony_ci		if (evento_indicado)
225762306a36Sopenharmony_ci			break;
225862306a36Sopenharmony_ci		schedule(); // planificar
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ciUna barrera de memoria general se obtiene automáticamente mediante
226262306a36Sopenharmony_ciset_current_state() después de haber alterado el estado de la tarea:
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci	CPU 1
226562306a36Sopenharmony_ci	===============================
226662306a36Sopenharmony_ci	set_current_state(); // hacer_estado_actual()
226762306a36Sopenharmony_ci	  smp_store_mb();
226862306a36Sopenharmony_ci	    STORE current->state
226962306a36Sopenharmony_ci	    <barrera general>
227062306a36Sopenharmony_ci	LOAD evento_indicado
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ciset_current_state() puede estar envuelto por:
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	prepare_to_wait(); // preparese_para_esperar();
227562306a36Sopenharmony_ci	prepare_to_wait_exclusive(); // prepararse_para_solo_esperar();
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_cique por lo tanto también implican una barrera de memoria general después de
227862306a36Sopenharmony_ciestablecer el estado. Toda la secuencia anterior está disponible en varias
227962306a36Sopenharmony_ciformas, todas las cuales obtienen la barrera de memoria en el lugar
228062306a36Sopenharmony_cicorrecto:
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	wait_event();
228362306a36Sopenharmony_ci	wait_event_interruptible();
228462306a36Sopenharmony_ci	wait_event_interruptible_exclusive();
228562306a36Sopenharmony_ci	wait_event_interruptible_timeout();
228662306a36Sopenharmony_ci	wait_event_killable();
228762306a36Sopenharmony_ci	wait_event_timeout();
228862306a36Sopenharmony_ci	wait_on_bit();
228962306a36Sopenharmony_ci	wait_on_bit_lock();
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ciEn segundo lugar, el código que realiza una activación normalmente se
229362306a36Sopenharmony_ciasemeja a algo como esto:
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	evento_indicado = 1;
229662306a36Sopenharmony_ci	wake_up(&event_wait_queue); // despertar
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_cio:
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	evento_indicado = 1;
230162306a36Sopenharmony_ci	wake_up_process(event_daemon); // despertar proceso
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ciwake_up() ejecuta una barrera de memoria general si despierta algo. Si no
230462306a36Sopenharmony_cidespierta nada, entonces una barrera de memoria puede o no ser ejecutada;
230562306a36Sopenharmony_cino debe confiar en ello. La barrera se produce antes del acceso al estado
230662306a36Sopenharmony_cide la tarea. En particular, se encuentra entre el STORE para indicar el
230762306a36Sopenharmony_cievento y el STORE para configurar TASK_RUNNING (hilo ejecutando):
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	CPU 1 (Durmiente)			CPU 2 (Despertadora)
231062306a36Sopenharmony_ci	===============================	===============================
231162306a36Sopenharmony_ci	set_current_state();		STORE evento_indicado
231262306a36Sopenharmony_ci	  smp_store_mb();		wake_up();
231362306a36Sopenharmony_ci	    STORE current->state	  ...
231462306a36Sopenharmony_ci	    <barrera general>		  <barrera general>
231562306a36Sopenharmony_ci	LOAD evento_indicado		  if ((LOAD task->state) & TASK_NORMAL)
231662306a36Sopenharmony_ci					    STORE task->state
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_cidonde "task" es el subproceso que se está despertando y es igual al
231962306a36Sopenharmony_ci"current" (hilo actual) de la CPU 1.
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ciPara reiterar, se garantiza la ejecución de una barrera de memoria general
232262306a36Sopenharmony_cimediante wake_up() si algo está realmente despierto, pero de lo contrario
232362306a36Sopenharmony_cino existe tal garantía. Para entender esto, considere la siguiente
232462306a36Sopenharmony_cisecuencia de eventos, donde X e Y son ambos cero inicialmente:
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	CPU 1				CPU 2
232762306a36Sopenharmony_ci	===============================	===============================
232862306a36Sopenharmony_ci	X = 1;				Y = 1;
232962306a36Sopenharmony_ci	smp_mb();			wake_up();
233062306a36Sopenharmony_ci	LOAD Y				LOAD X
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ciSi ocurre una reactivación ("wakeup"), una (al menos) de las dos cargas
233362306a36Sopenharmony_cidebe ver 1. Si, por otro lado, no ocurre una reactivación, ambas cargas
233462306a36Sopenharmony_cipueden ver 0.
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ciwake_up_process() siempre ejecuta una barrera de memoria general. La
233762306a36Sopenharmony_cibarrera, de nuevo, ocurre antes de que se acceda al estado del hilo. En
233862306a36Sopenharmony_ciparticular, si wake_up(), en el fragmento anterior, fuera reemplazado por
233962306a36Sopenharmony_ciuna llamada a wake_up_process(), las dos cargas verían 1, garantizado.
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ciLas funciones de activación disponibles incluyen:
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	complete();
234462306a36Sopenharmony_ci	wake_up();
234562306a36Sopenharmony_ci	wake_up_all();
234662306a36Sopenharmony_ci	wake_up_bit();
234762306a36Sopenharmony_ci	wake_up_interruptible();
234862306a36Sopenharmony_ci	wake_up_interruptible_all();
234962306a36Sopenharmony_ci	wake_up_interruptible_nr();
235062306a36Sopenharmony_ci	wake_up_interruptible_poll();
235162306a36Sopenharmony_ci	wake_up_interruptible_sync();
235262306a36Sopenharmony_ci	wake_up_interruptible_sync_poll();
235362306a36Sopenharmony_ci	wake_up_locked();
235462306a36Sopenharmony_ci	wake_up_locked_poll();
235562306a36Sopenharmony_ci	wake_up_nr();
235662306a36Sopenharmony_ci	wake_up_poll();
235762306a36Sopenharmony_ci	wake_up_process();
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ciEn términos de orden de la memoria, todas estas funciones proporcionan las
236062306a36Sopenharmony_cimismas garantías que un wake_up() (o más fuertes).
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci[!] Tenga en cuenta que las barreras de la memoria implicadas por el
236362306a36Sopenharmony_cidurmiente y el despierto _no_ ordenan varios stores antes del despertar con
236462306a36Sopenharmony_cirespecto a cargas de los valores guardados después de que el durmiente haya
236562306a36Sopenharmony_cillamado a set_current_state(). Por ejemplo, si el durmiente hace:
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	set_current_state(TASK_INTERRUPTIBLE);
236862306a36Sopenharmony_ci	if (evento_indicado)
236962306a36Sopenharmony_ci		break;
237062306a36Sopenharmony_ci	__set_current_state(TASK_RUNNING);
237162306a36Sopenharmony_ci	hacer_algo(my_data);
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ciy el que despierta hace:
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	my_data = valor;
237662306a36Sopenharmony_ci	evento_indicado = 1;
237762306a36Sopenharmony_ci	wake_up(&event_wait_queue);
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_cino existe garantía de que el cambio a event_indicated sea percibido por
238062306a36Sopenharmony_ciel durmiente de manera que venga después del cambio a my_data. En tal
238162306a36Sopenharmony_cicircunstancia, el código en ambos lados debe sacar sus propias barreras de
238262306a36Sopenharmony_cimemoria entre los separados accesos a datos. Por lo tanto, el durmiente
238362306a36Sopenharmony_cianterior debería hacer:
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	set_current_state(TASK_INTERRUPTIBLE);
238662306a36Sopenharmony_ci	if (evento_indicado) {
238762306a36Sopenharmony_ci		smp_rmb();
238862306a36Sopenharmony_ci		hacer_algo(my_data);
238962306a36Sopenharmony_ci	}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ciy el que despierta debería hacer:
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	my_data = value;
239462306a36Sopenharmony_ci	smp_wmb();
239562306a36Sopenharmony_ci	evento_indicado = 1;
239662306a36Sopenharmony_ci	wake_up(&event_wait_queue);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ciFUNCIONES VARIAS
239962306a36Sopenharmony_ci----------------
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ciOtras funciones que implican barreras:
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci (*) schedule() y similares implican barreras completas de memoria.
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci========================================
240762306a36Sopenharmony_ciEFECTOS DE BARRERA ADQUIRIENDO INTRA-CPU
240862306a36Sopenharmony_ci========================================
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ciEn los sistemas SMP, las primitivas de bloqueo proveen una forma más
241162306a36Sopenharmony_cisustancial de barrera: una que afecta el orden de acceso a la memoria en
241262306a36Sopenharmony_ciotras CPU, dentro del contexto de conflicto en cualquier bloqueo en
241362306a36Sopenharmony_ciparticular.
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ciADQUISICIÓN VS ACCESOS A MEMORIA
241762306a36Sopenharmony_ci--------------------------------
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ciConsidere lo siguiente: el sistema tiene un par de spinlocks (M) y (Q), y
242062306a36Sopenharmony_citres CPU; entonces la siguiente secuencia de eventos debería ocurrir:
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	CPU 1				CPU 2
242362306a36Sopenharmony_ci	===============================	===============================
242462306a36Sopenharmony_ci	WRITE_ONCE(*A, a);		WRITE_ONCE(*E, e);
242562306a36Sopenharmony_ci	ACQUIRE M			ACQUIRE Q
242662306a36Sopenharmony_ci	WRITE_ONCE(*B, b);		WRITE_ONCE(*F, f);
242762306a36Sopenharmony_ci	WRITE_ONCE(*C, c);		WRITE_ONCE(*G, g);
242862306a36Sopenharmony_ci	RELEASE M			RELEASE Q
242962306a36Sopenharmony_ci	WRITE_ONCE(*D, d);		WRITE_ONCE(*H, h);
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ciEntonces no hay garantía sobre en qué orden verá la CPU 3 los accesos a *A
243262306a36Sopenharmony_cihasta que *H ocurra, además de las restricciones impuestas por los bloqueos
243362306a36Sopenharmony_ciseparados en las distintas CPUs. Podría, por ejemplo, ver:
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	*E, ACQUIRE M, ACQUIRE Q, *G, *C, *F, *A, *B, RELEASE Q, *D, *H, RELEASE M
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ciPero no verá ninguno de:
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	*B, *C or *D preceding ACQUIRE M
244062306a36Sopenharmony_ci	*A, *B or *C following RELEASE M
244162306a36Sopenharmony_ci	*F, *G or *H preceding ACQUIRE Q
244262306a36Sopenharmony_ci	*E, *F or *G following RELEASE Q
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci========================================
244562306a36Sopenharmony_ci¿DÓNDE SE NECESITAN BARRERAS DE MEMORIA?
244662306a36Sopenharmony_ci========================================
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ciBajo operación normal, el re-ordenamiento de una operación de memoria
244962306a36Sopenharmony_cigeneralmente no va a suponer un problema, ya que para una pieza de código
245062306a36Sopenharmony_cilineal de un solo subproceso seguirá pareciendo que funciona correctamente,
245162306a36Sopenharmony_ciincluso si está en un kernel SMP. Existen, sin embargo, cuatro
245262306a36Sopenharmony_cicircunstancias en las que reordenar definitivamente _podría_ ser un
245362306a36Sopenharmony_ciproblema:
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci (*) Interacción entre procesadores.
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci (*) Operaciones atómicas.
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci (*) Acceso a dispositivos.
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci (*) Interrupciones.
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ciINTERACCIÓN ENTRE PROCESADORES
246562306a36Sopenharmony_ci------------------------------
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ciCuando se da un sistema con más de un procesador, más de una CPU en el
246862306a36Sopenharmony_cisistema puede estar trabajando en el mismo conjunto de datos al mismo
246962306a36Sopenharmony_citiempo. Esto puede causar problemas de sincronización, y la forma habitual
247062306a36Sopenharmony_cide tratar con estos es utilizar cerrojos. Sin embargo, los cerrojos son
247162306a36Sopenharmony_cibastante caros, por lo que puede ser preferible operar sin el uso de un
247262306a36Sopenharmony_cicerrojo a ser posible. En cuyo caso, es posible que las operaciones que
247362306a36Sopenharmony_ciafectan a ambas CPU deban ordenarse cuidadosamente para evitar un
247462306a36Sopenharmony_cifuncionamiento incorrecto.
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ciConsidere, por ejemplo, la ruta lenta del semáforo R/W. Aquí hay un proceso
247762306a36Sopenharmony_cide espera en cola del semáforo, en virtud de que tiene una parte de su pila
247862306a36Sopenharmony_civinculada a la lista de procesos en espera del semáforo:
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	struct rw_semaphore {
248162306a36Sopenharmony_ci		...
248262306a36Sopenharmony_ci		spinlock_t lock;
248362306a36Sopenharmony_ci		struct list_head waiters;
248462306a36Sopenharmony_ci	};
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	struct rwsem_waiter {
248762306a36Sopenharmony_ci		struct list_head list;
248862306a36Sopenharmony_ci		struct task_struct *task;
248962306a36Sopenharmony_ci	};
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ciPara despertar a un proceso que espera ("waiter") en particular, las
249262306a36Sopenharmony_cifunciones up_read() o up_write() tienen que:
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci (1) leer el siguiente puntero del registro de este proceso que espera,
249562306a36Sopenharmony_ci     para saber dónde está el registro del siguiente waiter;
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci (2) leer el puntero a la estructura de tareas del waiter;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci (3) borrar el puntero de la tarea para decirle al waiter que se le ha dado
250062306a36Sopenharmony_ci     el semáforo;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci (4) llamar a wake_up_process() en la tarea; y
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci (5) liberar la referencia retenida en la estructura de tareas del waiter.
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ciEn otras palabras, tiene que realizar esta secuencia de eventos:
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	LOAD waiter->list.next;
250962306a36Sopenharmony_ci	LOAD waiter->task;
251062306a36Sopenharmony_ci	STORE waiter->task;
251162306a36Sopenharmony_ci	CALL wakeup
251262306a36Sopenharmony_ci	RELEASE task
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ciy si alguno de estos pasos ocurre fuera de orden, entonces todo puede que
251562306a36Sopenharmony_cifuncione defectuosamente.
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ciUna vez que se ha puesto en cola y soltado el bloqueo de semáforo, el
251862306a36Sopenharmony_ciproceso que espera no consigue el candado de nuevo; en cambio, solo espera
251962306a36Sopenharmony_cia que se borre su puntero de tarea antes de continuar. Dado que el registro
252062306a36Sopenharmony_ciestá en la pila del proceso que espera, esto significa que si el puntero de
252162306a36Sopenharmony_cila tarea se borra _antes_ de que se lea el siguiente puntero de la lista,
252262306a36Sopenharmony_ciotra CPU podría comenzar a procesar el proceso que espera y podría romper
252362306a36Sopenharmony_ciel stack del proceso que espera antes de que la función up*() tenga la
252462306a36Sopenharmony_cioportunidad de leer el puntero que sigue.
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ciConsidere entonces lo que podría suceder con la secuencia de eventos
252762306a36Sopenharmony_cianterior:
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	CPU 1				CPU 2
253062306a36Sopenharmony_ci	===============================	===============================
253162306a36Sopenharmony_ci					down_xxx()
253262306a36Sopenharmony_ci					Poner waiter en la "queue" (cola)
253362306a36Sopenharmony_ci					Dormir
253462306a36Sopenharmony_ci	up_yyy()
253562306a36Sopenharmony_ci	LOAD waiter->task;
253662306a36Sopenharmony_ci	STORE waiter->task;
253762306a36Sopenharmony_ci					Despertado por otro evento
253862306a36Sopenharmony_ci	<preempt>
253962306a36Sopenharmony_ci					Reanudar el procesamiento
254062306a36Sopenharmony_ci					down_xxx() regresa
254162306a36Sopenharmony_ci					llamada a foo()
254262306a36Sopenharmony_ci					foo() estropea *waiter
254362306a36Sopenharmony_ci	</preempt>
254462306a36Sopenharmony_ci	LOAD waiter->list.next;
254562306a36Sopenharmony_ci	--- OOPS ---
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ciEsto podría solucionarse usando el bloqueo de semáforo, pero luego la
254862306a36Sopenharmony_cifunción down_xxx() tiene que obtener innecesariamente el spinlock
254962306a36Sopenharmony_cinuevamente, después de ser despertado el hilo.
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ciLa forma de lidiar con esto es insertar una barrera de memoria SMP general:
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	LOAD waiter->list.next;
255462306a36Sopenharmony_ci	LOAD waiter->task;
255562306a36Sopenharmony_ci	smp_mb();
255662306a36Sopenharmony_ci	STORE waiter->task;
255762306a36Sopenharmony_ci	CALL wakeup
255862306a36Sopenharmony_ci	RELEASE task
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ciEn este caso, la barrera garantiza que todos los accesos a memoria antes de
256162306a36Sopenharmony_cila barrera parecerán suceder antes de todos los accesos a memoria después
256262306a36Sopenharmony_cide dicha barrera con respecto a las demás CPU del sistema. _No_ garantiza
256362306a36Sopenharmony_cique todos los accesos a memoria antes de la barrera se completarán en el
256462306a36Sopenharmony_cimomento en que la instrucción de la barrera en sí se complete.
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ciEn un sistema UP, donde esto no sería un problema, la función smp_mb() es
256762306a36Sopenharmony_cisolo una barrera del compilador, asegurándose así de que el compilador
256862306a36Sopenharmony_ciemita las instrucciones en el orden correcto sin realmente intervenir en la
256962306a36Sopenharmony_ciCPU. Como solo hay un CPU, la lógica de orden de dependencias de esa CPU se
257062306a36Sopenharmony_ciencargará de todo lo demás.
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ciOPERACIONES ATÓMICAS
257462306a36Sopenharmony_ci--------------------
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ciSi bien son, técnicamente, consideraciones de interacción entre
257762306a36Sopenharmony_ciprocesadores, las operaciones atómicas se destacan especialmente porque
257862306a36Sopenharmony_cialgunas de ellas implican barreras de memoria completa y algunas otras no,
257962306a36Sopenharmony_cipero se confía mucho en ellos en su conjunto a lo largo del kernel.
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ciConsulte Documentation/atomic_t.txt para obtener más información.
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ciACCESO A DISPOSITIVOS
258562306a36Sopenharmony_ci---------------------
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ciUn driver puede ser interrumpido por su propia rutina de servicio de
258862306a36Sopenharmony_ciinterrupción y, por lo tanto, las dos partes del driver pueden interferir
258962306a36Sopenharmony_cicon los intentos de controlar o acceder al dispositivo.
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ciEsto puede aliviarse, al menos en parte, desactivando las interrupciones
259262306a36Sopenharmony_cilocales (una forma de bloqueo), de modo que las operaciones críticas sean
259362306a36Sopenharmony_citodas contenidas dentro la sección de interrupción desactivada en el
259462306a36Sopenharmony_cicontrolador. Mientras la interrupción del driver está ejecutando la rutina,
259562306a36Sopenharmony_cies posible que el "core" del controlador no se ejecute en la misma CPU y no
259662306a36Sopenharmony_cise permita que su interrupción vuelva a ocurrir hasta que la interrupción
259762306a36Sopenharmony_ciactual haya sido resuelta, por lo tanto, el controlador de interrupción no
259862306a36Sopenharmony_cinecesita bloquearse contra esto.
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ciSin embargo, considere un driver que estaba hablando con una tarjeta
260162306a36Sopenharmony_ciethernet que tiene un registro de direcciones y un registro de datos. Si
260262306a36Sopenharmony_ciel core de ese controlador habla con la tarjeta estando en desactivación de
260362306a36Sopenharmony_ciinterrupción y luego se invoca el controlador de interrupción del
260462306a36Sopenharmony_cicontrolador:
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	IRQ LOCALES DESACTIVADAS
260762306a36Sopenharmony_ci	writew(ADDR, 3);
260862306a36Sopenharmony_ci	writew(DATA, y);
260962306a36Sopenharmony_ci	IRQ LOCALES ACTIVADAS
261062306a36Sopenharmony_ci	<interrupción>
261162306a36Sopenharmony_ci	writew(ADDR, 4);
261262306a36Sopenharmony_ci	q = readw(DATA);
261362306a36Sopenharmony_ci	</interrupción>
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ciEl almacenamiento en el registro de datos puede ocurrir después del segundo
261662306a36Sopenharmony_cialmacenamiento en el registro de direcciones si las reglas de orden son lo
261762306a36Sopenharmony_cisuficientemente relajadas:
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci  	STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ciSi se relajan las reglas de orden, se debe asumir que los accesos
262262306a36Sopenharmony_cirealizados dentro de la sección con interrupción deshabilitada pueden
262362306a36Sopenharmony_cifiltrarse fuera de esta y pueden intercalarse con accesos realizados en una
262462306a36Sopenharmony_ciinterrupción - y viceversa - a menos que se utilicenn barreras implícita o
262562306a36Sopenharmony_ciexplícitas.
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ciNormalmente, esto no será un problema porque los accesos de E/S realizados
262862306a36Sopenharmony_cidentro de tales secciones incluirán operaciones de carga síncronas en
262962306a36Sopenharmony_ciregistros E/S estrictamente ordenados, que forman barreras de E/S
263062306a36Sopenharmony_ciimplícitas.
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ciUna situación similar puede ocurrir entre una rutina de interrupción y dos
263462306a36Sopenharmony_cirutinas ejecutándose en separadas CPU que se comunican entre sí. Si tal
263562306a36Sopenharmony_cicaso es probable, entonces se deben usar bloqueos de desactivación de
263662306a36Sopenharmony_ciinterrupciones para garantizar el orden.
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci=====================================
264062306a36Sopenharmony_ci Efectos de barrera de E/S del kernel
264162306a36Sopenharmony_ci=====================================
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ciLa interfaz con periféricos a través de accesos de E/S es profundamente
264462306a36Sopenharmony_ciespecífica para cada arquitectura y dispositivo. Por lo tanto, los drivers
264562306a36Sopenharmony_cique son inherentemente no portátiles pueden depender de comportamientos
264662306a36Sopenharmony_ciespecíficos de sus sistemas de destino, con el fin de lograr la
264762306a36Sopenharmony_cisincronización de la manera más ligera posible. Para drivers que deseen ser
264862306a36Sopenharmony_ciportátiles entre múltiples arquitecturas e implementaciones de bus, el
264962306a36Sopenharmony_cikernel ofrece una serie de funciones de acceso que proporcionan varios
265062306a36Sopenharmony_cigrados de garantías de orden:
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci (*) readX(), writeX():
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	Las funciones de acceso MMIO readX() y writeX() usan un puntero al
265562306a36Sopenharmony_ci	periférico al que se accede como un parámetro __iomem *. para punteros
265662306a36Sopenharmony_ci	asignados los atributos de E/S predeterminados (por ejemplo, los
265762306a36Sopenharmony_ci        devueltos por ioremap()), las garantías de orden son las siguientes:
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	1. Se ordenan todos los accesos readX() y writeX() a un mismo periférico
266062306a36Sopenharmony_ci	   entre estos. Esto asegura que los registros de acceso MMIO por el
266162306a36Sopenharmony_ci	   mismo subproceso de la CPU a un dispositivo en particular llegarán en
266262306a36Sopenharmony_ci	   el orden del programa.
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	2. Se ordena un writeX() emitido por un subproceso de CPU que contiene un
266562306a36Sopenharmony_ci	   spinlock antes de un writeX() al mismo periférico desde otro
266662306a36Sopenharmony_ci           subproceso de CPU, si emitido después de una adquisición posterior del
266762306a36Sopenharmony_ci	   mismo spinlock. Esto garantiza que ese registro MMIO escribe en un
266862306a36Sopenharmony_ci           dispositivo en particular, mientras que se obtiene un spinlock en un
266962306a36Sopenharmony_ci           orden consistente con las adquisiciones del cerrojo.
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	3. Un writeX() por un subproceso de la CPU al periférico primero esperará
267262306a36Sopenharmony_ci	   a la finalización de todas las escrituras anteriores en la memoria
267362306a36Sopenharmony_ci           emitidas por, o bien propagadas por, el mismo subproceso. Esto asegura
267462306a36Sopenharmony_ci	   que las escrituras de la CPU a un búfer DMA de salida asignadas por
267562306a36Sopenharmony_ci           dma_alloc_coherent() serán visibles para un motor ("engine") DMA
267662306a36Sopenharmony_ci           cuando la CPU escriba en sus registros de control MMIO, para activar
267762306a36Sopenharmony_ci           la transferencia.
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	4. Un readX() de un subproceso del CPU, desde el periférico, se
268062306a36Sopenharmony_ci	   completará antes de que cualquier lectura subsiguiente de memoria por
268162306a36Sopenharmony_ci	   el mismo subproceso pueda comenzar. Esto asegura que las lecturas de
268262306a36Sopenharmony_ci           la CPU desde un búfer DMA entrantes asignadas por
268362306a36Sopenharmony_ci           dma_alloc_coherent(), no verán datos obsoletos después de leer el
268462306a36Sopenharmony_ci           registro de estado MMIO del motor DMA, para establecer que la
268562306a36Sopenharmony_ci           transferencia DMA se haya completado.
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	5. Un readX() por un subproceso del CPU, desde el periférico, se
268862306a36Sopenharmony_ci	   completará antes de que cualquier bucle delay() subsiguiente pueda
268962306a36Sopenharmony_ci           comenzar a ejecutarse en el mismo subproceso. Esto asegura que dos
269062306a36Sopenharmony_ci           escrituras del CPU a registros MMIO en un periférico llegarán al menos
269162306a36Sopenharmony_ci	   con 1us de diferencia, si la primera escritura se lee inmediatamente
269262306a36Sopenharmony_ci           de vuelta con readX() y se llama a udelay(1) antes del segundo
269362306a36Sopenharmony_ci           writeX():
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci		writel(42, DEVICE_REGISTER_0); // Llega al dispositivo ...
269662306a36Sopenharmony_ci		readl(DEVICE_REGISTER_0);
269762306a36Sopenharmony_ci		udelay(1);
269862306a36Sopenharmony_ci		writel(42, DEVICE_REGISTER_1); // al menos 1us antes de esto....
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ciLas propiedades de orden de los punteros __iomem obtenidos con valores de
270162306a36Sopenharmony_ciatributos que no sean los valores por defecto (por ejemplo, los devueltos
270262306a36Sopenharmony_cipor ioremap_wc()) son específicos de la arquitectura subyacente y, por lo
270362306a36Sopenharmony_citanto, las garantías enumeradas anteriormente no pueden por lo general ser
270462306a36Sopenharmony_ciaseguradas para accesos a este tipo de "mappings" (asignaciones).
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci (*) readX_relaxed(), writeX_relaxed():
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	Son similares a readX() y writeX(), pero proporcionan una garantía de
270962306a36Sopenharmony_ci        orden de memoria más débil. Específicamente, no garantizan orden con
271062306a36Sopenharmony_ci	respecto al bloqueo, los accesos normales a la memoria o los bucles
271162306a36Sopenharmony_ci        delay() (es decir, los puntos 2-5 arriba) pero todavía se garantiza que
271262306a36Sopenharmony_ci        se ordenarán con respecto a otros accesos desde el mismo hilo de la CPU,
271362306a36Sopenharmony_ci        al mismo periférico, cuando se opera en punteros __iomem asignados con el
271462306a36Sopenharmony_ci        valor predeterminado para los atributos de E/S.
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci (*) readsX(), writesX():
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	Los puntos de entrada readsX() y writesX() MMIO están diseñados para
271962306a36Sopenharmony_ci        acceder FIFOs mapeados en memoria y basados en registros que residen en
272062306a36Sopenharmony_ci        periféricos, que no son capaces de realizar DMA. Por tanto, sólo
272162306a36Sopenharmony_ci        proporcionan garantías de orden readX_relaxed() y writeX_relaxed(), como
272262306a36Sopenharmony_ci        se documentó anteriormente.
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci (*) inX(), outX():
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	Los puntos de entrada inX() y outX() están destinados a acceder a mapas
272762306a36Sopenharmony_ci        de puertos "legacy" (antiguos) de periféricos de E/S, que pueden requerir
272862306a36Sopenharmony_ci	instrucciones especiales en algunas arquitecturas (especialmente, en
272962306a36Sopenharmony_ci        x86). El número de puerto del periférico que se está accedido se pasa
273062306a36Sopenharmony_ci        como un argumento.
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	Dado que muchas arquitecturas de CPU acceden finalmente a estos
273362306a36Sopenharmony_ci        periféricos a través de un mapeo interno de memoria virtual, las
273462306a36Sopenharmony_ci        garantías de orden portátiles proporcionadas por inX() y outX() son las
273562306a36Sopenharmony_ci        mismas que las proporcionadas por readX() y writeX(), respectivamente, al
273662306a36Sopenharmony_ci        acceder a una asignación con los valores de atributos de E/S
273762306a36Sopenharmony_ci        predeterminados (los que haya por defecto).
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci        Los drivers de dispositivos pueden esperar que outX() emita una
274062306a36Sopenharmony_ci        transacción de escritura no publicada, que espera una respuesta de
274162306a36Sopenharmony_ci        finalización del periférico de E/S antes de regresar. Esto no está
274262306a36Sopenharmony_ci        garantizado por todas las arquitecturas y por lo tanto no forma parte de
274362306a36Sopenharmony_ci        la semántica de orden portátil.
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci (*) insX(), outsX():
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci        Como arriba, los puntos de entrada insX() y outsX() proporcionan el mismo
274862306a36Sopenharmony_ci        orden garantizado por readsX() y writesX() respectivamente, al acceder a
274962306a36Sopenharmony_ci        un mapping con los atributos de E/S predeterminados.
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci (*) ioreadX(), iowriteX():
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci        Estos funcionarán adecuadamente para el tipo de acceso que realmente están
275462306a36Sopenharmony_ci        haciendo, ya sea inX()/outX() o readX()/writeX().
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ciCon la excepción de los puntos de entrada (insX(), outsX(), readsX() y
275762306a36Sopenharmony_ciwritesX()), todo lo anterior supone que el periférico subyacente es
275862306a36Sopenharmony_cilittle-endian y, por lo tanto, realizará operaciones de intercambio de
275962306a36Sopenharmony_cibytes en arquitecturas big-endian.
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci===========================================
276362306a36Sopenharmony_ciMODELO DE ORDEN MÍNIMO DE EJECUCIÓN ASUMIDO
276462306a36Sopenharmony_ci===========================================
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ciDebe suponerse que la CPU conceptual está débilmente ordenada, pero que
276762306a36Sopenharmony_cimantiene la apariencia de causalidad del programa con respecto a sí misma.
276862306a36Sopenharmony_ciAlgunas CPU (como i386 o x86_64) están más limitadas que otras (como
276962306a36Sopenharmony_cipowerpc o frv), por lo que el caso más relajado (es decir, DEC Alpha) se
277062306a36Sopenharmony_cidebe asumir fuera de código específico de arquitectura.
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ciEsto significa que se debe considerar que la CPU ejecutará su flujo de
277362306a36Sopenharmony_ciinstrucciones en el orden que se quiera - o incluso en paralelo - siempre
277462306a36Sopenharmony_cique si una instrucción en el flujo depende de una instrucción anterior,
277562306a36Sopenharmony_cientonces dicha instrucción anterior debe ser lo suficientemente completa[*]
277662306a36Sopenharmony_ciantes de que la posterior instrucción puede proceder; en otras palabras:
277762306a36Sopenharmony_cisiempre que la apariencia de causalidad se mantenga.
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci [*] Algunas instrucciones tienen más de un efecto, como cambiar el
278062306a36Sopenharmony_ci     código de condición, cambio de registros o cambio de memoria - y
278162306a36Sopenharmony_ci     distintas instrucciones pueden depender de diferentes efectos.
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ciUna CPU puede también descartar cualquier secuencia de instrucciones que
278462306a36Sopenharmony_citermine sin tener efecto final. Por ejemplo, si dos instrucciones
278562306a36Sopenharmony_ciadyacentes cargan un valor inmediato en el mismo registro, la primera puede
278662306a36Sopenharmony_cidescartarse.
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ciDe manera similar, se debe suponer que el compilador podría reordenar la
279062306a36Sopenharmony_cicorriente de instrucciones de la manera que crea conveniente, nuevamente
279162306a36Sopenharmony_cisiempre que la apariencia de causalidad se mantenga.
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci=====================================
279562306a36Sopenharmony_ciEFECTOS DE LA MEMORIA CACHÉ DE LA CPU
279662306a36Sopenharmony_ci=====================================
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ciLa forma en que se perciben las operaciones de memoria caché en todo el
279962306a36Sopenharmony_cisistema se ve afectada, hasta cierto punto, por los cachés que se
280062306a36Sopenharmony_ciencuentran entre las CPU y la memoria, y por el sistema de coherencia en
280162306a36Sopenharmony_cimemoria que mantiene la consistencia de estado en el sistema.
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ciEn cuanto a la forma en que una CPU interactúa con otra parte del sistema a
280462306a36Sopenharmony_citravés del caché, el sistema de memoria tiene que incluir los cachés de la
280562306a36Sopenharmony_ciCPU y barreras de memoria, que en su mayor parte actúan en la interfaz
280662306a36Sopenharmony_cientre la CPU y su caché (las barreras de memoria lógicamente actúan sobre
280762306a36Sopenharmony_cila línea de puntos en el siguiente diagrama):
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	    <--- CPU --->         :       <----------- Memoria ----------->
281062306a36Sopenharmony_ci	                          :
281162306a36Sopenharmony_ci	+--------+    +--------+  :   +--------+    +-----------+
281262306a36Sopenharmony_ci	|  Core  |    | Cola   |  :   | Cache  |    |           |    +---------+
281362306a36Sopenharmony_ci	|  CPU   |    | de     |  :   | CPU    |    |           |    |         |
281462306a36Sopenharmony_ci	|        |--->| acceso |----->|        |<-->|           |    |         |
281562306a36Sopenharmony_ci	|        |    | a      |  :   |        |    |           |--->| Memoria |
281662306a36Sopenharmony_ci	|        |    | memoria|  :   |        |    |           |    |         |
281762306a36Sopenharmony_ci	+--------+    +--------+  :   +--------+    | Mecanismo |    |         |
281862306a36Sopenharmony_ci	                          :                 | de        |    +---------+
281962306a36Sopenharmony_ci	                          :                 | Coherencia|
282062306a36Sopenharmony_ci	                          :                 | de la     |    +--------+
282162306a36Sopenharmony_ci	+--------+    +--------+  :   +--------+    | cache     |    |	      |
282262306a36Sopenharmony_ci	|  Core  |    | Cola   |  :   | Cache  |    |           |    |        |
282362306a36Sopenharmony_ci	|  CPU   |    | de     |  :   | CPU    |    |           |--->| Dispos |
282462306a36Sopenharmony_ci	|        |--->| acceso |----->|        |<-->|           |    | itivo  |
282562306a36Sopenharmony_ci	|        |    | a      |  :   |        |    |           |    |        |
282662306a36Sopenharmony_ci	|        |    | memoria|  :   |        |    |           |    +--------+
282762306a36Sopenharmony_ci	+--------+    +--------+  :   +--------+    +-----------+
282862306a36Sopenharmony_ci	                          :
282962306a36Sopenharmony_ci	                          :
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ciAunque es posible que una carga o store en particular no aparezca fuera de
283262306a36Sopenharmony_cila CPU que lo emitió, ya que puede haber sido satisfecha dentro del propio
283362306a36Sopenharmony_cicaché de la CPU, seguirá pareciendo como si el acceso total a la memoria
283462306a36Sopenharmony_cihubiera tenido lugar para las otras CPUs, ya que los mecanismos de
283562306a36Sopenharmony_cicoherencia de caché migrarán la cacheline sobre la CPU que accede y se
283662306a36Sopenharmony_cipropagarán los efectos en caso de conflicto.
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ciEl núcleo de la CPU puede ejecutar instrucciones en el orden que considere
283962306a36Sopenharmony_ciadecuado, siempre que parezca mantenerse la causalidad esperada del
284062306a36Sopenharmony_ciprograma. Algunas de las instrucciones generan operaciones de carga y
284162306a36Sopenharmony_cialmacenamiento que luego van a la cola de accesos a memoria a realizar. El
284262306a36Sopenharmony_cinúcleo puede colocarlos en la cola en cualquier orden que desee, y
284362306a36Sopenharmony_cicontinuar su ejecución hasta que se vea obligado a esperar que una
284462306a36Sopenharmony_ciinstrucción sea completada.
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ciDe lo que se ocupan las barreras de la memoria es de controlar el orden en
284762306a36Sopenharmony_cique los accesos cruzan, desde el lado de la CPU, hasta el lado de memoria,
284862306a36Sopenharmony_ciy el orden en que los otros observadores perciben los efectos en el sistema
284962306a36Sopenharmony_cique sucedan por esto.
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci[!] Las barreras de memoria _no_ son necesarias dentro de una CPU
285262306a36Sopenharmony_cideterminada, ya que las CPU siempre ven sus propias cargas y stores como si
285362306a36Sopenharmony_cihubieran sucedido en el orden del programa.
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci[!] Los accesos a MMIO u otros dispositivos pueden pasar por alto el
285662306a36Sopenharmony_cisistema de caché. Esto depende de las propiedades de la ventana de memoria
285762306a36Sopenharmony_cia través de la cual se accede a los dispositivos y/o el uso de
285862306a36Sopenharmony_ciinstrucciones especiales de comunicación con dispositivo que pueda tener la
285962306a36Sopenharmony_ciCPU.
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ciCOHERENCIA DE CACHÉ FRENTE A DMA
286362306a36Sopenharmony_ci---------------------------------
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ciNo todos los sistemas mantienen coherencia de caché con respecto a los
286662306a36Sopenharmony_cidispositivos que realizan DMA. En tales casos, un dispositivo que intente
286762306a36Sopenharmony_ciDMA puede obtener datos obsoletos de la RAM, porque las líneas de caché
286862306a36Sopenharmony_ci"sucias" pueden residir en los cachés de varias CPU, y es posible que no
286962306a36Sopenharmony_cise hayan vuelto a escribir en la RAM todavía. Para hacer frente a esto, la
287062306a36Sopenharmony_ciparte apropiada del kernel debe vaciar los bits superpuestos de caché en
287162306a36Sopenharmony_cicada CPU (y tal vez también invalidarlos).
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ciAdemás, los datos enviados por DMA a RAM, por un dispositivo, pueden ser
287462306a36Sopenharmony_cisobrescritos por líneas de caché sucias que se escriben de nuevo en la RAM
287562306a36Sopenharmony_cidesde el caché de una CPU, después de que el dispositivo haya puesto sus
287662306a36Sopenharmony_cipropios datos, o las líneas de caché presentes en el caché de la CPU pueden
287762306a36Sopenharmony_cisimplemente ocultar el hecho de que la memoria RAM se haya actualizado,
287862306a36Sopenharmony_cihasta el momento en que la caché se descarta de la memoria caché de la CPU
287962306a36Sopenharmony_ciy se vuelve a cargar. Para hacer frente a esto, la parte apropiada del
288062306a36Sopenharmony_cikernel debe invalidar los bits superpuestos del caché en cada CPU.
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ciConsulte Documentation/core-api/cachetlb.rst para obtener más información
288362306a36Sopenharmony_cisobre administración de la memoria caché.
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ciCOHERENCIA DE CACHÉ FRENTE A MMIO
288762306a36Sopenharmony_ci---------------------------------
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ciLa E/S mapeada en memoria generalmente se lleva a cabo a través de
289062306a36Sopenharmony_ciubicaciones de memoria que forman parte de una ventana del espacio de
289162306a36Sopenharmony_cimemoria de la CPU, que tiene diferentes propiedades asignadas que la
289262306a36Sopenharmony_civentana habitual dirigida a RAM.
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ciEntre dichas propiedades, suele existir el hecho de que tales accesos
289562306a36Sopenharmony_cieluden el almacenamiento en caché por completo e ir directamente a los
289662306a36Sopenharmony_cibuses del dispositivo. Esto significa que los accesos MMIO pueden, en
289762306a36Sopenharmony_ciefecto, superar los accesos a la memoria caché que se emitieron
289862306a36Sopenharmony_cianteriormente. Una barrera de memoria no es suficiente en tal caso, sino
289962306a36Sopenharmony_cique el caché debe ser vaciado entre la escritura de la memoria caché, y el
290062306a36Sopenharmony_ciacceso MMIO, si los dos son de cualquier manera dependiente.
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci=======================
290462306a36Sopenharmony_ciCOSAS QUE HACEN LAS CPU
290562306a36Sopenharmony_ci=======================
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ciUn programador podría dar por sentado que la CPU realizará las operaciones
290862306a36Sopenharmony_cide memoria exactamente en el orden especificado, de modo que si a la CPU se
290962306a36Sopenharmony_cientrega, por ejemplo, el siguiente fragmento de código a ejecutar:
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	a = READ_ONCE(*A);
291262306a36Sopenharmony_ci	WRITE_ONCE(*B, b);
291362306a36Sopenharmony_ci	c = READ_ONCE(*C);
291462306a36Sopenharmony_ci	d = READ_ONCE(*D);
291562306a36Sopenharmony_ci	WRITE_ONCE(*E, e);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ciesperarían entonces que la CPU complete la operación de memoria para cada
291862306a36Sopenharmony_ciinstrucción antes de pasar a la siguiente, lo que lleva a una definida
291962306a36Sopenharmony_cisecuencia de operaciones vistas por observadores externos en el sistema:
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci  	LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ciLa realidad es, por supuesto, mucho más intrincada. Para muchas CPU y
292462306a36Sopenharmony_cicompiladores, la anterior suposición no se sostiene porque:
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci (*) es más probable que las cargas deban completarse de inmediato para
292762306a36Sopenharmony_ci     permitir progreso en la ejecución, mientras que los stores a menudo se
292862306a36Sopenharmony_ci     pueden aplazar sin problema;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci (*) las cargas se pueden hacer especulativamente, y el resultado es
293162306a36Sopenharmony_ci     descartado si resulta innecesario;
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci (*) las cargas se pueden hacer de forma especulativa, lo que lleva a que
293462306a36Sopenharmony_ci     se haya obtenido el resultado en el momento equivocado de la secuencia
293562306a36Sopenharmony_ci     de eventos esperada;
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci (*) el orden de los accesos a memoria se puede reorganizar para promover
293862306a36Sopenharmony_ci     un mejor uso de los buses y cachés de la CPU;
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci (*) las cargas y los stores se pueden combinar para mejorar el rendimiento
294162306a36Sopenharmony_ci     cuando se habla con memoria o hardware de E/S, que puede realizar
294262306a36Sopenharmony_ci     accesos por lotes a ubicaciones adyacentes, reduciendo así los costes
294362306a36Sopenharmony_ci     de configuración de transacciones (la memoria y los dispositivos PCI
294462306a36Sopenharmony_ci     pueden ambos pueden hacer esto); y
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci (*) la caché de datos de la CPU puede afectar al orden, y mientras sus
294762306a36Sopenharmony_ci     mecanismos de coherencia pueden aliviar esto, una vez que el store
294862306a36Sopenharmony_ci     haya accedido al caché- no hay garantía de que la gestión de la
294962306a36Sopenharmony_ci     coherencia se propague en orden a otras CPU.
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ciEntonces, digamos que lo que otra CPU podría observar en el fragmento de
295262306a36Sopenharmony_cicódigo anterior es:
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	(Donde "LOAD {*C,*D}" es una carga combinada)
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ciSin embargo, se garantiza que una CPU es autoconsistente: verá que sus
296062306a36Sopenharmony_ci _propios_ accesos parecen estar correctamente ordenados, sin necesidad de
296162306a36Sopenharmony_cibarrera de memoria. Por ejemplo con el siguiente código:
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	U = READ_ONCE(*A);
296462306a36Sopenharmony_ci	WRITE_ONCE(*A, V);
296562306a36Sopenharmony_ci	WRITE_ONCE(*A, W);
296662306a36Sopenharmony_ci	X = READ_ONCE(*A);
296762306a36Sopenharmony_ci	WRITE_ONCE(*A, Y);
296862306a36Sopenharmony_ci	Z = READ_ONCE(*A);
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ciy asumiendo que no hay intervención de una influencia externa, se puede
297162306a36Sopenharmony_cisuponer que el resultado final se parecerá a:
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci	U == el valor original de *A
297462306a36Sopenharmony_ci	X == W
297562306a36Sopenharmony_ci	Z == Y
297662306a36Sopenharmony_ci	*A == Y
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ciEl código anterior puede hacer que la CPU genere la secuencia completa de
297962306a36Sopenharmony_ciaccesos de memoria:
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci	U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_cien ese orden, pero, sin intervención, la secuencia puede contener casi
298462306a36Sopenharmony_cicualquier combinación de elementos combinados o descartados, siempre que la
298562306a36Sopenharmony_ciperspectiva del programa del mundo siga siendo consistente. Tenga en cuenta
298662306a36Sopenharmony_cique READ_ONCE() y WRITE_ONCE() -no- son opcionales en el ejemplo anterior,
298762306a36Sopenharmony_ciya que hay arquitecturas donde una CPU determinada podría reordenar cargas
298862306a36Sopenharmony_cisucesivas en la misma ubicación. En tales arquitecturas, READ_ONCE() y
298962306a36Sopenharmony_ciWRITE_ONCE() hacen lo que sea necesario para evitar esto, por ejemplo, en
299062306a36Sopenharmony_ciItanium los casts volátiles utilizados por READ_ONCE() y WRITE_ONCE() hacen
299162306a36Sopenharmony_cique GCC emita las instrucciones especiales ld.acq y st.rel
299262306a36Sopenharmony_ci(respectivamente) que impiden dicha reordenación.
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ciEl compilador también puede combinar, descartar o diferir elementos de la
299562306a36Sopenharmony_cisecuencia antes incluso de que la CPU los vea.
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ciPor ejemplo:
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	*A = V;
300062306a36Sopenharmony_ci	*A = W;
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_cipuede reducirse a:
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	*A = W;
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ciya que, sin una barrera de escritura o WRITE_ONCE(), puede que se asuma
300762306a36Sopenharmony_cique el efecto del almacenamiento de V a *A se pierde. Similarmente:
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci  	*A = Y;
301062306a36Sopenharmony_ci  	Z = *A;
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_cipuede, sin una barrera de memoria o un READ_ONCE() y WRITE_ONCE(), esto
301362306a36Sopenharmony_cisea reducido a:
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci  	*A = Y;
301662306a36Sopenharmony_ci  	Z = Y;
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ciy la operación LOAD nunca aparezca fuera de la CPU.
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ciY LUEGO ESTÁ EL ALFA
302262306a36Sopenharmony_ci--------------------
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ciLa CPU DEC Alpha es una de las CPU más relajadas que existen. No solo eso,
302562306a36Sopenharmony_cialgunas versiones de la CPU Alpha tienen un caché de datos dividido, lo que
302662306a36Sopenharmony_ciles permite tener dos líneas de caché relacionadas semánticamente,
302762306a36Sopenharmony_ciactualizadas en momentos separados. Aquí es donde la barrera de dependencia
302862306a36Sopenharmony_cide dirección realmente se vuelve necesaria, ya que se sincronizan ambos
302962306a36Sopenharmony_cicachés con el sistema de coherencia de memoria, lo que hace que parezca un
303062306a36Sopenharmony_cicambio en el puntero, frente a que los nuevos datos se produzcan en el
303162306a36Sopenharmony_ciorden correcto.
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ciAlpha define el modelo de memoria del kernel Linux, aunque a partir de
303462306a36Sopenharmony_civ4.15, la adición al kernel de Linux de smp_mb() a READ_ONCE() en Alpha
303562306a36Sopenharmony_ciredujo en gran medida su impacto en el modelo de memoria.
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ciGUESTS DE MÁQUINAS VIRTUALES
303962306a36Sopenharmony_ci-----------------------------
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_ciLos "guests" (invitados) que se ejecutan en máquinas virtuales pueden verse
304262306a36Sopenharmony_ciafectados por los efectos de SMP incluso si el "host" (huésped) en sí se
304362306a36Sopenharmony_cicompila sin compatibilidad con SMP. Este es un efecto de la interacción con
304462306a36Sopenharmony_ciun host SMP mientras ejecuta un kernel UP. El uso obligatorio de barreras
304562306a36Sopenharmony_cipara este caso de uso sería posible, pero a menudo no son óptimas.
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ciPara hacer frente a este caso de manera óptima, están disponibles macros de
304862306a36Sopenharmony_cibajo nivel virt_mb() etc. Estas tienen el mismo efecto que smp_mb(), etc.
304962306a36Sopenharmony_cicuando SMP está habilitado, pero generan código idéntico para sistemas SMP
305062306a36Sopenharmony_ciy no SMP. Por ejemplo, los invitados de máquinas virtuales debería usar
305162306a36Sopenharmony_civirt_mb() en lugar de smp_mb() al sincronizar contra un (posiblemente SMP)
305262306a36Sopenharmony_cianfitrión.
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ciEstos son equivalentes a sus contrapartes smp_mb() etc. en todos los demás
305562306a36Sopenharmony_ciaspectos, en particular, no controlan los efectos MMIO: para controlar los
305662306a36Sopenharmony_ciefectos MMIO, utilice barreras obligatorias.
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci================
306062306a36Sopenharmony_ciEJEMPLOS DE USOS
306162306a36Sopenharmony_ci================
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ciBUFFERS CIRCULARES
306462306a36Sopenharmony_ci------------------
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ciLas barreras de memoria se pueden utilizar para implementar almacenamiento
306762306a36Sopenharmony_cien búfer circular, sin necesidad de un cerrojo para serializar al productor
306862306a36Sopenharmony_cicon el consumidor. Vea:
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	Documentation/core-api/circular-buffers.rst
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_cipara más detalles.
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci===========
307662306a36Sopenharmony_ciREFERENCIAS
307762306a36Sopenharmony_ci===========
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ciAlpha AXP Architecture Reference Manual, Segunda Edición (por Sites & Witek,
308062306a36Sopenharmony_ciDigital Press)
308162306a36Sopenharmony_ci	Capítulo 5.2: Physical Address Space Characteristics
308262306a36Sopenharmony_ci	Capítulo 5.4: Caches and Write Buffers
308362306a36Sopenharmony_ci	Capítulo 5.5: Data Sharing
308462306a36Sopenharmony_ci	Capítulo 5.6: Read/Write Ordering
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ciAMD64 Architecture Programmer's Manual Volumen 2: System Programming
308762306a36Sopenharmony_ci	Capítulo 7.1: Memory-Access Ordering
308862306a36Sopenharmony_ci	Capítulo 7.4: Buffering and Combining Memory Writes
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ciARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
309162306a36Sopenharmony_ci	Capítulo B2: The AArch64 Application Level Memory Model
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ciIA-32 Intel Architecture Software Developer's Manual, Volumen 3:
309462306a36Sopenharmony_ciSystem Programming Guide
309562306a36Sopenharmony_ci	Capítulo 7.1: Locked Atomic Operations
309662306a36Sopenharmony_ci	Capítulo 7.2: Memory Ordering
309762306a36Sopenharmony_ci	Capítulo 7.4: Serializing Instructions
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ciThe SPARC Architecture Manual, Version 9
310062306a36Sopenharmony_ci	Capítulo 8: Memory Models
310162306a36Sopenharmony_ci	Appendix D: Formal Specification of the Memory Models
310262306a36Sopenharmony_ci	Appendix J: Programming with the Memory Models
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ciStorage in the PowerPC (por Stone and Fitzgerald)
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ciUltraSPARC Programmer Reference Manual
310762306a36Sopenharmony_ci	Capítulo 5: Memory Accesses and Cacheability
310862306a36Sopenharmony_ci	Capítulo 15: Sparc-V9 Memory Models
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ciUltraSPARC III Cu User's Manual
311162306a36Sopenharmony_ci	Capítulo 9: Memory Models
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ciUltraSPARC IIIi Processor User's Manual
311462306a36Sopenharmony_ci	Capítulo 8: Memory Models
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ciUltraSPARC Architecture 2005
311762306a36Sopenharmony_ci	Capítulo 9: Memory
311862306a36Sopenharmony_ci	Appendix D: Formal Specifications of the Memory Models
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ciUltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
312162306a36Sopenharmony_ci	Capítulo 8: Memory Models
312262306a36Sopenharmony_ci	Appendix F: Caches and Cache Coherency
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ciSolaris Internals, Core Kernel Architecture, p63-68:
312562306a36Sopenharmony_ci	Capítulo 3.3: Hardware Considerations for Locks and
312662306a36Sopenharmony_ci			Synchronization
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ciUnix Systems for Modern Architectures, Symmetric Multiprocessing and Caching
312962306a36Sopenharmony_cifor Kernel Programmers:
313062306a36Sopenharmony_ci	Capítulo 13: Other Memory Models
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ciIntel Itanium Architecture Software Developer's Manual: Volumen 1:
313362306a36Sopenharmony_ci	Sección 2.6: Speculation
313462306a36Sopenharmony_ci	Sección 4.4: Memory Access
3135