1259b007fSCarlos BilbaoNOTE:
2259b007fSCarlos BilbaoThis is a version of Documentation/memory-barriers.txt translated into
3259b007fSCarlos BilbaoSpanish by Carlos Bilbao <carlos.bilbao@amd.com>. If you find any
4259b007fSCarlos Bilbaodifference between this document and the original file or a problem with
5259b007fSCarlos Bilbaothe translation, please contact the maintainer of this file. Please also
6259b007fSCarlos Bilbaonote that the purpose of this file is to be easier to read for non English
7259b007fSCarlos Bilbao(read: Spanish) speakers and is not intended as a fork. So if you have any
8259b007fSCarlos Bilbaocomments or updates for this file please update the original English file
9259b007fSCarlos Bilbaofirst. The English version is definitive, and readers should look there if
10259b007fSCarlos Bilbaothey have any doubt.
11259b007fSCarlos Bilbao
12259b007fSCarlos Bilbao			 ======================================
13259b007fSCarlos Bilbao			 BARRERAS DE MEMORIA EN EL KERNEL LINUX
14259b007fSCarlos Bilbao			 ======================================
15259b007fSCarlos Bilbao
16259b007fSCarlos BilbaoDocumento original: David Howells <dhowells@redhat.com>
17259b007fSCarlos Bilbao    Paul E. McKenney <paulmck@linux.ibm.com>
18259b007fSCarlos Bilbao    Will Deacon <will.deacon@arm.com>
19259b007fSCarlos Bilbao    Peter Zijlstra <peterz@infradead.org>
20259b007fSCarlos Bilbao
21259b007fSCarlos BilbaoTraducido por: Carlos Bilbao <carlos.bilbao@amd.com>
22259b007fSCarlos BilbaoNota: Si tiene alguna duda sobre la exactitud del contenido de esta
23259b007fSCarlos Bilbaotraducción, la única referencia válida es la documentación oficial en
24259b007fSCarlos Bilbaoinglés.
25259b007fSCarlos Bilbao
26259b007fSCarlos Bilbao===========
27259b007fSCarlos BilbaoADVERTENCIA
28259b007fSCarlos Bilbao===========
29259b007fSCarlos Bilbao
30259b007fSCarlos BilbaoEste documento no es una especificación; es intencionalmente (por motivos
31259b007fSCarlos Bilbaode brevedad) y sin querer (por ser humanos) incompleta. Este documento
32259b007fSCarlos Bilbaopretende ser una guía para usar las diversas barreras de memoria
33259b007fSCarlos Bilbaoproporcionadas por Linux, pero ante cualquier duda (y hay muchas) por favor
34259b007fSCarlos Bilbaopregunte. Algunas dudas pueden ser resueltas refiriéndose al modelo de
35259b007fSCarlos Bilbaoconsistencia de memoria formal y documentación en tools/memory-model/. Sin
36259b007fSCarlos Bilbaoembargo, incluso este modelo debe ser visto como la opinión colectiva de
37259b007fSCarlos Bilbaosus maintainers en lugar de que como un oráculo infalible.
38259b007fSCarlos Bilbao
39259b007fSCarlos BilbaoDe nuevo, este documento no es una especificación de lo que Linux espera
40259b007fSCarlos Bilbaodel hardware.
41259b007fSCarlos Bilbao
42259b007fSCarlos BilbaoEl propósito de este documento es doble:
43259b007fSCarlos Bilbao
44259b007fSCarlos Bilbao (1) especificar la funcionalidad mínima en la que se puede confiar para
45259b007fSCarlos Bilbao     cualquier barrera en concreto, y
46259b007fSCarlos Bilbao
47259b007fSCarlos Bilbao (2) proporcionar una guía sobre cómo utilizar las barreras disponibles.
48259b007fSCarlos Bilbao
49259b007fSCarlos BilbaoTenga en cuenta que una arquitectura puede proporcionar más que el
50259b007fSCarlos Bilbaorequisito mínimo para cualquier barrera en particular, pero si la
51259b007fSCarlos Bilbaoarquitectura proporciona menos de eso, dicha arquitectura es incorrecta.
52259b007fSCarlos Bilbao
53259b007fSCarlos BilbaoTenga en cuenta también que es posible que una barrera no valga (sea no-op)
54259b007fSCarlos Bilbaopara alguna arquitectura porque por la forma en que funcione dicha
55259b007fSCarlos Bilbaoarquitectura, la barrera explícita resulte innecesaria en ese caso.
56259b007fSCarlos Bilbao
57259b007fSCarlos Bilbao==========
58259b007fSCarlos BilbaoCONTENIDOS
59259b007fSCarlos Bilbao==========
60259b007fSCarlos Bilbao
61259b007fSCarlos Bilbao (*) Modelo abstracto de acceso a memoria.
62259b007fSCarlos Bilbao
63259b007fSCarlos Bilbao     - Operaciones del dispositivo.
64259b007fSCarlos Bilbao     - Garantías.
65259b007fSCarlos Bilbao
66259b007fSCarlos Bilbao (*) ¿Qué son las barreras de memoria?
67259b007fSCarlos Bilbao
68259b007fSCarlos Bilbao     - Variedades de barrera de memoria.
69259b007fSCarlos Bilbao     - ¿Qué no se puede asumir sobre las barreras de memoria?
70259b007fSCarlos Bilbao     - Barreras de dirección-dependencia (históricas).
71259b007fSCarlos Bilbao     - Dependencias de control.
72259b007fSCarlos Bilbao     - Emparejamiento de barreras smp.
73259b007fSCarlos Bilbao     - Ejemplos de secuencias de barrera de memoria.
74259b007fSCarlos Bilbao     - Barreras de memoria de lectura frente a especulación de carga.
75259b007fSCarlos Bilbao     - Atomicidad multicopia.
76259b007fSCarlos Bilbao
77259b007fSCarlos Bilbao (*) Barreras explícitas del kernel.
78259b007fSCarlos Bilbao
79259b007fSCarlos Bilbao     - Barrera del compilador.
80259b007fSCarlos Bilbao     - Barreras de memoria de la CPU.
81259b007fSCarlos Bilbao
82259b007fSCarlos Bilbao (*) Barreras de memoria implícitas del kernel.
83259b007fSCarlos Bilbao
84259b007fSCarlos Bilbao     - Funciones de adquisición de cerrojo.
85259b007fSCarlos Bilbao     - Funciones de desactivación de interrupciones.
86259b007fSCarlos Bilbao     - Funciones de dormir y despertar.
87259b007fSCarlos Bilbao     - Funciones varias.
88259b007fSCarlos Bilbao
89259b007fSCarlos Bilbao (*) Efectos de barrera adquiriendo intra-CPU.
90259b007fSCarlos Bilbao
91259b007fSCarlos Bilbao     - Adquisición vs accesos a memoria.
92259b007fSCarlos Bilbao
93259b007fSCarlos Bilbao (*) ¿Dónde se necesitan barreras de memoria?
94259b007fSCarlos Bilbao
95259b007fSCarlos Bilbao     - Interacción entre procesadores.
96259b007fSCarlos Bilbao     - Operaciones atómicas.
97259b007fSCarlos Bilbao     - Acceso a dispositivos.
98259b007fSCarlos Bilbao     - Interrupciones.
99259b007fSCarlos Bilbao
100259b007fSCarlos Bilbao (*) Efectos de barrera de E/S del kernel.
101259b007fSCarlos Bilbao
102259b007fSCarlos Bilbao (*) Modelo de orden mínimo de ejecución asumido.
103259b007fSCarlos Bilbao
104259b007fSCarlos Bilbao (*) Efectos de la memoria caché de la CPU.
105259b007fSCarlos Bilbao
106259b007fSCarlos Bilbao     - Coherencia de caché.
107259b007fSCarlos Bilbao     - Coherencia de caché frente a DMA.
108259b007fSCarlos Bilbao     - Coherencia de caché frente a MMIO.
109259b007fSCarlos Bilbao
110259b007fSCarlos Bilbao (*) Cosas que hacen las CPU.
111259b007fSCarlos Bilbao
112259b007fSCarlos Bilbao     - Y luego está el Alfa.
113259b007fSCarlos Bilbao     - Guests de máquinas virtuales.
114259b007fSCarlos Bilbao
115259b007fSCarlos Bilbao (*) Ejemplos de usos.
116259b007fSCarlos Bilbao
117259b007fSCarlos Bilbao     - Buffers circulares.
118259b007fSCarlos Bilbao
119259b007fSCarlos Bilbao (*) Referencias.
120259b007fSCarlos Bilbao
121259b007fSCarlos Bilbao
122259b007fSCarlos Bilbao====================================
123259b007fSCarlos BilbaoMODELO ABSTRACTO DE ACCESO A MEMORIA
124259b007fSCarlos Bilbao====================================
125259b007fSCarlos Bilbao
126259b007fSCarlos BilbaoConsidere el siguiente modelo abstracto del sistema:
127259b007fSCarlos Bilbao
128259b007fSCarlos Bilbao		            :                :
129259b007fSCarlos Bilbao		            :                :
130259b007fSCarlos Bilbao		            :                :
131259b007fSCarlos Bilbao		+-------+   :   +--------+   :   +-------+
132259b007fSCarlos Bilbao		|       |   :   |        |   :   |       |
133259b007fSCarlos Bilbao		|       |   :   |        |   :   |       |
134259b007fSCarlos Bilbao		| CPU 1 |<----->| Memoria|<----->| CPU 2 |
135259b007fSCarlos Bilbao		|       |   :   |        |   :   |       |
136259b007fSCarlos Bilbao		|       |   :   |        |   :   |       |
137259b007fSCarlos Bilbao		+-------+   :   +--------+   :   +-------+
138259b007fSCarlos Bilbao		    ^       :       ^        :       ^
139259b007fSCarlos Bilbao		    |       :       |        :       |
140259b007fSCarlos Bilbao		    |       :       |        :       |
141259b007fSCarlos Bilbao		    |       :       v        :       |
142259b007fSCarlos Bilbao		    |       :   +--------+   :       |
143259b007fSCarlos Bilbao		    |       :   |        |   :       |
144259b007fSCarlos Bilbao		    |       :   | Disposi|   :       |
145259b007fSCarlos Bilbao		    +---------->| tivo   |<----------+
146259b007fSCarlos Bilbao		            :   |        |   :
147259b007fSCarlos Bilbao		            :   |        |   :
148259b007fSCarlos Bilbao		            :   +--------+   :
149259b007fSCarlos Bilbao		            :                :
150259b007fSCarlos Bilbao
151259b007fSCarlos BilbaoCada CPU ejecuta un programa que genera operaciones de acceso a la memoria.
152259b007fSCarlos BilbaoEn la CPU abstracta, el orden de las operaciones de memoria es muy
153259b007fSCarlos Bilbaorelajado, y una CPU en realidad puede realizar las operaciones de memoria
154259b007fSCarlos Bilbaoen el orden que desee, siempre que la causalidad del programa parezca
155259b007fSCarlos Bilbaomantenerse. De manera similar, el compilador también puede organizar las
156259b007fSCarlos Bilbaoinstrucciones que emite en el orden que quiera, siempre que no afecte al
157259b007fSCarlos Bilbaofuncionamiento aparente del programa.
158259b007fSCarlos Bilbao
159259b007fSCarlos BilbaoEntonces, en el diagrama anterior, los efectos de las operaciones de
160259b007fSCarlos Bilbaomemoria realizadas por un CPU son percibidos por el resto del sistema a
161259b007fSCarlos Bilbaomedida que las operaciones cruzan la interfaz entre la CPU y el resto del
162259b007fSCarlos Bilbaosistema (las líneas discontinuas a puntos).
163259b007fSCarlos Bilbao
164259b007fSCarlos BilbaoPor ejemplo, considere la siguiente secuencia de eventos:
165259b007fSCarlos Bilbao
166259b007fSCarlos Bilbao	CPU 1		CPU 2
167259b007fSCarlos Bilbao	===============	===============
168259b007fSCarlos Bilbao	{ A == 1; B == 2 }
169259b007fSCarlos Bilbao	A = 3;		x = B;
170259b007fSCarlos Bilbao	B = 4;		y = A;
171259b007fSCarlos Bilbao
172259b007fSCarlos BilbaoEl conjunto de accesos visto por el sistema de memoria en el medio se puede
173259b007fSCarlos Bilbaoorganizar en 24 combinaciones diferentes (donde LOAD es cargar y STORE es
174259b007fSCarlos Bilbaoguardar):
175259b007fSCarlos Bilbao
176259b007fSCarlos BilbaoSTORE A=3,	STORE B=4,	y=LOAD A->3,	x=LOAD B->4
177259b007fSCarlos BilbaoSTORE A=3,	STORE B=4,	x=LOAD B->4,	y=LOAD A->3
178259b007fSCarlos BilbaoSTORE A=3,	y=LOAD A->3,	STORE B=4,	x=LOAD B->4
179259b007fSCarlos BilbaoSTORE A=3,	y=LOAD A->3,	x=LOAD B->2,	STORE B=4
180259b007fSCarlos BilbaoSTORE A=3,	x=LOAD B->2,	STORE B=4,	y=LOAD A->3
181259b007fSCarlos BilbaoSTORE A=3,	x=LOAD B->2,	y=LOAD A->3,	STORE B=4
182259b007fSCarlos BilbaoSTORE B=4,	STORE A=3,	y=LOAD A->3,	x=LOAD B->4
183259b007fSCarlos BilbaoSTORE B=4, ...
184259b007fSCarlos Bilbao...
185259b007fSCarlos Bilbao
186259b007fSCarlos Bilbaoy por lo tanto puede resultar en cuatro combinaciones diferentes de
187259b007fSCarlos Bilbaovalores:
188259b007fSCarlos Bilbao
189259b007fSCarlos Bilbaox == 2, y == 1
190259b007fSCarlos Bilbaox == 2, y == 3
191259b007fSCarlos Bilbaox == 4, y == 1
192259b007fSCarlos Bilbaox == 4, y == 3
193259b007fSCarlos Bilbao
194259b007fSCarlos BilbaoAdemás, los stores asignados por una CPU al sistema de memoria pueden no
195259b007fSCarlos Bilbaoser percibidos por los loads realizados por otra CPU en el mismo orden en
196259b007fSCarlos Bilbaoque fueron realizados.
197259b007fSCarlos Bilbao
198259b007fSCarlos BilbaoComo otro ejemplo, considere esta secuencia de eventos:
199259b007fSCarlos Bilbao
200259b007fSCarlos Bilbao	CPU 1		CPU 2
201259b007fSCarlos Bilbao	===============	===============
202259b007fSCarlos Bilbao	{ A == 1, B == 2, C == 3, P == &A, Q == &C }
203259b007fSCarlos Bilbao	B = 4;		Q = P;
204259b007fSCarlos Bilbao	P = &B;		D = *Q;
205259b007fSCarlos Bilbao
206259b007fSCarlos BilbaoAquí hay una dependencia obvia de la dirección, ya que el valor cargado en
207259b007fSCarlos BilbaoD depende en la dirección recuperada de P por la CPU 2. Al final de la
208259b007fSCarlos Bilbaosecuencia, cualquiera de los siguientes resultados son posibles:
209259b007fSCarlos Bilbao
210259b007fSCarlos Bilbao  (Q == &A) y (D == 1)
211259b007fSCarlos Bilbao  (Q == &B) y (D == 2)
212259b007fSCarlos Bilbao  (Q == &B) y (D == 4)
213259b007fSCarlos Bilbao
214259b007fSCarlos BilbaoTenga en cuenta que la CPU 2 nunca intentará cargar C en D porque la CPU
215259b007fSCarlos Bilbaocargará P en Q antes de emitir la carga de *Q.
216259b007fSCarlos Bilbao
217259b007fSCarlos BilbaoOPERACIONES DEL DISPOSITIVO
218259b007fSCarlos Bilbao---------------------------
219259b007fSCarlos Bilbao
220259b007fSCarlos BilbaoAlgunos dispositivos presentan sus interfaces de control como colecciones
221259b007fSCarlos Bilbaode ubicaciones de memoria, pero el orden en que se accede a los registros
222259b007fSCarlos Bilbaode control es muy importante. Por ejemplo, imagine una tarjeta ethernet con
223259b007fSCarlos Bilbaoun conjunto de registros a los que se accede a través de un registro de
224259b007fSCarlos Bilbaopuerto de dirección (A) y un registro de datos del puerto (D). Para leer el
225259b007fSCarlos Bilbaoregistro interno 5, el siguiente código podría entonces ser usado:
226259b007fSCarlos Bilbao
227259b007fSCarlos Bilbao  *A = 5;
228259b007fSCarlos Bilbao  x = *D;
229259b007fSCarlos Bilbao
230259b007fSCarlos Bilbaopero esto podría aparecer como cualquiera de las siguientes dos secuencias:
231259b007fSCarlos Bilbao
232259b007fSCarlos Bilbao  STORE *A = 5, x = LOAD *D
233259b007fSCarlos Bilbao  x = LOAD *D, STORE *A = 5
234259b007fSCarlos Bilbao
235259b007fSCarlos Bilbaoel segundo de las cuales casi con certeza resultará en mal funcionamiento,
236259b007fSCarlos Bilbaoya que se estableció la dirección _después_ de intentar leer el registro.
237259b007fSCarlos Bilbao
238259b007fSCarlos Bilbao
239259b007fSCarlos BilbaoGARANTÍAS
240259b007fSCarlos Bilbao---------
241259b007fSCarlos Bilbao
242259b007fSCarlos BilbaoHay algunas garantías mínimas que se pueden esperar de una CPU:
243259b007fSCarlos Bilbao
244259b007fSCarlos Bilbao (*) En cualquier CPU dada, los accesos a la memoria dependiente se
245259b007fSCarlos Bilbao     emitirán en orden, con respeto a sí mismo. Esto significa que para:
246259b007fSCarlos Bilbao
247259b007fSCarlos Bilbao	Q = READ_ONCE(P); D = READ_ONCE(*Q);
248259b007fSCarlos Bilbao
249259b007fSCarlos Bilbao     donde READ_ONCE() es LEER_UNA_VEZ(), la CPU emitirá las siguientes
250259b007fSCarlos Bilbao     operaciones de memoria:
251259b007fSCarlos Bilbao
252259b007fSCarlos Bilbao	Q = LOAD P, D = LOAD *Q
253259b007fSCarlos Bilbao
254259b007fSCarlos Bilbao     y siempre en ese orden. Sin embargo, en DEC Alpha, READ_ONCE() también
255259b007fSCarlos Bilbao     emite una instrucción de barrera de memoria, de modo que una CPU DEC
256259b007fSCarlos Bilbao     Alpha, sin embargo emite las siguientes operaciones de memoria:
257259b007fSCarlos Bilbao
258259b007fSCarlos Bilbao	Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER
259259b007fSCarlos Bilbao
260259b007fSCarlos Bilbao     Ya sea en DEC Alpha o no, READ_ONCE() también evita que el compilador
261259b007fSCarlos Bilbao     haga cosas inapropiadas.
262259b007fSCarlos Bilbao
263259b007fSCarlos Bilbao (*) Los loads y stores superpuestos dentro de una CPU en particular
264259b007fSCarlos Bilbao     parecerán ser ordenados dentro de esa CPU. Esto significa que para:
265259b007fSCarlos Bilbao
266259b007fSCarlos Bilbao	a = READ_ONCE(*X); WRITE_ONCE(*X, b);
267259b007fSCarlos Bilbao
268259b007fSCarlos Bilbao     donde WRITE_ONCE() es ESCRIBIR_UNA_VEZ(), la CPU solo emitirá la
269259b007fSCarlos Bilbao     siguiente secuencia de operaciones de memoria:
270259b007fSCarlos Bilbao
271259b007fSCarlos Bilbao	a = LOAD *X, STORE *X = b
272259b007fSCarlos Bilbao
273259b007fSCarlos Bilbao     Y para:
274259b007fSCarlos Bilbao
275259b007fSCarlos Bilbao	WRITE_ONCE(*X, c); d = READ_ONCE(*X);
276259b007fSCarlos Bilbao
277259b007fSCarlos Bilbao     la CPU solo emitirá:
278259b007fSCarlos Bilbao
279259b007fSCarlos Bilbao	STORE *X = c, d = LOAD *X
280259b007fSCarlos Bilbao
281259b007fSCarlos Bilbao  (Los loads y stores se superponen si están destinados a piezas
282259b007fSCarlos Bilbao  superpuestas de memoria).
283259b007fSCarlos Bilbao
284259b007fSCarlos BilbaoY hay una serie de cosas que _deben_ o _no_ deben asumirse:
285259b007fSCarlos Bilbao
286259b007fSCarlos Bilbao (*) _No_debe_ asumirse que el compilador hará lo que usted quiera
287259b007fSCarlos Bilbao     con referencias de memoria que no están protegidas por READ_ONCE() y
288259b007fSCarlos Bilbao     WRITE ONCE(). Sin ellos, el compilador tiene derecho a hacer todo tipo
289259b007fSCarlos Bilbao     de transformaciones "creativas", que se tratan en la sección BARRERA
290259b007fSCarlos Bilbao     DEL COMPILADOR.
291259b007fSCarlos Bilbao
292259b007fSCarlos Bilbao   (*) _No_debe_ suponerse que se emitirán loads y stores independientes
293259b007fSCarlos Bilbao       en el orden dado. Esto significa que para:
294259b007fSCarlos Bilbao
295259b007fSCarlos Bilbao	X = *A; Y = *B; *D = Z;
296259b007fSCarlos Bilbao
297259b007fSCarlos Bilbao     podemos obtener cualquiera de las siguientes secuencias:
298259b007fSCarlos Bilbao
299259b007fSCarlos Bilbao    X = LOAD *A,  Y = LOAD *B,  STORE *D = Z
300259b007fSCarlos Bilbao   	X = LOAD *A,  STORE *D = Z, Y = LOAD *B
301259b007fSCarlos Bilbao   	Y = LOAD *B,  X = LOAD *A,  STORE *D = Z
302259b007fSCarlos Bilbao   	Y = LOAD *B,  STORE *D = Z, X = LOAD *A
303259b007fSCarlos Bilbao   	STORE *D = Z, X = LOAD *A,  Y = LOAD *B
304259b007fSCarlos Bilbao   	STORE *D = Z, Y = LOAD *B,  X = LOAD *A
305259b007fSCarlos Bilbao
306259b007fSCarlos Bilbao (*) Se _debe_ suponer que los accesos de memoria superpuestos pueden
307259b007fSCarlos Bilbao     fusionarse o ser descartados. Esto significa que para:
308259b007fSCarlos Bilbao
309259b007fSCarlos Bilbao	X = *A; Y = *(A + 4);
310259b007fSCarlos Bilbao
311259b007fSCarlos Bilbao  podemos obtener cualquiera de las siguientes secuencias:
312259b007fSCarlos Bilbao
313259b007fSCarlos BilbaoX = LOAD *A; Y = LOAD *(A + 4);
314259b007fSCarlos BilbaoY = LOAD *(A + 4); X = LOAD *A;
315259b007fSCarlos Bilbao{X, Y} = LOAD {*A, *(A + 4) };
316259b007fSCarlos Bilbao
317259b007fSCarlos Bilbao  Y para:
318259b007fSCarlos Bilbao
319259b007fSCarlos Bilbao*A = X; *(A + 4) = Y;
320259b007fSCarlos Bilbao
321259b007fSCarlos Bilbao  podemos obtener cualquiera de:
322259b007fSCarlos Bilbao
323259b007fSCarlos BilbaoSTORE *A = X; STORE *(A + 4) = Y;
324259b007fSCarlos BilbaoSTORE *(A + 4) = Y; STORE *A = X;
325259b007fSCarlos BilbaoSTORE {*A, *(A + 4) } = {X, Y};
326259b007fSCarlos Bilbao
327259b007fSCarlos BilbaoY hay anti-garantías:
328259b007fSCarlos Bilbao
329259b007fSCarlos Bilbao(*) Estas garantías no se aplican a los campos de bits, porque los
330259b007fSCarlos Bilbao    compiladores a menudo generan código para modificarlos usando
331259b007fSCarlos Bilbao    secuencias de lectura-modificación-escritura no atómica. No intente
332259b007fSCarlos Bilbao    utilizar campos de bits para sincronizar algoritmos paralelos.
333259b007fSCarlos Bilbao
334259b007fSCarlos Bilbao(*) Incluso en los casos en que los campos de bits están protegidos por
335259b007fSCarlos Bilbao    cerrojos (o "cerrojos", o "locks"), todos los componentes en un campo
336259b007fSCarlos Bilbao    de bits dado deben estar protegidos por un candado. Si dos campos en un
337259b007fSCarlos Bilbao    campo de bits dado están protegidos por diferentes locks, las
338259b007fSCarlos Bilbao    secuencias de lectura-modificación-escritura no atómicas del lock
339259b007fSCarlos Bilbao    pueden causar una actualización a una campo para corromper el valor de
340259b007fSCarlos Bilbao    un campo adyacente.
341259b007fSCarlos Bilbao
342259b007fSCarlos Bilbao(*) Estas garantías se aplican solo a escalares correctamente alineados y
343259b007fSCarlos Bilbao    dimensionados. De "tamaño adecuado" significa actualmente variables que
344259b007fSCarlos Bilbao    son del mismo tamaño que "char", "short", "int" y "long".
345259b007fSCarlos Bilbao    "Adecuadamente alineado" significa la alineación natural, por lo tanto,
346259b007fSCarlos Bilbao    no hay restricciones para "char", alineación de dos bytes para "short",
347259b007fSCarlos Bilbao    alineación de cuatro bytes para "int", y alineación de cuatro u ocho
348259b007fSCarlos Bilbao    bytes para "long", en sistemas de 32 y 64 bits, respectivamente. Tenga
349259b007fSCarlos Bilbao    en cuenta que estos garantías se introdujeron en el estándar C11, así
350259b007fSCarlos Bilbao    que tenga cuidado cuando utilice compiladores anteriores a C11 (por
351259b007fSCarlos Bilbao    ejemplo, gcc 4.6). La parte de la norma que contiene esta garantía es
352259b007fSCarlos Bilbao    la Sección 3.14, que define "ubicación de memoria" de la siguiente
353259b007fSCarlos Bilbao    manera:
354259b007fSCarlos Bilbao
355259b007fSCarlos Bilbao    ubicación de memoria
356259b007fSCarlos Bilbao  ya sea un objeto de tipo escalar, o una secuencia máxima
357259b007fSCarlos Bilbao  de campos de bits adyacentes, todos con ancho distinto de cero
358259b007fSCarlos Bilbao
359259b007fSCarlos Bilbao  NOTE 1: Dos hilos de ejecución pueden actualizar y acceder
360259b007fSCarlos Bilbao  ubicaciones de memoria separadas sin interferir entre
361259b007fSCarlos Bilbao  ellos.
362259b007fSCarlos Bilbao
363259b007fSCarlos Bilbao  NOTE 2: Un campo de bits y un miembro adyacente que no es un campo de
364259b007fSCarlos Bilbao  bits están en ubicaciones de memoria separadas. Lo mismo sucede con
365259b007fSCarlos Bilbao  dos campos de bits, si uno se declara dentro de un declaración de
366259b007fSCarlos Bilbao  estructura anidada y el otro no, o si las dos están separados por una
367259b007fSCarlos Bilbao  declaración de campo de bits de longitud cero, o si están separados por
368259b007fSCarlos Bilbao  un miembro no declarado como campo de bits. No es seguro actualizar
369259b007fSCarlos Bilbao  simultáneamente dos campos de bits en la misma estructura si entre
370259b007fSCarlos Bilbao  todos los miembros declarados también hay campos de bits, sin importar
371259b007fSCarlos Bilbao  cuál resulta ser el tamaño de estos campos de bits intermedios.
372259b007fSCarlos Bilbao
373259b007fSCarlos Bilbao
374259b007fSCarlos Bilbao==================================
375259b007fSCarlos Bilbao¿QUÉ SON LAS BARRERAS DE MEMORIA?
376259b007fSCarlos Bilbao==================================
377259b007fSCarlos Bilbao
378259b007fSCarlos BilbaoComo se puede leer arriba, las operaciones independientes de memoria se
379259b007fSCarlos Bilbaorealizan de manera efectiva en orden aleatorio, pero esto puede ser un
380259b007fSCarlos Bilbaoproblema para la interacción CPU-CPU y para la E/S ("I/O"). Lo que se
381259b007fSCarlos Bilbaorequiere es alguna forma de intervenir para instruir al compilador y al
382259b007fSCarlos BilbaoCPU para restringir el orden.
383259b007fSCarlos Bilbao
384259b007fSCarlos BilbaoLas barreras de memoria son este tipo de intervenciones. Imponen una
385259b007fSCarlos Bilbaopercepción de orden parcial, sobre las operaciones de memoria a ambos lados
386259b007fSCarlos Bilbaode la barrera.
387259b007fSCarlos Bilbao
388259b007fSCarlos BilbaoTal cumplimiento es importante porque las CPUs y otros dispositivos en un
389259b007fSCarlos Bilbaosistema pueden usar una variedad de trucos para mejorar el rendimiento,
390259b007fSCarlos Bilbaoincluido el reordenamiento, diferimiento y combinación de operaciones de
391259b007fSCarlos Bilbaomemoria; cargas especulativas; predicción de "branches" especulativos y
392259b007fSCarlos Bilbaovarios tipos de almacenamiento en caché. Las barreras de memoria se
393259b007fSCarlos Bilbaoutilizan para anular o suprimir estos trucos, permitiendo que el código
394259b007fSCarlos Bilbaocontrole sensatamente la interacción de múltiples CPU y/o dispositivos.
395259b007fSCarlos Bilbao
396259b007fSCarlos Bilbao
397259b007fSCarlos BilbaoVARIEDADES DE BARRERA DE MEMORIA
398259b007fSCarlos Bilbao---------------------------------
399259b007fSCarlos Bilbao
400259b007fSCarlos BilbaoLas barreras de memoria vienen en cuatro variedades básicas:
401259b007fSCarlos Bilbao
402259b007fSCarlos Bilbao (1) Barreras de memoria al escribir o almacenar (Write or store memory
403259b007fSCarlos Bilbao     barriers).
404259b007fSCarlos Bilbao
405259b007fSCarlos Bilbao     Una barrera de memoria de escritura garantiza que todas las
406259b007fSCarlos Bilbao     operaciones de STORE especificadas antes de que la barrera aparezca
407259b007fSCarlos Bilbao     suceden antes de todas las operaciones STORE especificadas después
408259b007fSCarlos Bilbao     de la barrera, con respecto a los otros componentes del sistema.
409259b007fSCarlos Bilbao
410259b007fSCarlos Bilbao     Una barrera de escritura es un orden parcial solo en los stores; No
411259b007fSCarlos Bilbao     es requerido que tenga ningún efecto sobre los loads.
412259b007fSCarlos Bilbao
413259b007fSCarlos Bilbao     Se puede considerar que una CPU envía una secuencia de operaciones de
414259b007fSCarlos Bilbao     store al sistema de memoria a medida que pasa el tiempo. Todos los
415259b007fSCarlos Bilbao     stores _antes_ de una barrera de escritura ocurrirán _antes_ de todos
416259b007fSCarlos Bilbao     los stores después de la barrera de escritura.
417259b007fSCarlos Bilbao
418259b007fSCarlos Bilbao     [!] Tenga en cuenta que las barreras de escritura normalmente deben
419259b007fSCarlos Bilbao     combinarse con read o barreras de address-dependency barriers
420259b007fSCarlos Bilbao     (dependencia de dirección); consulte la subsección
421259b007fSCarlos Bilbao     "Emparejamiento de barreras smp".
422259b007fSCarlos Bilbao
423259b007fSCarlos Bilbao
424259b007fSCarlos Bilbao (2) Barrera de dependencia de dirección (histórico).
425259b007fSCarlos Bilbao
426259b007fSCarlos Bilbao     Una barrera de dependencia de dirección es una forma más débil de
427259b007fSCarlos Bilbao     barrera de lectura. En el caso de que se realicen dos loads de manera
428259b007fSCarlos Bilbao     que la segunda dependa del resultado de la primera (por ejemplo: el
429259b007fSCarlos Bilbao     primer load recupera la dirección a la que se dirigirá el segundo
430259b007fSCarlos Bilbao     load), una barrera de dependencia de dirección sería necesaria para
431259b007fSCarlos Bilbao     asegurarse de que el objetivo de la segunda carga esté actualizado
432259b007fSCarlos Bilbao     después de acceder a la dirección obtenida por la primera carga.
433259b007fSCarlos Bilbao
434259b007fSCarlos Bilbao     Una barrera de dependencia de direcciones es una ordenación parcial en
435259b007fSCarlos Bilbao     laods de direcciones interdependientes; no se requiere que tenga
436259b007fSCarlos Bilbao     ningún efecto en los stores, ya sean cargas de memoria o cargas
437259b007fSCarlos Bilbao     de memoria superpuestas.
438259b007fSCarlos Bilbao
439259b007fSCarlos Bilbao     Como se mencionó en (1), las otras CPU en el sistema pueden verse como
440259b007fSCarlos Bilbao     secuencias de stores en el sistema de memoria que la considerada CPU
441259b007fSCarlos Bilbao     puede percibir. Una barrera de dependencia de dirección emitida por
442259b007fSCarlos Bilbao     la CPU en cuestión garantiza que para cualquier carga que la preceda,
443259b007fSCarlos Bilbao     si esa carga toca alguna secuencia de stores de otra CPU, entonces
444259b007fSCarlos Bilbao     en el momento en que la barrera se complete, los efectos de todos los
445259b007fSCarlos Bilbao     stores antes del cambio del load serán perceptibles por cualquier
446259b007fSCarlos Bilbao     carga emitida después la barrera de la dependencia de la dirección.
447259b007fSCarlos Bilbao
448259b007fSCarlos Bilbao     Consulte la subsección "Ejemplos de secuencias de barrera de memoria"
449259b007fSCarlos Bilbao     para ver los diagramas mostrando las restricciones de orden.
450259b007fSCarlos Bilbao
451259b007fSCarlos Bilbao     [!] Tenga en cuenta que la primera carga realmente tiene que tener una
452259b007fSCarlos Bilbao     dependencia de _dirección_ y no es una dependencia de control. Si la
453259b007fSCarlos Bilbao     dirección para la segunda carga depende de la primera carga, pero la
454259b007fSCarlos Bilbao     dependencia es a través de un condicional en lugar de -en realidad-
455259b007fSCarlos Bilbao     cargando la dirección en sí, entonces es una dependencia de _control_
456259b007fSCarlos Bilbao     y se requiere una barrera de lectura completa o superior. Consulte la
457259b007fSCarlos Bilbao     subsección "Dependencias de control" para más información.
458259b007fSCarlos Bilbao
459259b007fSCarlos Bilbao     [!] Tenga en cuenta que las barreras de dependencia de dirección
460259b007fSCarlos Bilbao     normalmente deben combinarse con barreras de escritura; consulte la
461259b007fSCarlos Bilbao     subsección "Emparejamiento de barreras smp".
462259b007fSCarlos Bilbao
463259b007fSCarlos Bilbao     [!] Desde el kernel v5.9, se eliminó la API del kernel para barreras
464259b007fSCarlos Bilbao     de memoria de direcciones explícitas. Hoy en día, las APIs para marcar
465259b007fSCarlos Bilbao     cargas de variables compartidas, como READ_ONCE() y rcu_dereference(),
466259b007fSCarlos Bilbao     proporcionan barreras de dependencia de dirección implícitas.
467259b007fSCarlos Bilbao
468259b007fSCarlos Bilbao (3) Barreras de memoria al leer o cargar (Read or load memory
469259b007fSCarlos Bilbao    barriers).
470259b007fSCarlos Bilbao
471259b007fSCarlos Bilbao     Una barrera de lectura es una barrera de dependencia de direcciones,
472259b007fSCarlos Bilbao     más una garantía de que todas las operaciones de LOAD especificadas
473259b007fSCarlos Bilbao     antes de la barrera parecerán ocurrir antes de todas las operaciones
474259b007fSCarlos Bilbao     de LOAD especificadas después de la barrera con respecto a los demás
475259b007fSCarlos Bilbao     componentes del sistema.
476259b007fSCarlos Bilbao
477259b007fSCarlos Bilbao     Una barrera de lectura es un orden parcial solo en cargas; no es
478259b007fSCarlos Bilbao     necesario que tenga ningún efecto en los stores.
479259b007fSCarlos Bilbao
480259b007fSCarlos Bilbao     Las barreras de memoria de lectura implican barreras de dependencia de
481259b007fSCarlos Bilbao     direcciones, y por tanto puede sustituirlas por estas.
482259b007fSCarlos Bilbao
483259b007fSCarlos Bilbao     [!] Tenga en mente que las barreras de lectura normalmente deben
484259b007fSCarlos Bilbao     combinarse con barreras de escritura; consulte la subsección
485259b007fSCarlos Bilbao     "Emparejamiento de barreras smp".
486259b007fSCarlos Bilbao
487259b007fSCarlos Bilbao (4) Barreras de memoria generales
488259b007fSCarlos Bilbao
489259b007fSCarlos Bilbao     Una barrera de memoria general proporciona la garantía de que todas
490259b007fSCarlos Bilbao     las operaciones LOAD y STORE especificadas antes de que la barrera
491259b007fSCarlos Bilbao     aparezca suceden antes de que todas las operaciones LOAD y STORE
492259b007fSCarlos Bilbao     especificadas después de la barrera con respecto a los demás
493259b007fSCarlos Bilbao     componentes del sistema.
494259b007fSCarlos Bilbao
495259b007fSCarlos Bilbao     Una barrera de memoria general es un orden parcial tanto en
496259b007fSCarlos Bilbao     operaciones de carga como de almacenamiento.
497259b007fSCarlos Bilbao
498259b007fSCarlos Bilbao     Las barreras de memoria generales implican barreras de memoria tanto
499259b007fSCarlos Bilbao     de lectura como de escritura, de modo que pueden sustituir a
500259b007fSCarlos Bilbao     cualquiera.
501259b007fSCarlos Bilbao
502259b007fSCarlos BilbaoY un par de variedades implícitas:
503259b007fSCarlos Bilbao
504259b007fSCarlos Bilbao (5)  ACQUIRE (de adquisición).
505259b007fSCarlos Bilbao
506259b007fSCarlos Bilbao     Esto actúa como una barrera permeable unidireccional. Garantiza que
507259b007fSCarlos Bilbao     toda las operaciones de memoria después de la operación ACQUIRE
508259b007fSCarlos Bilbao     parezcan suceder después de la ACQUIRE con respecto a los demás
509259b007fSCarlos Bilbao     componentes del sistema. Las operaciones ACQUIRE incluyen operaciones
510259b007fSCarlos Bilbao     LOCK y smp_load_acquire(), y operaciones smp_cond_load_acquire().
511259b007fSCarlos Bilbao
512259b007fSCarlos Bilbao     Las operaciones de memoria que ocurren antes de una operación ACQUIRE
513259b007fSCarlos Bilbao     pueden parecer suceder después de que se complete.
514259b007fSCarlos Bilbao
515259b007fSCarlos Bilbao     Una operación ACQUIRE casi siempre debe estar emparejada con una
516259b007fSCarlos Bilbao     operación RELEASE (de liberación).
517259b007fSCarlos Bilbao
518259b007fSCarlos Bilbao
519259b007fSCarlos Bilbao (6) Operaciones RELEASE (de liberación).
520259b007fSCarlos Bilbao
521259b007fSCarlos Bilbao     Esto también actúa como una barrera permeable unidireccional.
522259b007fSCarlos Bilbao     Garantiza que todas las operaciones de memoria antes de la operación
523259b007fSCarlos Bilbao     RELEASE parecerán ocurrir antes de la operación RELEASE con respecto a
524259b007fSCarlos Bilbao     los demás componentes del sistema. Las operaciones de RELEASE incluyen
525259b007fSCarlos Bilbao     operaciones de UNLOCK y operaciones smp_store_release().
526259b007fSCarlos Bilbao
527259b007fSCarlos Bilbao     Las operaciones de memoria que ocurren después de una operación
528259b007fSCarlos Bilbao     RELEASE pueden parecer suceder antes de que se complete.
529259b007fSCarlos Bilbao
530259b007fSCarlos Bilbao     El uso de las operaciones ACQUIRE y RELEASE generalmente excluye la
531259b007fSCarlos Bilbao     necesidad de otros tipos de barrera de memoria. Además, un par
532259b007fSCarlos Bilbao     RELEASE+ACQUIRE NO garantiza actuar como una barrera de memoria
533259b007fSCarlos Bilbao     completa. Sin embargo, después de un ACQUIRE de una variable dada,
534259b007fSCarlos Bilbao     todos los accesos a la memoria que preceden a cualquier anterior
535259b007fSCarlos Bilbao     RELEASE en esa misma variable están garantizados como visibles. En
536259b007fSCarlos Bilbao     otras palabras, dentro de la sección crítica de una variable dada,
537259b007fSCarlos Bilbao     todos los accesos de todas las secciones críticas anteriores para esa
538259b007fSCarlos Bilbao     variable habrán terminado de forma garantizada.
539259b007fSCarlos Bilbao
540259b007fSCarlos Bilbao     Esto significa que ACQUIRE actúa como una operación mínima de
541259b007fSCarlos Bilbao     "adquisición" y RELEASE actúa como una operación mínima de
542259b007fSCarlos Bilbao     "liberación".
543259b007fSCarlos Bilbao
544259b007fSCarlos BilbaoUn subconjunto de las operaciones atómicas descritas en atomic_t.txt
545259b007fSCarlos Bilbaocontiene variantes de ACQUIRE y RELEASE, además de definiciones
546259b007fSCarlos Bilbaocompletamente ordenadas o relajadas (sin barrera semántica). Para
547259b007fSCarlos Bilbaocomposiciones atómicas que realizan tanto un load como store, la semántica
548259b007fSCarlos BilbaoACQUIRE se aplica solo a la carga y la semántica RELEASE se aplica sólo a
549259b007fSCarlos Bilbaola parte de la operación del store.
550259b007fSCarlos Bilbao
551259b007fSCarlos BilbaoLas barreras de memoria solo son necesarias cuando existe la posibilidad de
552259b007fSCarlos Bilbaointeracción entre dos CPU o entre una CPU y un dispositivo. Si se puede
553259b007fSCarlos Bilbaogarantizar que no habrá tal interacción en ninguna pieza de código en
554259b007fSCarlos Bilbaoparticular, entonces las barreras de memoria son innecesarias en ese
555259b007fSCarlos Bilbaofragmento de código.
556259b007fSCarlos Bilbao
557259b007fSCarlos BilbaoTenga en cuenta que estas son las garantías _mínimas_. Diferentes
558259b007fSCarlos Bilbaoarquitecturas pueden proporcionar garantías más sustanciales, pero no se
559259b007fSCarlos Bilbaopuede confiar en estas fuera de esa arquitectura en específico.
560259b007fSCarlos Bilbao
561259b007fSCarlos Bilbao
562259b007fSCarlos Bilbao¿QUÉ NO SE PUEDE ASUMIR SOBRE LAS BARRERAS DE LA MEMORIA?
563259b007fSCarlos Bilbao---------------------------------------------------------
564259b007fSCarlos Bilbao
565259b007fSCarlos BilbaoHay ciertas cosas que las barreras de memoria del kernel Linux no
566259b007fSCarlos Bilbaogarantizan:
567259b007fSCarlos Bilbao
568259b007fSCarlos Bilbao (*) No hay garantía de que ninguno de los accesos a la memoria
569259b007fSCarlos Bilbao     especificados antes de una barrera de memoria estará _completo_ al
570259b007fSCarlos Bilbao     completarse una instrucción de barrera de memoria; se puede considerar
571259b007fSCarlos Bilbao     que la barrera dibuja una línea en la cola de acceso del CPU que no
572259b007fSCarlos Bilbao     pueden cruzar los accesos del tipo correspondiente.
573259b007fSCarlos Bilbao
574259b007fSCarlos Bilbao (*) No hay garantía de que la emisión de una barrera de memoria en una CPU
575259b007fSCarlos Bilbao     tenga cualquier efecto directo en otra CPU o cualquier otro hardware
576259b007fSCarlos Bilbao     en el sistema. El efecto indirecto será el orden en que la segunda CPU
577259b007fSCarlos Bilbao     ve los efectos de los primeros accesos que ocurren de la CPU, pero lea
578259b007fSCarlos Bilbao     el siguiente argumento:
579259b007fSCarlos Bilbao
580259b007fSCarlos Bilbao (*) No hay garantía de que una CPU vea el orden correcto de los efectos
581259b007fSCarlos Bilbao     de los accesos de una segunda CPU, incluso _si_ la segunda CPU usa una
582259b007fSCarlos Bilbao     barrera de memoria, a menos que la primera CPU _también_ use una
583259b007fSCarlos Bilbao     barrera de memoria coincidente (vea el subapartado "Emparejamiento de
584259b007fSCarlos Bilbao     barrera SMP").
585259b007fSCarlos Bilbao
586259b007fSCarlos Bilbao (*) No hay garantía de que alguna pieza intermedia fuera del hardware[*]
587259b007fSCarlos Bilbao     del CPU no reordenará los accesos a la memoria. Los mecanismos de
588259b007fSCarlos Bilbao     coherencia de caché del CPU deben propagar los efectos indirectos de
589259b007fSCarlos Bilbao     una barrera de memoria entre las CPU, pero es posible que no lo hagan
590259b007fSCarlos Bilbao     en orden.
591259b007fSCarlos Bilbao
592259b007fSCarlos Bilbao	[*] Para obtener información sobre bus mastering DMA y coherencia, lea:
593259b007fSCarlos Bilbao
594259b007fSCarlos Bilbao	    Documentation/driver-api/pci/pci.rst
595259b007fSCarlos Bilbao	    Documentation/core-api/dma-api-howto.rst
596259b007fSCarlos Bilbao	    Documentation/core-api/dma-api.rst
597259b007fSCarlos Bilbao
598259b007fSCarlos Bilbao
599259b007fSCarlos BilbaoBARRERA DE DEPENDENCIA DE DIRECCIÓN (HISTÓRICO)
600259b007fSCarlos Bilbao-----------------------------------------------
601259b007fSCarlos Bilbao
602259b007fSCarlos BilbaoA partir de la versión 4.15 del kernel Linux, se agregó un smp_mb() a
603259b007fSCarlos BilbaoREAD_ONCE() para DEC Alpha, lo que significa que las únicas personas que
604259b007fSCarlos Bilbaonecesitan prestar atención a esta sección son aquellas que trabajan en el
605259b007fSCarlos Bilbaocódigo específico de la arquitectura DEC Alpha y aquellas que trabajan en
606259b007fSCarlos BilbaoREAD_ONCE() por dentro. Para aquellos que lo necesitan, y para aquellos que
607*bd2c35d0SAkira Yokosawaestén interesados desde un punto de vista histórico, aquí está la historia
608259b007fSCarlos Bilbaode las barreras de dependencia de dirección.
609259b007fSCarlos Bilbao
610259b007fSCarlos Bilbao[!] Si bien las dependencias de direcciones se observan tanto en carga a
611259b007fSCarlos Bilbaocarga como en relaciones de carga a store, las barreras de dependencia de
612259b007fSCarlos Bilbaodirección no son necesarias para situaciones de carga a store.
613259b007fSCarlos Bilbao
614259b007fSCarlos BilbaoEl requisito de las barreras de dependencia de dirección es un poco sutil,
615259b007fSCarlos Bilbaoy no siempre es obvio que sean necesarias. Para ilustrar, considere la
616259b007fSCarlos Bilbaosiguiente secuencia de eventos:
617259b007fSCarlos Bilbao
618259b007fSCarlos Bilbao	CPU 1		      CPU 2
619259b007fSCarlos Bilbao	===============	      ===============
620259b007fSCarlos Bilbao	{ A == 1, B == 2, C == 3, P == &A, Q == &C }
621259b007fSCarlos Bilbao	B = 4;
622259b007fSCarlos Bilbao	<barrera de escritura>
623259b007fSCarlos Bilbao	WRITE_ONCE(P, &B);
624259b007fSCarlos Bilbao			      Q = READ_ONCE_OLD(P);
625259b007fSCarlos Bilbao			      D = *Q;
626259b007fSCarlos Bilbao
627259b007fSCarlos Bilbao[!] READ_ONCE_OLD() corresponde a READ_ONCE() del kernel anterior a 4.15,
628259b007fSCarlos Bilbaoque no implica una barrera de dependencia de direcciones.
629259b007fSCarlos Bilbao
630259b007fSCarlos BilbaoHay una clara dependencia de dirección aquí, y parecería que al final de
631259b007fSCarlos Bilbaola secuencia, Q debe ser &A o &B, y que:
632259b007fSCarlos Bilbao
633259b007fSCarlos Bilbao	(Q == &A) implica (D == 1)
634259b007fSCarlos Bilbao	(Q == &B) implica (D == 4)
635259b007fSCarlos Bilbao
636259b007fSCarlos Bilbao¡Pero! La percepción de la CPU 2 de P puede actualizarse _antes_ de su
637259b007fSCarlos Bilbaopercepción de B, por lo tanto dando lugar a la siguiente situación:
638259b007fSCarlos Bilbao
639259b007fSCarlos Bilbao	(Q == &B) y (D == 2) ????
640259b007fSCarlos Bilbao
641259b007fSCarlos BilbaoSi bien esto puede parecer una falla en el mantenimiento de la coherencia
642259b007fSCarlos Bilbaoo la causalidad, no lo es, y este comportamiento se puede observar en
643259b007fSCarlos Bilbaociertas CPU reales (como DEC Alfa).
644259b007fSCarlos Bilbao
645259b007fSCarlos BilbaoPara lidiar con esto, READ_ONCE() proporciona una barrera de dependencia
646259b007fSCarlos Bilbaode dirección implícita desde el lanzamiento del kernel v4.15:
647259b007fSCarlos Bilbao
648259b007fSCarlos Bilbao	CPU 1		      CPU 2
649259b007fSCarlos Bilbao	===============	      ===============
650259b007fSCarlos Bilbao	{ A == 1, B == 2, C == 3, P == &A, Q == &C }
651259b007fSCarlos Bilbao	B = 4;
652259b007fSCarlos Bilbao	<barrera de escritura>
653259b007fSCarlos Bilbao	WRITE_ONCE(P, &B);
654259b007fSCarlos Bilbao			      Q = READ_ONCE(P);
655259b007fSCarlos Bilbao			      <barrera de dependencia de dirección implícita>
656259b007fSCarlos Bilbao			      D = *Q;
657259b007fSCarlos Bilbao
658259b007fSCarlos BilbaoEsto refuerza la ocurrencia de una de las dos implicaciones, y previene la
659259b007fSCarlos Bilbaotercera posibilidad de surgir.
660259b007fSCarlos Bilbao
661259b007fSCarlos Bilbao
662259b007fSCarlos Bilbao[!] Tenga en cuenta que esta situación extremadamente contraria a la
663259b007fSCarlos Bilbaointuición surge más fácilmente en máquinas con cachés divididos, de modo
664259b007fSCarlos Bilbaoque, por ejemplo, un banco de caché procesa líneas de caché pares y el otro
665259b007fSCarlos Bilbaobanco procesa líneas impares de caché. El puntero P podría almacenarse en
666259b007fSCarlos Bilbaouna línea de caché impar y la variable B podría almacenarse en una línea de
667259b007fSCarlos Bilbaocaché con número par. Entonces, si el banco de números pares de la memoria
668259b007fSCarlos Bilbaocaché de la CPU de lectura está extremadamente ocupado mientras que el
669259b007fSCarlos Bilbaobanco impar está inactivo, uno podría ver el nuevo valor del puntero P
670259b007fSCarlos Bilbao(&B), pero el antiguo valor de la variable B (2).
671259b007fSCarlos Bilbao
672259b007fSCarlos Bilbao
673259b007fSCarlos BilbaoNo se requiere una barrera de dependencia de dirección para ordenar
674259b007fSCarlos Bilbaoescrituras dependientes porque las CPU que admite el kernel Linux no
675259b007fSCarlos Bilbaoescriben hasta que están seguros (1) de que la escritura realmente
676259b007fSCarlos Bilbaosucederá, (2) de la ubicación de la escritura, y (3) del valor a escribir.
677259b007fSCarlos BilbaoPero, por favor, lea atentamente la sección "DEPENDENCIAS DEL CONTROL" y el
678259b007fSCarlos Bilbaoarchivo Documentation/RCU/rcu_dereference.rst: el compilador puede romperse
679259b007fSCarlos Bilbaoy romper dependencias en muchas formas altamente creativas.
680259b007fSCarlos Bilbao
681259b007fSCarlos Bilbao	CPU 1		      CPU 2
682259b007fSCarlos Bilbao	===============	      ===============
683259b007fSCarlos Bilbao	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
684259b007fSCarlos Bilbao	B = 4;
685259b007fSCarlos Bilbao	<barrera de escritura>
686259b007fSCarlos Bilbao	WRITE_ONCE(P, &B);
687259b007fSCarlos Bilbao			      Q = READ_ONCE_OLD(P);
688259b007fSCarlos Bilbao			      WRITE_ONCE(*Q, 5);
689259b007fSCarlos Bilbao
690259b007fSCarlos BilbaoPor lo tanto, no se requiere ninguna barrera de dependencia de direcciones
691259b007fSCarlos Bilbaopara ordenar la lectura en Q con el load en *Q. En otras palabras, este
692259b007fSCarlos Bilbaoresultado está prohibido, incluso sin una barrera de dependencia de
693259b007fSCarlos Bilbaodirección implícita del READ_ONCE() moderno:
694259b007fSCarlos Bilbao
695259b007fSCarlos Bilbao	(Q == &B) && (B == 4)
696259b007fSCarlos Bilbao
697259b007fSCarlos BilbaoTenga en cuenta que este patrón debe ser raro. Después de todo, el objetivo
698259b007fSCarlos Bilbaodel orden de dependencia es -prevenir- escrituras en la estructura de
699259b007fSCarlos Bilbaodatos, junto con los costosos errores de caché asociados con tales
700259b007fSCarlos Bilbaoescrituras. Este patrón se puede utilizar para registrar raras condiciones
701259b007fSCarlos Bilbaode error y similares, y el orden natural de las CPUs evita que se pierdan
702259b007fSCarlos Bilbaotales registros.
703259b007fSCarlos Bilbao
704259b007fSCarlos Bilbao
705259b007fSCarlos BilbaoTenga en cuenta que el orden proporcionado por una dependencia de dirección
706259b007fSCarlos Bilbaoes local para la CPU que lo contiene. Lea la sección sobre "Atomicidad
707259b007fSCarlos Bilbaomulticopia" para más información.
708259b007fSCarlos Bilbao
709259b007fSCarlos Bilbao
710259b007fSCarlos BilbaoLa barrera de dependencia de dirección es muy importante para el sistema
711259b007fSCarlos BilbaoRCU, por ejemplo. Vea rcu_assign_pointer() y rcu_dereference() en
712259b007fSCarlos Bilbaoinclude/linux/rcupdate.h. Esto permite que el objetivo actual de un puntero
713259b007fSCarlos BilbaoRCU sea reemplazado con un nuevo objetivo modificado, sin que el objetivo
714259b007fSCarlos Bilbaodel reemplazo parezca estar inicializado de manera incompleta.
715259b007fSCarlos Bilbao
716259b007fSCarlos BilbaoConsulte también la subsección sobre "Coherencia de caché" para obtener un
717259b007fSCarlos Bilbaoejemplo más completo.
718259b007fSCarlos Bilbao
719259b007fSCarlos BilbaoDEPENDENCIAS DE CONTROL
720259b007fSCarlos Bilbao-----------------------
721259b007fSCarlos Bilbao
722259b007fSCarlos BilbaoLas dependencias de control pueden ser un poco complicadas porque los
723259b007fSCarlos Bilbaocompiladores actuales no las entienden. El propósito de esta sección es
724259b007fSCarlos Bilbaoayudarle a prevenir que la ignorancia del compilador rompa su código.
725259b007fSCarlos Bilbao
726259b007fSCarlos BilbaoUna dependencia de control load-load (de carga a carga) requiere una
727259b007fSCarlos Bilbaobarrera de memoria de lectura completa, no simplemente una barrera
728259b007fSCarlos Bilbao(implícita) de dependencia de direcciones para que funcione correctamente.
729259b007fSCarlos BilbaoConsidere el siguiente fragmento de código:
730259b007fSCarlos Bilbao
731259b007fSCarlos Bilbao	q = READ_ONCE(a);
732259b007fSCarlos Bilbao	<barrera implícita de dependencia de direcciones>
733259b007fSCarlos Bilbao	if (q) {
734259b007fSCarlos Bilbao		/* BUG: No hay dependencia de dirección!!! */
735259b007fSCarlos Bilbao		p = READ_ONCE(b);
736259b007fSCarlos Bilbao	}
737259b007fSCarlos Bilbao
738259b007fSCarlos BilbaoEsto no tendrá el efecto deseado porque no hay una dependencia de dirección
739259b007fSCarlos Bilbaoreal, sino más bien una dependencia de control que la CPU puede
740259b007fSCarlos Bilbaocortocircuitar al intentar predecir el resultado por adelantado, para que
741259b007fSCarlos Bilbaootras CPU vean la carga de b como si hubiera ocurrido antes que la carga de
742259b007fSCarlos Bilbaoa. En cuyo caso lo que realmente se requiere es:
743259b007fSCarlos Bilbao
744259b007fSCarlos Bilbao  	q = READ_ONCE(a);
745259b007fSCarlos Bilbao  	if (q) {
746259b007fSCarlos Bilbao  		<barrera de lectura>
747259b007fSCarlos Bilbao  		p = READ_ONCE(b);
748259b007fSCarlos Bilbao  	}
749259b007fSCarlos Bilbao
750259b007fSCarlos BilbaoSin embargo, los stores no se especulan. Esto significa que ordenar -es-
751259b007fSCarlos Bilbaoprovisto para dependencias de control de load-store, como en el siguiente
752259b007fSCarlos Bilbaoejemplo:
753259b007fSCarlos Bilbao
754259b007fSCarlos Bilbao	q = READ_ONCE(a);
755259b007fSCarlos Bilbao	if (q) {
756259b007fSCarlos Bilbao		WRITE_ONCE(b, 1);
757259b007fSCarlos Bilbao	}
758259b007fSCarlos Bilbao
759259b007fSCarlos BilbaoLas dependencias de control se emparejan normalmente con otros tipos de
760259b007fSCarlos Bilbaobarreras. Dicho esto, tenga en cuenta que ni READ_ONCE() ni WRITE_ONCE()
761259b007fSCarlos Bilbaoson opcionales! Sin READ_ONCE(), el compilador podría combinar la carga de
762259b007fSCarlos Bilbao'a' con otras cargas de 'a'. Sin WRITE_ONCE(), el compilador podría
763259b007fSCarlos Bilbaocombinar el store de 'b' con otros stores de 'b'. Cualquiera de estos casos
764259b007fSCarlos Bilbaopuede dar lugar a efectos en el orden muy contrarios a la intuición.
765259b007fSCarlos Bilbao
766259b007fSCarlos BilbaoPeor aún, si el compilador puede probar (decir) que el valor de la
767259b007fSCarlos Bilbaovariable 'a' siempre es distinta de cero, estaría dentro de sus derechos
768259b007fSCarlos Bilbaopara optimizar el ejemplo original eliminando la declaración "if", como:
769259b007fSCarlos Bilbao
770259b007fSCarlos Bilbao	q = a;
771259b007fSCarlos Bilbao	b = 1;  /* BUG: Compilador y CPU pueden ambos reordernar!!! */
772259b007fSCarlos Bilbao
773259b007fSCarlos BilbaoAsí que no deje de lado READ_ONCE().
774259b007fSCarlos Bilbao
775259b007fSCarlos BilbaoEs tentador tratar de hacer cumplir el orden en stores idénticos en ambos
776259b007fSCarlos Bilbaocaminos del "if" de la siguiente manera:
777259b007fSCarlos Bilbao
778259b007fSCarlos Bilbao	q = READ_ONCE(a);
779259b007fSCarlos Bilbao	if (q) {
780259b007fSCarlos Bilbao		barrier();
781259b007fSCarlos Bilbao		WRITE_ONCE(b, 1);
782259b007fSCarlos Bilbao		hacer_algo();
783259b007fSCarlos Bilbao	} else {
784259b007fSCarlos Bilbao		barrier();
785259b007fSCarlos Bilbao		WRITE_ONCE(b, 1);
786259b007fSCarlos Bilbao		hacer_otra_cosa();
787259b007fSCarlos Bilbao	}
788259b007fSCarlos Bilbao
789259b007fSCarlos BilbaoDesafortunadamente, los compiladores actuales transformarán esto de la
790259b007fSCarlos Bilbaosiguiente manera en casos de alto nivel de optimización:
791259b007fSCarlos Bilbao
792259b007fSCarlos Bilbao  	q = READ_ONCE(a);
793259b007fSCarlos Bilbao  	barrier();
794259b007fSCarlos Bilbao  	WRITE_ONCE(b, 1);  /* BUG: No hay orden en load de a!!! */
795259b007fSCarlos Bilbao  	if (q) {
796259b007fSCarlos Bilbao  		/* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
797259b007fSCarlos Bilbao  		hacer_algo();
798259b007fSCarlos Bilbao  	} else {
799259b007fSCarlos Bilbao  		/* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
800259b007fSCarlos Bilbao  		hacer_otra_cosa();
801259b007fSCarlos Bilbao  	}
802259b007fSCarlos Bilbao
803259b007fSCarlos BilbaoAhora no hay condicional entre la carga de 'a' y el store de 'b', lo que
804259b007fSCarlos Bilbaosignifica que la CPU está en su derecho de reordenarlos: El condicional es
805259b007fSCarlos Bilbaoabsolutamente necesario y debe estar presente en el código ensamblador
806259b007fSCarlos Bilbaoincluso después de que se hayan aplicado todas las optimizaciones del
807259b007fSCarlos Bilbaocompilador. Por lo tanto, si necesita ordenar en este ejemplo, necesita
808259b007fSCarlos Bilbaoexplícitamente barreras de memoria, por ejemplo, smp_store_release():
809259b007fSCarlos Bilbao
810259b007fSCarlos Bilbao
811259b007fSCarlos Bilbao	q = READ_ONCE(a);
812259b007fSCarlos Bilbao	if (q) {
813259b007fSCarlos Bilbao		smp_store_release(&b, 1);
814259b007fSCarlos Bilbao		hacer_algo();
815259b007fSCarlos Bilbao	} else {
816259b007fSCarlos Bilbao		smp_store_release(&b, 1);
817259b007fSCarlos Bilbao		hacer_otra_cosa();
818259b007fSCarlos Bilbao	}
819259b007fSCarlos Bilbao
820259b007fSCarlos BilbaoPor el contrario, sin barreras de memoria explícita, el control de un if
821259b007fSCarlos Bilbaocon dos opciones está garantizado solo cuando los stores difieren, por
822259b007fSCarlos Bilbaoejemplo:
823259b007fSCarlos Bilbao
824259b007fSCarlos Bilbao  	q = READ_ONCE(a);
825259b007fSCarlos Bilbao  	if (q) {
826259b007fSCarlos Bilbao  		WRITE_ONCE(b, 1);
827259b007fSCarlos Bilbao  		hacer_algo();
828259b007fSCarlos Bilbao  	} else {
829259b007fSCarlos Bilbao  		WRITE_ONCE(b, 2);
830259b007fSCarlos Bilbao  		hacer_otra_cosa();
831259b007fSCarlos Bilbao  	}
832259b007fSCarlos Bilbao
833259b007fSCarlos BilbaoAún se requiere el inicial READ_ONCE() para evitar que el compilador toque
834259b007fSCarlos Bilbaoel valor de 'a'.
835259b007fSCarlos Bilbao
836259b007fSCarlos BilbaoAdemás, debe tener cuidado con lo que hace con la variable local 'q', de lo
837259b007fSCarlos Bilbaocontrario, el compilador podría adivinar el valor y volver a eliminar el
838259b007fSCarlos Bilbaonecesario condicional. Por ejemplo:
839259b007fSCarlos Bilbao
840259b007fSCarlos Bilbao  	q = READ_ONCE(a);
841259b007fSCarlos Bilbao  	if (q % MAX) {
842259b007fSCarlos Bilbao  		WRITE_ONCE(b, 1);
843259b007fSCarlos Bilbao  		hacer_algo();
844259b007fSCarlos Bilbao  	} else {
845259b007fSCarlos Bilbao  		WRITE_ONCE(b, 2);
846259b007fSCarlos Bilbao  		hacer_otra_cosa();
847259b007fSCarlos Bilbao  	}
848259b007fSCarlos Bilbao
849259b007fSCarlos BilbaoSi MAX se define como 1, entonces el compilador sabe que (q % MAX) es igual
850259b007fSCarlos Bilbaoa cero, en cuyo caso el compilador tiene derecho a transformar el código
851259b007fSCarlos Bilbaoanterior en el siguiente:
852259b007fSCarlos Bilbao
853259b007fSCarlos Bilbao  	q = READ_ONCE(a);
854259b007fSCarlos Bilbao  	WRITE_ONCE(b, 2);
855259b007fSCarlos Bilbao  	hacer_otra_cosa();
856259b007fSCarlos Bilbao
857259b007fSCarlos BilbaoDada esta transformación, la CPU no está obligada a respetar el orden entre
858259b007fSCarlos Bilbaola carga de la variable 'a' y el store de la variable 'b'. Es tentador
859259b007fSCarlos Bilbaoagregar una barrier(), pero esto no ayuda. El condicional se ha ido, y la
860259b007fSCarlos Bilbaobarrera no lo traerá de vuelta. Por lo tanto, si confia en este orden, debe
861259b007fSCarlos Bilbaoasegurarse de que MAX sea mayor que uno, tal vez de la siguiente manera:
862259b007fSCarlos Bilbao
863259b007fSCarlos Bilbao  	q = READ_ONCE(a);
864259b007fSCarlos Bilbao  	BUILD_BUG_ON(MAX <= 1); /* Orden de carga de a con store de b */
865259b007fSCarlos Bilbao  	if (q % MAX) {
866259b007fSCarlos Bilbao  		WRITE_ONCE(b, 1);
867259b007fSCarlos Bilbao  		hacer_algo();
868259b007fSCarlos Bilbao  	} else {
869259b007fSCarlos Bilbao  		WRITE_ONCE(b, 2);
870259b007fSCarlos Bilbao  		hacer_otra_cosa();
871259b007fSCarlos Bilbao  	}
872259b007fSCarlos Bilbao
873259b007fSCarlos BilbaoTenga en cuenta una vez más que los stores de 'b' difieren. Si fueran
874259b007fSCarlos Bilbaoidénticos, como se señaló anteriormente, el compilador podría sacar ese
875259b007fSCarlos Bilbaostore fuera de la declaración 'if'.
876259b007fSCarlos Bilbao
877259b007fSCarlos BilbaoTambién debe tener cuidado de no confiar demasiado en el cortocircuito
878259b007fSCarlos Bilbaode la evaluación booleana. Considere este ejemplo:
879259b007fSCarlos Bilbao
880259b007fSCarlos Bilbao  	q = READ_ONCE(a);
881259b007fSCarlos Bilbao  	if (q || 1 > 0)
882259b007fSCarlos Bilbao  	WRITE_ONCE(b, 1);
883259b007fSCarlos Bilbao
884259b007fSCarlos BilbaoDebido a que la primera condición no puede fallar y la segunda condición es
885259b007fSCarlos Bilbaosiempre cierta, el compilador puede transformar este ejemplo de la
886259b007fSCarlos Bilbaosiguiente manera, rompiendo la dependencia del control:
887259b007fSCarlos Bilbao
888259b007fSCarlos Bilbao  	q = READ_ONCE(a);
889259b007fSCarlos Bilbao  	WRITE_ONCE(b, 1);
890259b007fSCarlos Bilbao
891259b007fSCarlos BilbaoEste ejemplo subraya la necesidad de asegurarse de que el compilador no
892259b007fSCarlos Bilbaopueda adivinar su código. Más generalmente, aunque READ_ONCE() fuerza
893259b007fSCarlos Bilbaoal compilador para emitir código para una carga dada, no fuerza al
894259b007fSCarlos Bilbaocompilador para usar los resultados.
895259b007fSCarlos Bilbao
896259b007fSCarlos BilbaoAdemás, las dependencias de control se aplican solo a la cláusula then y
897259b007fSCarlos Bilbaola cláusula else de la sentencia if en cuestión. En particular, no se
898259b007fSCarlos Bilbaoaplica necesariamente al código que sigue a la declaración if:
899259b007fSCarlos Bilbao
900259b007fSCarlos Bilbao  	q = READ_ONCE(a);
901259b007fSCarlos Bilbao  	if (q) {
902259b007fSCarlos Bilbao  		WRITE_ONCE(b, 1);
903259b007fSCarlos Bilbao  	} else {
904259b007fSCarlos Bilbao  		WRITE_ONCE(b, 2);
905259b007fSCarlos Bilbao  	}
906259b007fSCarlos Bilbao  	WRITE_ONCE(c, 1);  /* BUG: No hay orden para la lectura de 'a'. */
907259b007fSCarlos Bilbao
908259b007fSCarlos BilbaoEs tentador argumentar que, de hecho, existe un orden porque el compilador
909259b007fSCarlos Bilbaono puede reordenar accesos volátiles y tampoco puede reordenar escrituras
910259b007fSCarlos Bilbaoen 'b' con la condición. Desafortunadamente para esta línea de
911259b007fSCarlos Bilbaorazonamiento, el compilador podría compilar las dos escrituras en 'b' como
912259b007fSCarlos Bilbaoinstrucciones de movimiento condicional, como en este fantástico idioma
913259b007fSCarlos Bilbaopseudo-ensamblador:
914259b007fSCarlos Bilbao
915259b007fSCarlos Bilbao        	ld r1,a
916259b007fSCarlos Bilbao        	cmp r1,$0
917259b007fSCarlos Bilbao        	cmov,ne r4,$1
918259b007fSCarlos Bilbao        	cmov,eq r4,$2
919259b007fSCarlos Bilbao        	st r4,b
920259b007fSCarlos Bilbao        	st $1,c
921259b007fSCarlos Bilbao
922259b007fSCarlos BilbaoUna CPU débilmente ordenada no tendría dependencia de ningún tipo entre la
923259b007fSCarlos Bilbaocarga de 'a' y el store de 'c'. Las dependencias de control se extenderían
924259b007fSCarlos Bilbaosolo al par de instrucciones cmov y el store dependiente de ellas. En
925259b007fSCarlos Bilbaoresumen, las dependencias de control se aplican solo a los stores en la
926259b007fSCarlos Bilbaocláusula then y la cláusula else de la sentencia if en cuestión (incluidas
927259b007fSCarlos Bilbaolas funciones invocado por esas dos cláusulas), no al código que sigue a
928259b007fSCarlos Bilbaoesa declaración if.
929259b007fSCarlos Bilbao
930259b007fSCarlos Bilbao
931259b007fSCarlos BilbaoTenga muy en cuenta que el orden proporcionado por una dependencia de
932259b007fSCarlos Bilbaocontrol es local a la CPU que lo contiene. Vea el apartado de "Atomicidad
933259b007fSCarlos Bilbaomulticopia" para más información.
934259b007fSCarlos Bilbao
935259b007fSCarlos Bilbao
936259b007fSCarlos BilbaoEn resumen:
937259b007fSCarlos Bilbao
938259b007fSCarlos Bilbao  (*) Las dependencias de control pueden ordenar cargas anteriores para
939259b007fSCarlos Bilbao      stores posteriores. Sin embargo, no garantizan ningún otro tipo de
940259b007fSCarlos Bilbao      orden: No cargas previas contra cargas posteriores, ni
941259b007fSCarlos Bilbao      almacenamientos previos y luego nada. Si necesita tales formas de
942259b007fSCarlos Bilbao      orden, use smp_rmb(), smp_wmb() o, en el caso de stores anteriores y
943259b007fSCarlos Bilbao      cargas posteriores, smp_mb().
944259b007fSCarlos Bilbao
945259b007fSCarlos Bilbao  (*) Si ambos caminos de la declaración "if" comienzan con stores
946259b007fSCarlos Bilbao      idénticos de la misma variable, entonces esos stores deben ser
947259b007fSCarlos Bilbao      ordenados, ya sea precediéndoles a ambos con smp_mb() o usando
948259b007fSCarlos Bilbao      smp_store_release() para realizar el store. Tenga en cuenta que -no-
949259b007fSCarlos Bilbao      es suficiente usar barrier() al comienzo de cada caso de la
950259b007fSCarlos Bilbao      declaración "if" porque, como se muestra en el ejemplo anterior, la
951259b007fSCarlos Bilbao      optimización de los compiladores puede destruir la dependencia de
952259b007fSCarlos Bilbao      control respetando al pie de la letra la ley de barrier().
953259b007fSCarlos Bilbao
954259b007fSCarlos Bilbao  (*) Las dependencias de control requieren al menos un condicional en
955259b007fSCarlos Bilbao      tiempo de ejecución entre la carga anterior y el almacenamiento
956259b007fSCarlos Bilbao      posterior, y este condicional debe implicar la carga previa. Si el
957259b007fSCarlos Bilbao      compilador es capaz de optimizar el condicional y quitarlo, también
958259b007fSCarlos Bilbao      habrá optimizado el ordenar. El uso cuidadoso de READ_ONCE() y
959259b007fSCarlos Bilbao      WRITE_ONCE() puede ayudar a preservar el necesario condicional.
960259b007fSCarlos Bilbao
961259b007fSCarlos Bilbao  (*) Las dependencias de control requieren que el compilador evite
962259b007fSCarlos Bilbao      reordenar las dependencia hasta su inexistencia. El uso cuidadoso de
963259b007fSCarlos Bilbao      READ_ONCE() o atomic{,64}_read() puede ayudarle a preservar la
964259b007fSCarlos Bilbao      dependencia de control. Consulte la sección BARRERA DEL COMPILADOR
965259b007fSCarlos Bilbao      para obtener más información al respecto.
966259b007fSCarlos Bilbao
967259b007fSCarlos Bilbao  (*) Las dependencias de control se aplican solo a la cláusula then y la
968259b007fSCarlos Bilbao      cláusula else de la sentencia "if" que contiene la dependencia de
969259b007fSCarlos Bilbao      control, incluyendo cualquier función a la que llamen dichas dos
970259b007fSCarlos Bilbao      cláusulas. Las dependencias de control no se aplican al código que
971259b007fSCarlos Bilbao      sigue a la instrucción if que contiene la dependencia de control.
972259b007fSCarlos Bilbao
973259b007fSCarlos Bilbao  (*) Las dependencias de control se emparejan normalmente con otros tipos
974259b007fSCarlos Bilbao      de barreras.
975259b007fSCarlos Bilbao
976259b007fSCarlos Bilbao  (*) Las dependencias de control no proporcionan atomicidad multicopia. Si
977259b007fSCarlos Bilbao      usted necesita todas las CPU para ver un store dado al mismo tiempo,
978259b007fSCarlos Bilbao      emplee smp_mb().
979259b007fSCarlos Bilbao
980259b007fSCarlos Bilbao  (*) Los compiladores no entienden las dependencias de control. Por lo
981259b007fSCarlos Bilbao      tanto es su trabajo asegurarse de que no rompan su código.
982259b007fSCarlos Bilbao
983259b007fSCarlos Bilbao
984259b007fSCarlos BilbaoEMPAREJAMIENTO DE BARRERAS SMP
985259b007fSCarlos Bilbao------------------------------
986259b007fSCarlos Bilbao
987259b007fSCarlos BilbaoCuando se trata de interacciones CPU-CPU, ciertos tipos de barrera de
988259b007fSCarlos Bilbaomemoria deben estar siempre emparejados. La falta del apropiado
989259b007fSCarlos Bilbaoemparejamiento es casi seguro un error.
990259b007fSCarlos Bilbao
991259b007fSCarlos BilbaoLas barreras generales se emparejan entre sí, aunque también se emparejan
992259b007fSCarlos Bilbaocon la mayoría de otro tipo de barreras, aunque sin atomicidad multicopia.
993259b007fSCarlos BilbaoUna barrera de adquisición se empareja con una barrera de liberación, pero
994259b007fSCarlos Bilbaoambas también pueden emparejarse con otras barreras, incluidas, por
995259b007fSCarlos Bilbaosupuesto, las barreras generales. Una barrera de escritura se empareja con
996259b007fSCarlos Bilbaouna barrera de dependencia de dirección, una dependencia de control, una
997259b007fSCarlos Bilbaobarrera de adquisición, una barrera de liberación, una barrera de lectura
998259b007fSCarlos Bilbaoo una barrera general. Del mismo modo, una barrera de lectura se empareja
999259b007fSCarlos Bilbaocon una de dependencia de control o barrera de dependencia de dirección con
1000259b007fSCarlos Bilbaouna barrera de escritura, una barrera de adquisición, una barrera de
1001259b007fSCarlos Bilbaoliberación o una barrera general:
1002259b007fSCarlos Bilbao
1003259b007fSCarlos Bilbao	CPU 1		      CPU 2
1004259b007fSCarlos Bilbao	===============	      ===============
1005259b007fSCarlos Bilbao	WRITE_ONCE(a, 1);
1006259b007fSCarlos Bilbao	<barrera de escritura>
1007259b007fSCarlos Bilbao	WRITE_ONCE(b, 2);     x = READ_ONCE(b);
1008259b007fSCarlos Bilbao			      <barrera de lectura>
1009259b007fSCarlos Bilbao			      y = READ_ONCE(a);
1010259b007fSCarlos Bilbao
1011259b007fSCarlos BilbaoO bien:
1012259b007fSCarlos Bilbao
1013259b007fSCarlos Bilbao	CPU 1		      CPU 2
1014259b007fSCarlos Bilbao	===============	      ===============================
1015259b007fSCarlos Bilbao	a = 1;
1016259b007fSCarlos Bilbao	<barrera de escritura>
1017259b007fSCarlos Bilbao	WRITE_ONCE(b, &a);    x = READ_ONCE(b);
1018259b007fSCarlos Bilbao			      <barrera de dependencia de dirección implícita>
1019259b007fSCarlos Bilbao			      y = *x;
1020259b007fSCarlos Bilbao
1021259b007fSCarlos BilbaoO incluso:
1022259b007fSCarlos Bilbao
1023259b007fSCarlos Bilbao	CPU 1		      CPU 2
1024259b007fSCarlos Bilbao	===============	      ===============================
1025259b007fSCarlos Bilbao	r1 = READ_ONCE(y);
1026259b007fSCarlos Bilbao	<barrera general>
1027259b007fSCarlos Bilbao	WRITE_ONCE(x, 1);     if (r2 = READ_ONCE(x)) {
1028259b007fSCarlos Bilbao			         <barrera de control implícita>
1029259b007fSCarlos Bilbao			         WRITE_ONCE(y, 1);
1030259b007fSCarlos Bilbao			      }
1031259b007fSCarlos Bilbao
1032259b007fSCarlos Bilbao	assert(r1 == 0 || r2 == 0);
1033259b007fSCarlos Bilbao
1034259b007fSCarlos BilbaoBásicamente, la barrera de lectura siempre tiene que estar ahí, aunque
1035259b007fSCarlos Bilbaopuede ser del tipo "más débil".
1036259b007fSCarlos Bilbao
1037259b007fSCarlos Bilbao[!] Tenga en cuenta que normalmente se esperaría que los stores antes de la
1038259b007fSCarlos Bilbaobarrera de escritura se hagan coincidir con los stores después de la
1039259b007fSCarlos Bilbaobarrera de lectura o la barrera de dependencia de dirección, y viceversa:
1040259b007fSCarlos Bilbao
1041259b007fSCarlos Bilbao	CPU 1                               CPU 2
1042259b007fSCarlos Bilbao	===================                 ===================
1043259b007fSCarlos Bilbao	WRITE_ONCE(a, 1);    }----   --->{  v = READ_ONCE(c);
1044259b007fSCarlos Bilbao	WRITE_ONCE(b, 2);    }    \ /    {  w = READ_ONCE(d);
1045259b007fSCarlos Bilbao	<barrera de escritura>            \        <barrera de lectura>
1046259b007fSCarlos Bilbao	WRITE_ONCE(c, 3);    }    / \    {  x = READ_ONCE(a);
1047259b007fSCarlos Bilbao	WRITE_ONCE(d, 4);    }----   --->{  y = READ_ONCE(b);
1048259b007fSCarlos Bilbao
1049259b007fSCarlos Bilbao
1050259b007fSCarlos BilbaoEJEMPLOS DE SECUENCIAS DE BARRERA DE MEMORIA
1051259b007fSCarlos Bilbao--------------------------------------------
1052259b007fSCarlos Bilbao
1053259b007fSCarlos BilbaoEn primer lugar, las barreras de escritura actúan como orden parcial en las
1054259b007fSCarlos Bilbaooperaciones de store. Considere la siguiente secuencia de eventos:
1055259b007fSCarlos Bilbao
1056259b007fSCarlos Bilbao	CPU 1
1057259b007fSCarlos Bilbao	=======================
1058259b007fSCarlos Bilbao	STORE A = 1
1059259b007fSCarlos Bilbao	STORE B = 2
1060259b007fSCarlos Bilbao	STORE C = 3
1061259b007fSCarlos Bilbao	<barrera de escritura>
1062259b007fSCarlos Bilbao	STORE D = 4
1063259b007fSCarlos Bilbao	STORE E = 5
1064259b007fSCarlos Bilbao
1065259b007fSCarlos BilbaoEsta secuencia de eventos es finalizado para con el sistema de coherencia
1066259b007fSCarlos Bilbaode memoria en un orden que el resto del sistema podría percibir como el
1067259b007fSCarlos Bilbaoconjunto desordenado { STORE A, STORE B, STORE C} todo ocurriendo antes del
1068259b007fSCarlos Bilbaoconjunto desordenado { STORE D, STORE E}:
1069259b007fSCarlos Bilbao
1070259b007fSCarlos Bilbao
1071259b007fSCarlos Bilbao	+-------+       :      :
1072259b007fSCarlos Bilbao	|       |       +------+
1073259b007fSCarlos Bilbao	|       |------>| C=3  |     }     /\
1074259b007fSCarlos Bilbao	|       |  :    +------+     }-----  \  -----> Eventos perceptibles para
1075259b007fSCarlos Bilbao	|       |  :    | A=1  |     }        \/       el resto del sistema
1076259b007fSCarlos Bilbao	|       |  :    +------+     }
1077259b007fSCarlos Bilbao	| CPU 1 |  :    | B=2  |     }
1078259b007fSCarlos Bilbao	|       |       +------+     }
1079259b007fSCarlos Bilbao	|       |   wwwwwwwwwwwwwwww }   <--- En este momento la barrera de
1080259b007fSCarlos Bilbao	|       |       +------+     }        escritura requiere que todos los
1081259b007fSCarlos Bilbao	|       |  :    | E=5  |     }        stores anteriores a la barrera
1082259b007fSCarlos Bilbao	|       |  :    +------+     }        sean confirmados antes de que otros
1083259b007fSCarlos Bilbao	|       |------>| D=4  |     }        store puedan suceder
1084259b007fSCarlos Bilbao	|       |       +------+
1085259b007fSCarlos Bilbao	+-------+       :      :
1086259b007fSCarlos Bilbao	                   |
1087259b007fSCarlos Bilbao	                   | Secuencia por la cual los stores son confirmados al
1088259b007fSCarlos Bilbao	                   | sistema de memoria por parte del CPU 1
1089259b007fSCarlos Bilbao	                   V
1090259b007fSCarlos Bilbao
1091259b007fSCarlos BilbaoEn segundo lugar, las barreras de dependencia de dirección actúan como
1092259b007fSCarlos Bilbaoórdenes parciales sobre la dirección de cargas dependientes. Considere la
1093259b007fSCarlos Bilbaosiguiente secuencia de eventos:
1094259b007fSCarlos Bilbao
1095259b007fSCarlos Bilbao	CPU 1			CPU 2
1096259b007fSCarlos Bilbao	=======================	=======================
1097259b007fSCarlos Bilbao		{ B = 7; X = 9; Y = 8; C = &Y }
1098259b007fSCarlos Bilbao	STORE A = 1
1099259b007fSCarlos Bilbao	STORE B = 2
1100259b007fSCarlos Bilbao	<barrera de escritura>
1101259b007fSCarlos Bilbao	STORE C = &B		LOAD X
1102259b007fSCarlos Bilbao	STORE D = 4		LOAD C (consigue &B)
1103259b007fSCarlos Bilbao				LOAD *C (lee B)
1104259b007fSCarlos Bilbao
1105259b007fSCarlos BilbaoSin intervención, la CPU 2 puede percibir los eventos en la CPU 1 en orden
1106259b007fSCarlos Bilbaoaleatorio a efectos prácticos, a pesar de la barrera de escritura emitida
1107259b007fSCarlos Bilbaopor la CPU 1:
1108259b007fSCarlos Bilbao
1109259b007fSCarlos Bilbao	+-------+       :      :                :       :
1110259b007fSCarlos Bilbao	|       |       +------+                +-------+  | Secuencia de
1111259b007fSCarlos Bilbao	|       |------>| B=2  |-----       --->| Y->8  |  | actualizado de
1112259b007fSCarlos Bilbao	|       |  :    +------+     \          +-------+  | percepción en CPU 2
1113259b007fSCarlos Bilbao	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |  V
1114259b007fSCarlos Bilbao	|       |       +------+       |        +-------+
1115259b007fSCarlos Bilbao	|       |   wwwwwwwwwwwwwwww   |        :       :
1116259b007fSCarlos Bilbao	|       |       +------+       |        :       :
1117259b007fSCarlos Bilbao	|       |  :    | C=&B |---    |        :       :       +-------+
1118259b007fSCarlos Bilbao	|       |  :    +------+   \   |        +-------+       |       |
1119259b007fSCarlos Bilbao	|       |------>| D=4  |    ----------->| C->&B |------>|       |
1120259b007fSCarlos Bilbao	|       |       +------+       |        +-------+       |       |
1121259b007fSCarlos Bilbao	+-------+       :      :       |        :       :       |       |
1122259b007fSCarlos Bilbao	                               |        :       :       |       |
1123259b007fSCarlos Bilbao	                               |        :       :       | CPU 2 |
1124259b007fSCarlos Bilbao	                               |        +-------+       |       |
1125259b007fSCarlos Bilbao	    Percepción de B      --->  |        | B->7  |------>|       |
1126259b007fSCarlos Bilbao	    aparentemente incorrecta!  |        +-------+       |       |
1127259b007fSCarlos Bilbao	                               |        :       :       |       |
1128259b007fSCarlos Bilbao	                               |        +-------+       |       |
1129259b007fSCarlos Bilbao	    La carga de X frena --->    \       | X->9  |------>|       |
1130259b007fSCarlos Bilbao	    el mantenimiento de          \      +-------+       |       |
1131259b007fSCarlos Bilbao	    la coherencia de B            ----->| B->2  |       +-------+
1132259b007fSCarlos Bilbao	                                        +-------+
1133259b007fSCarlos Bilbao	                                        :       :
1134259b007fSCarlos Bilbao
1135259b007fSCarlos Bilbao
1136259b007fSCarlos BilbaoEn el ejemplo anterior, la CPU 2 percibe que B es 7, a pesar de la carga de
1137259b007fSCarlos Bilbao*C (que sería B) viniendo después del LOAD de C.
1138259b007fSCarlos Bilbao
1139259b007fSCarlos BilbaoSin embargo, si se colocara una barrera de dependencia de dirección entre
1140259b007fSCarlos Bilbaola carga de C y la carga de *C (es decir: B) en la CPU 2:
1141259b007fSCarlos Bilbao
1142259b007fSCarlos Bilbao	CPU 1			CPU 2
1143259b007fSCarlos Bilbao	=======================	=======================
1144259b007fSCarlos Bilbao		{ B = 7; X = 9; Y = 8; C = &Y }
1145259b007fSCarlos Bilbao	STORE A = 1
1146259b007fSCarlos Bilbao	STORE B = 2
1147259b007fSCarlos Bilbao	<barrera de escritura>
1148259b007fSCarlos Bilbao	STORE C = &B		LOAD X
1149259b007fSCarlos Bilbao	STORE D = 4		LOAD C (consigue &B)
1150259b007fSCarlos Bilbao				<barrera de dependencia de dirección>
1151259b007fSCarlos Bilbao				LOAD *C (reads B)
1152259b007fSCarlos Bilbao
1153259b007fSCarlos Bilbaoentonces ocurrirá lo siguiente:
1154259b007fSCarlos Bilbao
1155259b007fSCarlos Bilbao	+-------+       :      :                :       :
1156259b007fSCarlos Bilbao	|       |       +------+                +-------+
1157259b007fSCarlos Bilbao	|       |------>| B=2  |-----       --->| Y->8  |
1158259b007fSCarlos Bilbao	|       |  :    +------+     \          +-------+
1159259b007fSCarlos Bilbao	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |
1160259b007fSCarlos Bilbao	|       |       +------+       |        +-------+
1161259b007fSCarlos Bilbao	|       |   wwwwwwwwwwwwwwww   |        :       :
1162259b007fSCarlos Bilbao	|       |       +------+       |        :       :
1163259b007fSCarlos Bilbao	|       |  :    | C=&B |---    |        :       :       +-------+
1164259b007fSCarlos Bilbao	|       |  :    +------+   \   |        +-------+       |       |
1165259b007fSCarlos Bilbao	|       |------>| D=4  |    ----------->| C->&B |------>|       |
1166259b007fSCarlos Bilbao	|       |       +------+       |        +-------+       |       |
1167259b007fSCarlos Bilbao	+-------+       :      :       |        :       :       |       |
1168259b007fSCarlos Bilbao	                               |        :       :       |       |
1169259b007fSCarlos Bilbao	                               |        :       :       | CPU 2 |
1170259b007fSCarlos Bilbao	                               |        +-------+       |       |
1171259b007fSCarlos Bilbao	                               |        | X->9  |------>|       |
1172259b007fSCarlos Bilbao	                               |        +-------+       |       |
1173259b007fSCarlos Bilbao	  Se asegura de que      --->   \   aaaaaaaaaaaaaaaaa   |       |
1174259b007fSCarlos Bilbao	  los efectos anteriores al      \      +-------+       |       |
1175259b007fSCarlos Bilbao	  store de C sean percibidos      ----->| B->2  |------>|       |
1176259b007fSCarlos Bilbao	  por los siguientes loads              +-------+       |       |
1177259b007fSCarlos Bilbao	                                        :       :       +-------+
1178259b007fSCarlos Bilbao
1179259b007fSCarlos Bilbao
1180259b007fSCarlos BilbaoY en tercer lugar, una barrera de lectura actúa como un orden parcial sobre
1181259b007fSCarlos Bilbaolas cargas. Considere la siguiente secuencia de eventos:
1182259b007fSCarlos Bilbao
1183259b007fSCarlos Bilbao	CPU 1			CPU 2
1184259b007fSCarlos Bilbao	=======================	=======================
1185259b007fSCarlos Bilbao		{ A = 0, B = 9 }
1186259b007fSCarlos Bilbao	STORE A=1
1187259b007fSCarlos Bilbao	<barrera de escritura>
1188259b007fSCarlos Bilbao	STORE B=2
1189259b007fSCarlos Bilbao				LOAD B
1190259b007fSCarlos Bilbao				LOAD A
1191259b007fSCarlos Bilbao
1192259b007fSCarlos BilbaoSin intervención, la CPU 2 puede elegir percibir los eventos en la CPU 1 en
1193259b007fSCarlos Bilbaoalgún orden aleatorio a efectos prácticos, a pesar de la barrera de
1194259b007fSCarlos Bilbaoescritura emitida por la CPU 1:
1195259b007fSCarlos Bilbao
1196259b007fSCarlos Bilbao	+-------+       :      :                :       :
1197259b007fSCarlos Bilbao	|       |       +------+                +-------+
1198259b007fSCarlos Bilbao	|       |------>| A=1  |------      --->| A->0  |
1199259b007fSCarlos Bilbao	|       |       +------+      \         +-------+
1200259b007fSCarlos Bilbao	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
1201259b007fSCarlos Bilbao	|       |       +------+        |       +-------+
1202259b007fSCarlos Bilbao	|       |------>| B=2  |---     |       :       :
1203259b007fSCarlos Bilbao	|       |       +------+   \    |       :       :       +-------+
1204259b007fSCarlos Bilbao	+-------+       :      :    \   |       +-------+       |       |
1205259b007fSCarlos Bilbao	                             ---------->| B->2  |------>|       |
1206259b007fSCarlos Bilbao	                                |       +-------+       | CPU 2 |
1207259b007fSCarlos Bilbao	                                |       | A->0  |------>|       |
1208259b007fSCarlos Bilbao	                                |       +-------+       |       |
1209259b007fSCarlos Bilbao	                                |       :       :       +-------+
1210259b007fSCarlos Bilbao	                                 \      :       :
1211259b007fSCarlos Bilbao	                                  \     +-------+
1212259b007fSCarlos Bilbao	                                   ---->| A->1  |
1213259b007fSCarlos Bilbao	                                        +-------+
1214259b007fSCarlos Bilbao	                                        :       :
1215259b007fSCarlos Bilbao
1216259b007fSCarlos BilbaoSin embargo, si se colocara una barrera de lectura entre la carga de B y la
1217259b007fSCarlos Bilbaocarga de A en la CPU 2:
1218259b007fSCarlos Bilbao
1219259b007fSCarlos Bilbao	CPU 1			CPU 2
1220259b007fSCarlos Bilbao	=======================	=======================
1221259b007fSCarlos Bilbao		{ A = 0, B = 9 }
1222259b007fSCarlos Bilbao	STORE A=1
1223259b007fSCarlos Bilbao	<barrera de escritura>
1224259b007fSCarlos Bilbao	STORE B=2
1225259b007fSCarlos Bilbao				LOAD B
1226259b007fSCarlos Bilbao				<barrera de lectura>
1227259b007fSCarlos Bilbao				LOAD A
1228259b007fSCarlos Bilbao
1229259b007fSCarlos Bilbaoentonces el orden parcial impuesto por la CPU 1 será percibido
1230259b007fSCarlos Bilbaocorrectamente por la CPU 2:
1231259b007fSCarlos Bilbao
1232259b007fSCarlos Bilbao	+-------+       :      :                :       :
1233259b007fSCarlos Bilbao	|       |       +------+                +-------+
1234259b007fSCarlos Bilbao	|       |------>| A=1  |------      --->| A->0  |
1235259b007fSCarlos Bilbao	|       |       +------+      \         +-------+
1236259b007fSCarlos Bilbao	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
1237259b007fSCarlos Bilbao	|       |       +------+        |       +-------+
1238259b007fSCarlos Bilbao	|       |------>| B=2  |---     |       :       :
1239259b007fSCarlos Bilbao	|       |       +------+   \    |       :       :       +-------+
1240259b007fSCarlos Bilbao	+-------+       :      :    \   |       +-------+       |       |
1241259b007fSCarlos Bilbao	                             ---------->| B->2  |------>|       |
1242259b007fSCarlos Bilbao	                                |       +-------+       | CPU 2 |
1243259b007fSCarlos Bilbao	                                |       :       :       |       |
1244259b007fSCarlos Bilbao	                                |       :       :       |       |
1245259b007fSCarlos Bilbao	  En este punto la barrera ----> \  rrrrrrrrrrrrrrrrr   |       |
1246259b007fSCarlos Bilbao	  de lectura consigue que         \     +-------+       |       |
1247259b007fSCarlos Bilbao	  todos los efectos anteriores     ---->| A->1  |------>|       |
1248259b007fSCarlos Bilbao	  al almacenamiento de B sean           +-------+       |       |
1249259b007fSCarlos Bilbao	  perceptibles por la CPU 2             :       :       +-------+
1250259b007fSCarlos Bilbao
1251259b007fSCarlos Bilbao
1252259b007fSCarlos BilbaoPara ilustrar esto de manera más completa, considere lo que podría pasar si
1253259b007fSCarlos Bilbaoel código contenía una carga de A a cada lado de la barrera de lectura:
1254259b007fSCarlos Bilbao
1255259b007fSCarlos Bilbao	CPU 1			CPU 2
1256259b007fSCarlos Bilbao	=======================	=======================
1257259b007fSCarlos Bilbao		{ A = 0, B = 9 }
1258259b007fSCarlos Bilbao	STORE A=1
1259259b007fSCarlos Bilbao	<barrera de escritura>
1260259b007fSCarlos Bilbao	STORE B=2
1261259b007fSCarlos Bilbao				LOAD B
1262259b007fSCarlos Bilbao				LOAD A [primer load de A]
1263259b007fSCarlos Bilbao				<rbarrera de lectura>
1264259b007fSCarlos Bilbao				LOAD A [segundo load de A]
1265259b007fSCarlos Bilbao
1266259b007fSCarlos BilbaoAunque las dos cargas de A ocurren después de la carga de B, ambas pueden
1267259b007fSCarlos Bilbaoobtener diferentes valores:
1268259b007fSCarlos Bilbao
1269259b007fSCarlos Bilbao	+-------+       :      :                :       :
1270259b007fSCarlos Bilbao	|       |       +------+                +-------+
1271259b007fSCarlos Bilbao	|       |------>| A=1  |------      --->| A->0  |
1272259b007fSCarlos Bilbao	|       |       +------+      \         +-------+
1273259b007fSCarlos Bilbao	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
1274259b007fSCarlos Bilbao	|       |       +------+        |       +-------+
1275259b007fSCarlos Bilbao	|       |------>| B=2  |---     |       :       :
1276259b007fSCarlos Bilbao	|       |       +------+   \    |       :       :       +-------+
1277259b007fSCarlos Bilbao	+-------+       :      :    \   |       +-------+       |       |
1278259b007fSCarlos Bilbao	                             ---------->| B->2  |------>|       |
1279259b007fSCarlos Bilbao	                                |       +-------+       | CPU 2 |
1280259b007fSCarlos Bilbao	                                |       :       :       |       |
1281259b007fSCarlos Bilbao	                                |       :       :       |       |
1282259b007fSCarlos Bilbao	                                |       +-------+       |       |
1283259b007fSCarlos Bilbao	                                |       | A->0  |------>| 1st   |
1284259b007fSCarlos Bilbao	                                |       +-------+       |       |
1285259b007fSCarlos Bilbao	  En este punto la barrera ----> \  rrrrrrrrrrrrrrrrr   |       |
1286259b007fSCarlos Bilbao	  de lectura consigue que         \     +-------+       |       |
1287259b007fSCarlos Bilbao	  todos los efectos anteriores     ---->| A->1  |------>|       |
1288259b007fSCarlos Bilbao	  al almacenamiento de B sean           +-------+       |       |
1289259b007fSCarlos Bilbao	  perceptibles por la CPU 2             :       :       +-------+
1290259b007fSCarlos Bilbao
1291259b007fSCarlos BilbaoPero puede ser que la actualización a A desde la CPU 1 se vuelva
1292259b007fSCarlos Bilbaoperceptible para la CPU 2 antes de que la barrera de lectura se complete de
1293259b007fSCarlos Bilbaotodos modos:
1294259b007fSCarlos Bilbao
1295259b007fSCarlos Bilbao	+-------+       :      :                :       :
1296259b007fSCarlos Bilbao	|       |       +------+                +-------+
1297259b007fSCarlos Bilbao	|       |------>| A=1  |------      --->| A->0  |
1298259b007fSCarlos Bilbao	|       |       +------+      \         +-------+
1299259b007fSCarlos Bilbao	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |
1300259b007fSCarlos Bilbao	|       |       +------+        |       +-------+
1301259b007fSCarlos Bilbao	|       |------>| B=2  |---     |       :       :
1302259b007fSCarlos Bilbao	|       |       +------+   \    |       :       :       +-------+
1303259b007fSCarlos Bilbao	+-------+       :      :    \   |       +-------+       |       |
1304259b007fSCarlos Bilbao	                             ---------->| B->2  |------>|       |
1305259b007fSCarlos Bilbao	                                |       +-------+       | CPU 2 |
1306259b007fSCarlos Bilbao	                                |       :       :       |       |
1307259b007fSCarlos Bilbao	                                 \      :       :       |       |
1308259b007fSCarlos Bilbao	                                  \     +-------+       |       |
1309259b007fSCarlos Bilbao	                                   ---->| A->1  |------>| 1st   |
1310259b007fSCarlos Bilbao	                                        +-------+       |       |
1311259b007fSCarlos Bilbao	                                    rrrrrrrrrrrrrrrrr   |       |
1312259b007fSCarlos Bilbao	                                        +-------+       |       |
1313259b007fSCarlos Bilbao	                                        | A->1  |------>| 2nd   |
1314259b007fSCarlos Bilbao	                                        +-------+       |       |
1315259b007fSCarlos Bilbao	                                        :       :       +-------+
1316259b007fSCarlos Bilbao
1317259b007fSCarlos BilbaoLa garantía es que la segunda carga siempre dará como resultado A == 1 si
1318259b007fSCarlos Bilbaola carga de B resultó en B == 2. No existe tal garantía para la primera
1319259b007fSCarlos Bilbaocarga de A; esto puede dar como resultado A == 0 o A == 1.
1320259b007fSCarlos Bilbao
1321259b007fSCarlos Bilbao
1322259b007fSCarlos BilbaoBARRERAS DE MEMORIA DE LECTURA FRENTE A ESPECULACIÓN DE CARGA
1323259b007fSCarlos Bilbao-------------------------------------------------------------
1324259b007fSCarlos Bilbao
1325259b007fSCarlos BilbaoMuchas CPU especulan con las cargas: es decir, ven que necesitarán cargar
1326259b007fSCarlos Bilbaoun elemento de la memoria, y encuentran un momento en el que no están
1327259b007fSCarlos Bilbaousando el bus para ningún otra carga, y también en la carga por adelantado,
1328259b007fSCarlos Bilbaoaunque en realidad no lo hayan llegado a ese punto en el flujo de ejecución
1329259b007fSCarlos Bilbaode instrucciones todavía. Esto permite que la instrucción de carga real
1330259b007fSCarlos Bilbaopotencialmente complete de inmediato, porque la CPU ya tiene el valor a
1331259b007fSCarlos Bilbaomano.
1332259b007fSCarlos Bilbao
1333259b007fSCarlos BilbaoPuede resultar que la CPU en realidad no necesitara el valor, tal vez
1334259b007fSCarlos Bilbaoporque una condición eludió la carga, en cuyo caso puede descartar el valor
1335259b007fSCarlos Bilbaoo simplemente almacenar en caché para su uso posterior.
1336259b007fSCarlos Bilbao
1337259b007fSCarlos BilbaoConsidere:
1338259b007fSCarlos Bilbao
1339259b007fSCarlos Bilbao	CPU 1			CPU 2
1340259b007fSCarlos Bilbao	=======================	=======================
1341259b007fSCarlos Bilbao				LOAD B
1342259b007fSCarlos Bilbao				DIVIDE		} Instrucciones de división
1343259b007fSCarlos Bilbao				DIVIDE		} tardan mucho en terminar
1344259b007fSCarlos Bilbao				LOAD A
1345259b007fSCarlos Bilbao
1346259b007fSCarlos Bilbaodonde DIVIDE es DIVIDIR. Que podría aparecer como esto:
1347259b007fSCarlos Bilbao
1348259b007fSCarlos Bilbao	                                        :       :       +-------+
1349259b007fSCarlos Bilbao	                                        +-------+       |       |
1350259b007fSCarlos Bilbao	                                    --->| B->2  |------>|       |
1351259b007fSCarlos Bilbao	                                        +-------+       | CPU 2 |
1352259b007fSCarlos Bilbao	                                        :       :DIVIDE |       |
1353259b007fSCarlos Bilbao	                                        +-------+       |       |
1354259b007fSCarlos Bilbao	La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |
1355259b007fSCarlos Bilbao	especula sobre el LOAD de A             +-------+   ~   |       |
1356259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1357259b007fSCarlos Bilbao	                                        :       :DIVIDE |       |
1358259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1359259b007fSCarlos Bilbao	Una vez completadas las divisiones  --> :       :   ~-->|       |
1360259b007fSCarlos Bilbao	la CPU puede realizar el                :       :       |       |
1361259b007fSCarlos Bilbao	LOAD con efecto inmediato               :       :       +-------+
1362259b007fSCarlos Bilbao
1363259b007fSCarlos Bilbao
1364259b007fSCarlos BilbaoColocando una barrera de lectura o una barrera de dependencia de dirección
1365259b007fSCarlos Bilbaojusto antes de la segundo carga:
1366259b007fSCarlos Bilbao
1367259b007fSCarlos Bilbao
1368259b007fSCarlos Bilbao
1369259b007fSCarlos Bilbao	CPU 1			CPU 2
1370259b007fSCarlos Bilbao	=======================	=======================
1371259b007fSCarlos Bilbao				LOAD B
1372259b007fSCarlos Bilbao				DIVIDE
1373259b007fSCarlos Bilbao				DIVIDE
1374259b007fSCarlos Bilbao				<rbarrera de lectura>
1375259b007fSCarlos Bilbao				LOAD A
1376259b007fSCarlos Bilbao
1377259b007fSCarlos Bilbaoobligará a reconsiderar cualquier valor obtenido especulativamente en una
1378259b007fSCarlos Bilbaomedida dependiente del tipo de barrera utilizada. Si no se hizo ningún
1379259b007fSCarlos Bilbaocambio en la ubicación de memoria especulada, entonces el valor especulado
1380259b007fSCarlos Bilbaosolo se usará:
1381259b007fSCarlos Bilbao
1382259b007fSCarlos Bilbao	                                        :       :       +-------+
1383259b007fSCarlos Bilbao	                                        +-------+       |       |
1384259b007fSCarlos Bilbao	                                    --->| B->2  |------>|       |
1385259b007fSCarlos Bilbao	                                        +-------+       | CPU 2 |
1386259b007fSCarlos Bilbao	                                        :       :DIVIDE |       |
1387259b007fSCarlos Bilbao	                                        +-------+       |       |
1388259b007fSCarlos Bilbao  La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |
1389259b007fSCarlos Bilbao  especula sobre el LOAD de A             +-------+   ~   |       |
1390259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1391259b007fSCarlos Bilbao	                                        :       :DIVIDE |       |
1392259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1393259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1394259b007fSCarlos Bilbao	                                    rrrrrrrrrrrrrrrr~   |       |
1395259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1396259b007fSCarlos Bilbao	                                        :       :   ~-->|       |
1397259b007fSCarlos Bilbao	                                        :       :       |       |
1398259b007fSCarlos Bilbao	                                        :       :       +-------+
1399259b007fSCarlos Bilbao
1400259b007fSCarlos Bilbao
1401259b007fSCarlos Bilbaopero si había una actualización o una invalidación de otra CPU pendiente,
1402259b007fSCarlos Bilbaoentonces la especulación será cancelada y el valor recargado:
1403259b007fSCarlos Bilbao
1404259b007fSCarlos Bilbao	                                        :       :       +-------+
1405259b007fSCarlos Bilbao	                                        +-------+       |       |
1406259b007fSCarlos Bilbao	                                    --->| B->2  |------>|       |
1407259b007fSCarlos Bilbao	                                        +-------+       | CPU 2 |
1408259b007fSCarlos Bilbao	                                        :       :DIVIDE |       |
1409259b007fSCarlos Bilbao	                                        +-------+       |       |
1410259b007fSCarlos Bilbao  La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |
1411259b007fSCarlos Bilbao  especula sobre el LOAD de A             +-------+   ~   |       |
1412259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1413259b007fSCarlos Bilbao	                                        :       :DIVIDE |       |
1414259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1415259b007fSCarlos Bilbao	                                        :       :   ~   |       |
1416259b007fSCarlos Bilbao	                                    rrrrrrrrrrrrrrrrr   |       |
1417259b007fSCarlos Bilbao	                                        +-------+       |       |
1418259b007fSCarlos Bilbao	La especulación es descartada --->  --->| A->1  |------>|       |
1419259b007fSCarlos Bilbao	y un valor actualizado                  +-------+       |       |
1420259b007fSCarlos Bilbao	es conseguido                           :       :       +-------+
1421259b007fSCarlos Bilbao
1422259b007fSCarlos BilbaoATOMICIDAD MULTICOPIA
1423259b007fSCarlos Bilbao---------------------
1424259b007fSCarlos Bilbao
1425259b007fSCarlos BilbaoLa atomicidad multicopia es una noción profundamente intuitiva sobre el
1426259b007fSCarlos Bilbaoorden que no es siempre proporcionada por los sistemas informáticos reales,
1427259b007fSCarlos Bilbaoa saber, que un determinada store se vuelve visible al mismo tiempo para
1428259b007fSCarlos Bilbaotodos las CPU o, alternativamente, que todas las CPU acuerdan el orden en
1429259b007fSCarlos Bilbaoque todos los stores se vuelven visibles. Sin embargo, el soporte para
1430259b007fSCarlos Bilbaoatomicidad multicopia completa descartaría valiosas optimizaciones
1431259b007fSCarlos Bilbaohardware, por lo que una versión más débil conocida como ``otra atomicidad
1432259b007fSCarlos Bilbaomulticopia'' en cambio, solo garantiza que un store dado se vuelva visible
1433259b007fSCarlos Bilbaoal mismo tiempo en todas las -otras- CPUs. El resto de este documento
1434259b007fSCarlos Bilbaodiscute esta versión más débil, pero por brevedad lo llamaremos simplemente
1435259b007fSCarlos Bilbao``atomicidad multicopia''.
1436259b007fSCarlos Bilbao
1437259b007fSCarlos BilbaoEl siguiente ejemplo demuestra la atomicidad multicopia:
1438259b007fSCarlos Bilbao
1439259b007fSCarlos Bilbao	CPU 1			CPU 2			CPU 3
1440259b007fSCarlos Bilbao	=======================	=======================	=======================
1441259b007fSCarlos Bilbao		{ X = 0, Y = 0 }
1442259b007fSCarlos Bilbao	STORE X=1		r1=LOAD X (reads 1)	LOAD Y (reads 1)
1443259b007fSCarlos Bilbao				<barrera general>	<barrera de lectura>
1444259b007fSCarlos Bilbao				STORE Y=r1		LOAD X
1445259b007fSCarlos Bilbao
1446259b007fSCarlos BilbaoSuponga que la carga de la CPU 2 desde X devuelve 1, que luego almacena en
1447259b007fSCarlos BilbaoY, y la carga de la CPU 3 desde Y devuelve 1. Esto indica que el store de
1448259b007fSCarlos Bilbaola CPU 1 a X precede a la carga de la CPU 2 desde X y el store de esa CPU 2
1449259b007fSCarlos Bilbaoa Y precede la carga de la CPU 3 desde Y. Además, las barreras de memoria
1450259b007fSCarlos Bilbaogarantizan que la CPU 2 ejecuta su carga antes que su almacenamiento, y la
1451259b007fSCarlos BilbaoCPU 3 carga desde Y antes de cargar desde X. La pregunta entonces es
1452259b007fSCarlos Bilbao"¿Puede la carga de la CPU 3 desde X devolver 0?"
1453259b007fSCarlos Bilbao
1454259b007fSCarlos BilbaoDebido a que la carga de la CPU 3 desde X en cierto sentido viene después
1455259b007fSCarlos Bilbaode la carga de la CPU 2, es natural esperar que la carga de la CPU 3 desde
1456259b007fSCarlos BilbaoX deba devolver 1. Esta expectativa se deriva de la atomicidad multicopia:
1457259b007fSCarlos Bilbaosi una carga que se ejecuta en la CPU B sigue una carga de la misma
1458259b007fSCarlos Bilbaovariable que se ejecuta en la CPU A (y la CPU A no almacenó originalmente
1459259b007fSCarlos Bilbaoel valor que leyó), entonces en sistemas atómicos multicopia, la carga de
1460259b007fSCarlos Bilbaola CPU B debe devolver el mismo valor que hizo la carga de la CPU A o algún
1461259b007fSCarlos Bilbaovalor posterior. Sin embargo, el kernel Linux no requiere que los sistemas
1462259b007fSCarlos Bilbaosean atómicos multicopia.
1463259b007fSCarlos Bilbao
1464259b007fSCarlos BilbaoEl uso de una barrera de memoria general en el ejemplo anterior compensa
1465259b007fSCarlos Bilbaocualquier falta de atomicidad multicopia. En el ejemplo, si la carga de la
1466259b007fSCarlos BilbaoCPU 2 de X devuelve 1 y la carga de la CPU 3 de Y devuelve 1, entonces la
1467259b007fSCarlos Bilbaocarga de la CPU 3 desde X debe de hecho también devolver 1.
1468259b007fSCarlos Bilbao
1469259b007fSCarlos BilbaoSin embargo, las dependencias, las barreras de lectura y las barreras de
1470259b007fSCarlos Bilbaoescritura no siempre son capaces de compensar la atomicidad no multicopia.
1471259b007fSCarlos BilbaoPor ejemplo, supongamos que la barrera general de la CPU 2 se elimina del
1472259b007fSCarlos Bilbaoejemplo anterior, dejando solo la dependencia de datos que se muestra a
1473259b007fSCarlos Bilbaocontinuación:
1474259b007fSCarlos Bilbao
1475259b007fSCarlos Bilbao	CPU 1			CPU 2			CPU 3
1476259b007fSCarlos Bilbao	=======================	=======================	=======================
1477259b007fSCarlos Bilbao		{ X = 0, Y = 0 }
1478259b007fSCarlos Bilbao	STORE X=1		r1=LOAD X (escribe 1)	LOAD Y (lee 1)
1479259b007fSCarlos Bilbao				<dependencia de datos>	<barrera de lectura>
1480259b007fSCarlos Bilbao				STORE Y=r1		LOAD X (lee 0)
1481259b007fSCarlos Bilbao
1482259b007fSCarlos BilbaoEsta sustitución permite que la atomicidad no multicopia se desenfrene: en
1483259b007fSCarlos Bilbaoeste ejemplo, es perfectamente legal que la carga de la CPU 2 desde X
1484259b007fSCarlos Bilbaodevuelva 1, la carga de la CPU 3 desde Y devuelva 1, y su carga desde X
1485259b007fSCarlos Bilbaotenga valor 0.
1486259b007fSCarlos Bilbao
1487259b007fSCarlos BilbaoEl punto clave es que aunque la dependencia de datos de la CPU 2 ordena su
1488259b007fSCarlos Bilbaocarga y store, no garantiza ordenar el store de la CPU 1. De forma que, si
1489259b007fSCarlos Bilbaoeste ejemplo se ejecuta en un sistema atómico no multicopia donde las CPU 1
1490259b007fSCarlos Bilbaoy 2 comparten un buffer de almacenamiento o un nivel de caché, la CPU 2
1491259b007fSCarlos Bilbaopodría tener acceso anticipado de escritura a CPU 1. Por lo tanto, se
1492259b007fSCarlos Bilbaorequieren barreras generales para garantizar que todas las CPU acurden el
1493259b007fSCarlos Bilbaoorden combinado de accesos múltiples.
1494259b007fSCarlos Bilbao
1495259b007fSCarlos BilbaoLas barreras generales pueden compensar no solo la atomicidad no
1496259b007fSCarlos Bilbaomulticopia, pero también pueden generar orden adicional que puede asegurar
1497259b007fSCarlos Bilbaoque -todas- las CPU percibirán el mismo orden de -todas- las operaciones.
1498259b007fSCarlos BilbaoPor el contrario, una cadena de parejas de liberación-adquisición no
1499259b007fSCarlos Bilbaoproporciona este orden adicional, lo que significa que solo se garantiza
1500259b007fSCarlos Bilbaoque las CPU de la cadena estén de acuerdo en el orden combinado de los
1501259b007fSCarlos Bilbaoaccesos. Por ejemplo, cambiando a código C en deferencia al fantasma de
1502259b007fSCarlos BilbaoHerman Hollerith:
1503259b007fSCarlos Bilbao
1504259b007fSCarlos Bilbao	int u, v, x, y, z;
1505259b007fSCarlos Bilbao
1506259b007fSCarlos Bilbao	void cpu0(void)
1507259b007fSCarlos Bilbao	{
1508259b007fSCarlos Bilbao		r0 = smp_load_acquire(&x);
1509259b007fSCarlos Bilbao		WRITE_ONCE(u, 1);
1510259b007fSCarlos Bilbao		smp_store_release(&y, 1);
1511259b007fSCarlos Bilbao	}
1512259b007fSCarlos Bilbao
1513259b007fSCarlos Bilbao	void cpu1(void)
1514259b007fSCarlos Bilbao	{
1515259b007fSCarlos Bilbao		r1 = smp_load_acquire(&y);
1516259b007fSCarlos Bilbao		r4 = READ_ONCE(v);
1517259b007fSCarlos Bilbao		r5 = READ_ONCE(u);
1518259b007fSCarlos Bilbao		smp_store_release(&z, 1);
1519259b007fSCarlos Bilbao	}
1520259b007fSCarlos Bilbao
1521259b007fSCarlos Bilbao	void cpu2(void)
1522259b007fSCarlos Bilbao	{
1523259b007fSCarlos Bilbao		r2 = smp_load_acquire(&z);
1524259b007fSCarlos Bilbao		smp_store_release(&x, 1);
1525259b007fSCarlos Bilbao	}
1526259b007fSCarlos Bilbao
1527259b007fSCarlos Bilbao	void cpu3(void)
1528259b007fSCarlos Bilbao	{
1529259b007fSCarlos Bilbao		WRITE_ONCE(v, 1);
1530259b007fSCarlos Bilbao		smp_mb();
1531259b007fSCarlos Bilbao		r3 = READ_ONCE(u);
1532259b007fSCarlos Bilbao	}
1533259b007fSCarlos Bilbao
1534259b007fSCarlos BilbaoDado que cpu0(), cpu1() y cpu2() participan en una cadena de parejas
1535259b007fSCarlos Bilbaosmp_store_release()/smp_load_acquire(), el siguiente resultado estaría
1536259b007fSCarlos Bilbaoprohibido:
1537259b007fSCarlos Bilbao
1538259b007fSCarlos Bilbao	r0 == 1 && r1 == 1 && r2 == 1
1539259b007fSCarlos Bilbao
1540259b007fSCarlos BilbaoAdemás, debido a la relación liberación-adquisición entre cpu0() y cpu1(),
1541259b007fSCarlos Bilbaocpu1() debe ver las escrituras de cpu0(), de modo que el siguiente
1542259b007fSCarlos Bilbaoresultado estaría prohibido:
1543259b007fSCarlos Bilbao
1544259b007fSCarlos Bilbao	r1 == 1 && r5 == 0
1545259b007fSCarlos Bilbao
1546259b007fSCarlos BilbaoSin embargo, el orden proporcionado por una cadena de
1547259b007fSCarlos Bilbaoliberación-adquisición es local a las CPU que participan en esa cadena y no
1548259b007fSCarlos Bilbaose aplica a cpu3(), al menos aparte de los stores. Por lo tanto, es posible
1549259b007fSCarlos Bilbaoel siguiente resultado:
1550259b007fSCarlos Bilbao
1551259b007fSCarlos Bilbao	r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0
1552259b007fSCarlos Bilbao
1553259b007fSCarlos BilbaoPor otro lado, también el siguiente resultado es posible:
1554259b007fSCarlos Bilbao
1555259b007fSCarlos Bilbao	r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 && r5 == 1
1556259b007fSCarlos Bilbao
1557259b007fSCarlos BilbaoAunque cpu0(), cpu1() y cpu2() verán sus respectivas lecturas y escrituras
1558259b007fSCarlos Bilbaoen orden, las CPU que no participan en la cadena de liberación-adquisición
1559259b007fSCarlos Bilbaopueden estar en desacuerdo con el orden. Este desacuerdo se debe al hecho
1560259b007fSCarlos Bilbaode que las instrucciones de barrera de memoria débiles utilizadas para
1561259b007fSCarlos Bilbaoimplementar smp_load_acquire() y smp_store_release() no son necesarios para
1562259b007fSCarlos Bilbaoordenar stores anteriores contra cargas posteriores en todos los casos.
1563259b007fSCarlos BilbaoEsto significa que cpu3() puede ver el store de cpu0() suceder -después- de
1564259b007fSCarlos Bilbaola carga de cpu1() desde v, aunque tanto cpu0() como cpu1() están de
1565259b007fSCarlos Bilbaoacuerdo en que estas dos operaciones ocurrieron en el orden previsto.
1566259b007fSCarlos Bilbao
1567259b007fSCarlos BilbaoSin embargo, tenga en cuenta que smp_load_acquire() no es mágico. En
1568259b007fSCarlos Bilbaoparticular, simplemente lee de su argumento en orden. Es decir, -no-
1569259b007fSCarlos Bilbaoasegura que se leerá cualquier valor en particular. Por lo tanto, los
1570259b007fSCarlos Bilbaosiguiente resultados son posibles:
1571259b007fSCarlos Bilbao
1572259b007fSCarlos Bilbao	r0 == 0 && r1 == 0 && r2 == 0 && r5 == 0
1573259b007fSCarlos Bilbao
1574259b007fSCarlos BilbaoTenga en cuenta que este resultado puede ocurrir incluso en un mítico
1575259b007fSCarlos Bilbaosistema, consistente en secuencia, donde nunca se reordena nada.
1576259b007fSCarlos Bilbao
1577259b007fSCarlos BilbaoPara reiterar, si su código requiere un orden completo de todas las
1578259b007fSCarlos Bilbaooperaciones, utilice barreras generales en todo momento.
1579259b007fSCarlos Bilbao
1580259b007fSCarlos Bilbao
1581259b007fSCarlos Bilbao==============================
1582259b007fSCarlos BilbaoBARRERAS EXPLÍCITAS DEL KERNEL
1583259b007fSCarlos Bilbao==============================
1584259b007fSCarlos Bilbao
1585259b007fSCarlos BilbaoEl kernel Linux tiene una variedad de diferentes barreras que actúan a
1586259b007fSCarlos Bilbaodiferentes niveles:
1587259b007fSCarlos Bilbao
1588259b007fSCarlos Bilbao  (*) Barrera del compilador.
1589259b007fSCarlos Bilbao
1590259b007fSCarlos Bilbao  (*) Barreras de memoria de la CPU.
1591259b007fSCarlos Bilbao
1592259b007fSCarlos Bilbao
1593259b007fSCarlos BilbaoBARRERA DEL COMPILADOR
1594259b007fSCarlos Bilbao-----------------------
1595259b007fSCarlos Bilbao
1596259b007fSCarlos BilbaoEl kernel de Linux tiene una función de barrera del compilador explícita
1597259b007fSCarlos Bilbaoque evita que el el compilador mueva los accesos a la memoria de cualquier
1598259b007fSCarlos Bilbaolado al otro:
1599259b007fSCarlos Bilbao
1600259b007fSCarlos Bilbao	barrier();
1601259b007fSCarlos Bilbao
1602259b007fSCarlos BilbaoEsta es una barrera general: no hay variantes de barrier() para casos de
1603259b007fSCarlos Bilbaolectura-lectura o escritura-escritura. Sin embargo, READ_ONCE() y
1604259b007fSCarlos BilbaoWRITE_ONCE() pueden ser considerado como formas débiles de barrier() que
1605259b007fSCarlos Bilbaoafectan solo específicos accesos marcados por READ_ONCE() o WRITE_ONCE().
1606259b007fSCarlos Bilbao
1607259b007fSCarlos BilbaoLa función barrier() produce los siguientes efectos:
1608259b007fSCarlos Bilbao
1609259b007fSCarlos Bilbao (*) Evita que el compilador reordene los accesos tras barrier() para
1610259b007fSCarlos Bilbao     preceder a cualquier acceso que preceda a barrier(). Un ejemplo de uso
1611259b007fSCarlos Bilbao     de esta propiedad es facilitar la comunicación entre código del
1612259b007fSCarlos Bilbao     interrupt-handler (encargo de gestionar interrupciones) y el código
1613259b007fSCarlos Bilbao     que fue interrumpido.
1614259b007fSCarlos Bilbao
1615259b007fSCarlos Bilbao (*) Dentro de un bucle ("loop"), obliga al compilador a cargar las
1616259b007fSCarlos Bilbao     variables utilizadas en ese loop condicional en cada paso a través de
1617259b007fSCarlos Bilbao     ese loop.
1618259b007fSCarlos Bilbao
1619259b007fSCarlos BilbaoLas funciones READ_ONCE() y WRITE_ONCE() pueden evitar cualquier cantidad
1620259b007fSCarlos Bilbaode optimizaciones que, si bien son perfectamente seguras en código de un
1621259b007fSCarlos Bilbaosolo subproceso, pueden resultar fatales en código concurrente. Aquí hay
1622259b007fSCarlos Bilbaoalgunos ejemplos de tal tipo de optimizaciones:
1623259b007fSCarlos Bilbao
1624259b007fSCarlos Bilbao(*) El compilador está en su derecho de reordenar cargas y stores de la
1625259b007fSCarlos Bilbao    misma variable, y en algunos casos, la CPU está dentro de su
1626259b007fSCarlos Bilbao    derecho de reordenar cargas a la misma variable. Esto significa que
1627259b007fSCarlos Bilbao    el siguiente código:
1628259b007fSCarlos Bilbao
1629259b007fSCarlos Bilbao a[0] = x;
1630259b007fSCarlos Bilbao a[1] = x;
1631259b007fSCarlos Bilbao
1632259b007fSCarlos Bilbao     Podría resultar en un valor más antiguo de x almacenado en a[1] que en
1633259b007fSCarlos Bilbao     a[0]. Evite que tanto el compilador como la CPU hagan esto de la
1634259b007fSCarlos Bilbao     siguiente manera:
1635259b007fSCarlos Bilbao
1636259b007fSCarlos Bilbao	a[0] = READ_ONCE(x);
1637259b007fSCarlos Bilbao	a[1] = READ_ONCE(x);
1638259b007fSCarlos Bilbao
1639259b007fSCarlos Bilbao     En resumen, READ_ONCE() y WRITE_ONCE() proporcionan coherencia de
1640259b007fSCarlos Bilbao     caché para accesos desde múltiples CPUs a una sola variable.
1641259b007fSCarlos Bilbao
1642259b007fSCarlos Bilbao     (*) El compilador tiene derecho a juntar cargas sucesivas de la misma
1643259b007fSCarlos Bilbao         variable. Tal fusión puede hacer que el compilador "optimice" el
1644259b007fSCarlos Bilbao         siguiente código:
1645259b007fSCarlos Bilbao
1646259b007fSCarlos Bilbao    	while (tmp = a)
1647259b007fSCarlos Bilbao    		hacer_algo_con(tmp);
1648259b007fSCarlos Bilbao
1649259b007fSCarlos Bilbao        en el siguiente código, que, aunque en cierto sentido es legítimo
1650259b007fSCarlos Bilbao        para un código de un solo subproceso, es casi seguro que no es lo
1651259b007fSCarlos Bilbao        que el desarrollador pretendía:
1652259b007fSCarlos Bilbao
1653259b007fSCarlos Bilbao   	if (tmp = a)
1654259b007fSCarlos Bilbao   		for (;;)
1655259b007fSCarlos Bilbao   			hacer_algo_con(tmp);
1656259b007fSCarlos Bilbao
1657259b007fSCarlos Bilbao        Use READ_ONCE() para evitar que el compilador le haga esto:
1658259b007fSCarlos Bilbao
1659259b007fSCarlos Bilbao   	while (tmp = READ_ONCE(a))
1660259b007fSCarlos Bilbao   		hacer_algo_con(tmp);
1661259b007fSCarlos Bilbao
1662259b007fSCarlos Bilbao (*) El compilador tiene derecho a recargar una variable, por ejemplo,
1663259b007fSCarlos Bilbao    en los casos en que la alta presión de los registros impida que el
1664259b007fSCarlos Bilbao    compilador mantenga todos los datos de interés en registros. El
1665259b007fSCarlos Bilbao    compilador podría por lo tanto, optimizar la variable 'tmp' de nuestro
1666259b007fSCarlos Bilbao    ejemplo anterior:
1667259b007fSCarlos Bilbao
1668259b007fSCarlos Bilbao	while (tmp = a)
1669259b007fSCarlos Bilbao		hacer_algo_con(tmp);
1670259b007fSCarlos Bilbao
1671259b007fSCarlos Bilbao     Esto podría resultar en el siguiente código, que es perfectamente
1672259b007fSCarlos Bilbao     seguro en código de subproceso único, pero puede ser fatal en código
1673259b007fSCarlos Bilbao     concurrente:
1674259b007fSCarlos Bilbao
1675259b007fSCarlos Bilbao	while (a)
1676259b007fSCarlos Bilbao		hacer_algo_con(a);
1677259b007fSCarlos Bilbao
1678259b007fSCarlos Bilbao    Por ejemplo, la versión optimizada de este código podría resultar en
1679259b007fSCarlos Bilbao    pasar un cero a hacer_algo_con() en el caso de que la variable a sea
1680259b007fSCarlos Bilbao    modificada por alguna otra CPU, entre la instrucción "while" y la
1681259b007fSCarlos Bilbao    llamada a hacer_algo_con().
1682259b007fSCarlos Bilbao
1683259b007fSCarlos Bilbao    De nuevo, use READ_ONCE() para evitar que el compilador haga esto:
1684259b007fSCarlos Bilbao
1685259b007fSCarlos Bilbao	while (tmp = READ_ONCE(a))
1686259b007fSCarlos Bilbao		hacer_algo_con(tmp);
1687259b007fSCarlos Bilbao
1688259b007fSCarlos Bilbao     Tenga en cuenta que si el compilador se queda sin registros, podría
1689259b007fSCarlos Bilbao     guardar tmp en la pila ("stack"). El overhead (coste en eficiencia) de
1690259b007fSCarlos Bilbao     este guardado y posterior restauración es por lo que los compiladores
1691259b007fSCarlos Bilbao     recargan las variables. Hacerlo es perfectamente seguro para código de
1692259b007fSCarlos Bilbao     subproceso único, por lo que debe informar al compilador sobre los
1693259b007fSCarlos Bilbao     casos donde no sea seguro.
1694259b007fSCarlos Bilbao
1695259b007fSCarlos Bilbao (*) El compilador está en su derecho de omitir una carga por completo si
1696259b007fSCarlos Bilbao     sabe cual será su valor. Por ejemplo, si el compilador puede probar
1697259b007fSCarlos Bilbao     que el valor de la variable 'a' siempre es cero, puede optimizar este
1698259b007fSCarlos Bilbao     código:
1699259b007fSCarlos Bilbao
1700259b007fSCarlos Bilbao	while (tmp = a)
1701259b007fSCarlos Bilbao		hacer_algo_con(tmp);
1702259b007fSCarlos Bilbao
1703259b007fSCarlos Bilbao     En esto:
1704259b007fSCarlos Bilbao
1705259b007fSCarlos Bilbao	do { } while (0);
1706259b007fSCarlos Bilbao
1707259b007fSCarlos Bilbao     Esta transformación es una victoria para un código de un solo
1708259b007fSCarlos Bilbao     subproceso, porque se deshace de una carga y un branch. El problema es
1709259b007fSCarlos Bilbao     que el compilador llevará a cabo su prueba asumiendo que la CPU actual
1710259b007fSCarlos Bilbao     es la única actualizando la variable 'a'. Si la variable 'a' es
1711259b007fSCarlos Bilbao     compartida, entonces la prueba del compilador será errónea. Use
1712259b007fSCarlos Bilbao     READ_ONCE() para decirle al compilador que no sabe tanto como cree:
1713259b007fSCarlos Bilbao
1714259b007fSCarlos Bilbao	while (tmp = READ_ONCE(a))
1715259b007fSCarlos Bilbao		hacer_algo_con(tmp);
1716259b007fSCarlos Bilbao
1717259b007fSCarlos Bilbao     Pero, por favor, tenga en cuenta que el compilador también está
1718259b007fSCarlos Bilbao     observando de cerca lo que usted hace con el valor después de
1719259b007fSCarlos Bilbao     READ_ONCE(). Por ejemplo, suponga que Ud. hace lo siguiente y MAX es
1720259b007fSCarlos Bilbao     una macro de preprocesador con el valor 1:
1721259b007fSCarlos Bilbao
1722259b007fSCarlos Bilbao	while ((tmp = READ_ONCE(a)) % MAX)
1723259b007fSCarlos Bilbao		hacer_algo_con(tmp);
1724259b007fSCarlos Bilbao
1725259b007fSCarlos Bilbao     Entonces el compilador sabe que el resultado del operador "%" aplicado
1726259b007fSCarlos Bilbao     a MAX siempre será cero, nuevamente permitiendo que el compilador
1727259b007fSCarlos Bilbao     optimice el código hasta su casi inexistencia. (Aún se cargará desde
1728259b007fSCarlos Bilbao     la variable 'a'.)
1729259b007fSCarlos Bilbao
1730259b007fSCarlos Bilbao (*) De manera similar, el compilador tiene derecho a omitir un store por
1731259b007fSCarlos Bilbao     completo si sabe que la variable ya tiene el valor almacenado.
1732259b007fSCarlos Bilbao     Nuevamente, el compilador asume que la CPU actual es la única que
1733259b007fSCarlos Bilbao     almacena la variable, lo que puede hacer que el compilador haga
1734259b007fSCarlos Bilbao     algo incorrecto para las variables compartidas. Por ejemplo, suponga
1735259b007fSCarlos Bilbao     que tiene lo siguiente:
1736259b007fSCarlos Bilbao
1737259b007fSCarlos Bilbao	a = 0;
1738259b007fSCarlos Bilbao	... Código que no almacena la variable a ...
1739259b007fSCarlos Bilbao	a = 0;
1740259b007fSCarlos Bilbao
1741259b007fSCarlos Bilbao     El compilador observa que el valor de la variable 'a' ya es cero, por
1742259b007fSCarlos Bilbao     lo que bien podría omitir el segundo store. Esto supondría una fatal
1743259b007fSCarlos Bilbao     sorpresa, si alguna otra CPU hubiera almacenado la variable 'a'
1744259b007fSCarlos Bilbao     mientras tanto.
1745259b007fSCarlos Bilbao
1746259b007fSCarlos Bilbao     Use WRITE_ONCE() para evitar que el compilador haga este tipo de
1747259b007fSCarlos Bilbao     suposición equivocada:
1748259b007fSCarlos Bilbao
1749259b007fSCarlos Bilbao	WRITE_ONCE(a, 0);
1750259b007fSCarlos Bilbao	... Código que no almacena la variable a  ...
1751259b007fSCarlos Bilbao	WRITE_ONCE(a, 0);
1752259b007fSCarlos Bilbao
1753259b007fSCarlos Bilbao  (*) El compilador tiene derecho a reordenar los accesos a memoria a menos
1754259b007fSCarlos Bilbao     que le diga que no. Por ejemplo, considere la siguiente interacción
1755259b007fSCarlos Bilbao     entre el código de nivel de proceso y un controlador de interrupción:
1756259b007fSCarlos Bilbao
1757259b007fSCarlos Bilbao	void nivel_de_procesamiento(void)
1758259b007fSCarlos Bilbao	{
1759259b007fSCarlos Bilbao		msg = ACQUIRE_mensaje();
1760259b007fSCarlos Bilbao		flag = true;
1761259b007fSCarlos Bilbao	}
1762259b007fSCarlos Bilbao
1763259b007fSCarlos Bilbao	void controlador_interrupcion(void)
1764259b007fSCarlos Bilbao	{
1765259b007fSCarlos Bilbao		if (flag)
1766259b007fSCarlos Bilbao			procesar_mensaje(msg);
1767259b007fSCarlos Bilbao	}
1768259b007fSCarlos Bilbao
1769259b007fSCarlos Bilbao     No hay nada que impida que el compilador transforme
1770259b007fSCarlos Bilbao     nivel_de_procesamiento() a lo siguiente, que de hecho, bien podría ser
1771259b007fSCarlos Bilbao     una victoria para código de un solo subproceso:
1772259b007fSCarlos Bilbao
1773259b007fSCarlos Bilbao	void nivel_de_procesamiento(void)
1774259b007fSCarlos Bilbao	{
1775259b007fSCarlos Bilbao		flag = true;
1776259b007fSCarlos Bilbao		msg = ACQUIRE_mensaje();
1777259b007fSCarlos Bilbao	}
1778259b007fSCarlos Bilbao
1779259b007fSCarlos Bilbao     Si la interrupción ocurre entre estas dos declaraciones, entonces
1780259b007fSCarlos Bilbao     controlador_interrupcion() podría recibir un mensaje ilegible. Use
1781259b007fSCarlos Bilbao     READ_ONCE() para evitar esto de la siguiente manera:
1782259b007fSCarlos Bilbao
1783259b007fSCarlos Bilbao	void nivel_de_procesamiento(void)
1784259b007fSCarlos Bilbao	{
1785259b007fSCarlos Bilbao		WRITE_ONCE(msg, ACQUIRE_mensaje());
1786259b007fSCarlos Bilbao		WRITE_ONCE(flag, true);
1787259b007fSCarlos Bilbao	}
1788259b007fSCarlos Bilbao
1789259b007fSCarlos Bilbao	void controlador_interrupcion(void)
1790259b007fSCarlos Bilbao	{
1791259b007fSCarlos Bilbao		if (READ_ONCE(flag))
1792259b007fSCarlos Bilbao			procesar_mensaje(READ_ONCE(msg));
1793259b007fSCarlos Bilbao	}
1794259b007fSCarlos Bilbao
1795259b007fSCarlos Bilbao     Tenga en cuenta que los envoltorios ("wrappers") READ_ONCE() y
1796259b007fSCarlos Bilbao     WRITE_ONCE() en controlador_interrupcion() son necesarios si este
1797259b007fSCarlos Bilbao     controlador de interrupciones puede ser interrumpido por algo que
1798259b007fSCarlos Bilbao     también accede a 'flag' y 'msg', por ejemplo, una interrupción anidada
1799259b007fSCarlos Bilbao     o un NMI. De lo contrario, READ_ONCE() y WRITE_ONCE() no son
1800259b007fSCarlos Bilbao     necesarios en controlador_interrupcion() aparte de con fines de
1801259b007fSCarlos Bilbao     documentación. (Tenga también en cuenta que las interrupciones
1802259b007fSCarlos Bilbao     anidadas no ocurren típicamente en los kernels Linux modernos, de
1803259b007fSCarlos Bilbao     hecho, si un controlador de interrupciones regresa con interrupciones
1804259b007fSCarlos Bilbao     habilitadas, obtendrá un WARN_ONCE().)
1805259b007fSCarlos Bilbao
1806259b007fSCarlos Bilbao     Debe suponer que el compilador puede mover READ_ONCE() y WRITE_ONCE()
1807259b007fSCarlos Bilbao     a código que no contiene READ_ONCE(), WRITE_ONCE(), barrier(), o
1808259b007fSCarlos Bilbao     primitivas similares.
1809259b007fSCarlos Bilbao
1810259b007fSCarlos Bilbao     Este efecto también podría lograrse usando barrier(), pero READ_ONCE()
1811259b007fSCarlos Bilbao     y WRITE_ONCE() son más selectivos: Con READ_ONCE() y WRITE_ONCE(), el
1812259b007fSCarlos Bilbao     compilador solo necesita olvidar el contenido de ubicaciones de
1813259b007fSCarlos Bilbao     memoria indicadas, mientras que con barrier() el compilador debe
1814259b007fSCarlos Bilbao     descartar el valor de todas las ubicaciones de memoria que tiene
1815259b007fSCarlos Bilbao     actualmente almacenadas en caché, en cualquier registro de la máquina.
1816259b007fSCarlos Bilbao     Por supuesto, el compilador también debe respetar el orden en que
1817259b007fSCarlos Bilbao     ocurren READ_ONCE() y WRITE_ONCE(), aunque la CPU, efectivamente, no
1818259b007fSCarlos Bilbao     necesita hacerlo.
1819259b007fSCarlos Bilbao
1820259b007fSCarlos Bilbao (*) El compilador tiene derecho a inventar stores para una variable,
1821259b007fSCarlos Bilbao     como en el siguiente ejemplo:
1822259b007fSCarlos Bilbao
1823259b007fSCarlos Bilbao	if (a)
1824259b007fSCarlos Bilbao		b = a;
1825259b007fSCarlos Bilbao	else
1826259b007fSCarlos Bilbao		b = 42;
1827259b007fSCarlos Bilbao
1828259b007fSCarlos Bilbao    El compilador podría ahorrar un branch al optimizar esto de la
1829259b007fSCarlos Bilbao    siguiente manera:
1830259b007fSCarlos Bilbao
1831259b007fSCarlos Bilbao    	b = 42;
1832259b007fSCarlos Bilbao    	if (a)
1833259b007fSCarlos Bilbao    		b = a;
1834259b007fSCarlos Bilbao
1835259b007fSCarlos Bilbao     En el código de un solo subproceso, esto no solo es seguro, sino que
1836259b007fSCarlos Bilbao     también ahorra un branch. Desafortunadamente, en código concurrente,
1837259b007fSCarlos Bilbao     esta optimización podría causar que alguna otra CPU vea un valor falso
1838259b007fSCarlos Bilbao     de 42, incluso si la variable 'a' nunca fue cero, al cargar la
1839259b007fSCarlos Bilbao     variable 'b'. Use WRITE_ONCE() para evitar esto de la siguiente
1840259b007fSCarlos Bilbao     manera:
1841259b007fSCarlos Bilbao
1842259b007fSCarlos Bilbao	if (a)
1843259b007fSCarlos Bilbao		WRITE_ONCE(b, a);
1844259b007fSCarlos Bilbao	else
1845259b007fSCarlos Bilbao		WRITE_ONCE(b, 42);
1846259b007fSCarlos Bilbao
1847259b007fSCarlos Bilbao    El compilador también puede inventar cargas. Estos casos suelen ser
1848259b007fSCarlos Bilbao    menos perjudiciales, pero pueden dar como resultado "bouncing" de la
1849259b007fSCarlos Bilbao    línea de caché y, por lo tanto, bajo rendimiento y escalabilidad.
1850259b007fSCarlos Bilbao    Utilice READ_ONCE() para evitar cargas inventadas.
1851259b007fSCarlos Bilbao
1852259b007fSCarlos Bilbao (*) Para ubicaciones de memoria alineadas cuyo tamaño les permita
1853259b007fSCarlos Bilbao     acceder con una sola instrucción de referencia de memoria, evite el
1854259b007fSCarlos Bilbao     "desgarro de la carga" (load tearing) y "desgarro del store" (store
1855259b007fSCarlos Bilbao     tearing), en el que un solo gran acceso es reemplazado por múltiples
1856259b007fSCarlos Bilbao     accesos menores. Por ejemplo, dada una arquitectura que tiene
1857259b007fSCarlos Bilbao     instrucciones de almacenamiento de 16 bits con campos inmediatos de 7
1858259b007fSCarlos Bilbao     bits, el compilador podría tener la tentación de usar dos
1859259b007fSCarlos Bilbao     instrucciones inmediatas de almacenamiento de 16 bits para implementar
1860259b007fSCarlos Bilbao     el siguiente store de 32 bits:
1861259b007fSCarlos Bilbao
1862259b007fSCarlos Bilbao	p = 0x00010002;
1863259b007fSCarlos Bilbao
1864259b007fSCarlos Bilbao     Tenga en cuenta que GCC realmente usa este tipo de optimización, lo
1865259b007fSCarlos Bilbao     cual no es sorprendente dado que probablemente costaría más de dos
1866259b007fSCarlos Bilbao     instrucciones el construir la constante y luego almacenarla. Por lo
1867259b007fSCarlos Bilbao     tanto, esta optimización puede ser una victoria en un código de un
1868259b007fSCarlos Bilbao     solo subproceso. De hecho, un error reciente (desde que se solucionó)
1869259b007fSCarlos Bilbao     hizo que GCC usara incorrectamente esta optimización en un store
1870259b007fSCarlos Bilbao     volátil. En ausencia de tales errores, el uso de WRITE_ONCE() evita el
1871259b007fSCarlos Bilbao     desgarro del store en el siguiente ejemplo:
1872259b007fSCarlos Bilbao
1873259b007fSCarlos Bilbao	struct __attribute__((__packed__)) foo {
1874259b007fSCarlos Bilbao		short a;
1875259b007fSCarlos Bilbao		int b;
1876259b007fSCarlos Bilbao		short c;
1877259b007fSCarlos Bilbao	};
1878259b007fSCarlos Bilbao	struct foo foo1, foo2;
1879259b007fSCarlos Bilbao	...
1880259b007fSCarlos Bilbao
1881259b007fSCarlos Bilbao	foo2.a = foo1.a;
1882259b007fSCarlos Bilbao	foo2.b = foo1.b;
1883259b007fSCarlos Bilbao	foo2.c = foo1.c;
1884259b007fSCarlos Bilbao
1885259b007fSCarlos Bilbao     Debido a que no hay envoltorios READ_ONCE() o WRITE_ONCE() y no
1886259b007fSCarlos Bilbao     hay markings volátiles, el compilador estaría en su derecho de
1887259b007fSCarlos Bilbao     implementar estas tres declaraciones de asignación como un par de
1888259b007fSCarlos Bilbao     cargas de 32 bits, seguido de un par de stores de 32 bits. Esto
1889259b007fSCarlos Bilbao     resultaría en una carga con desgarro en 'foo1.b' y store del desgarro
1890259b007fSCarlos Bilbao     en 'foo2.b'. READ_ONCE() y WRITE_ONCE() nuevamente evitan el desgarro
1891259b007fSCarlos Bilbao     en este ejemplo:
1892259b007fSCarlos Bilbao
1893259b007fSCarlos Bilbao	foo2.a = foo1.a;
1894259b007fSCarlos Bilbao	WRITE_ONCE(foo2.b, READ_ONCE(foo1.b));
1895259b007fSCarlos Bilbao	foo2.c = foo1.c;
1896259b007fSCarlos Bilbao
1897259b007fSCarlos BilbaoAparte de esto, nunca es necesario usar READ_ONCE() y WRITE_ONCE() en una
1898259b007fSCarlos Bilbaovariable que se ha marcado como volátil. Por ejemplo, dado que 'jiffies'
1899259b007fSCarlos Bilbaoestá marcado como volátil, nunca es necesario usar READ_ONCE(jiffies). La
1900259b007fSCarlos Bilbaorazón de esto es que READ_ONCE() y WRITE_ONCE() se implementan como
1901259b007fSCarlos Bilbaoconversiones volátiles, lo que no tiene efecto cuando su argumento ya está
1902259b007fSCarlos Bilbaomarcado como volátil.
1903259b007fSCarlos Bilbao
1904259b007fSCarlos BilbaoTenga en cuenta que estas barreras del compilador no tienen un efecto
1905259b007fSCarlos Bilbaodirecto en la CPU, que luego puede reordenar las cosas como quiera.
1906259b007fSCarlos Bilbao
1907259b007fSCarlos Bilbao
1908259b007fSCarlos BilbaoBARRERAS DE MEMORIA DE LA CPU
1909259b007fSCarlos Bilbao-----------------------------
1910259b007fSCarlos Bilbao
1911259b007fSCarlos BilbaoEl kernel de Linux tiene siete barreras básicas de memoria de CPU:
1912259b007fSCarlos Bilbao
1913259b007fSCarlos BilbaoTIPO			OBLIGATORIO	SMP CONDICIONAL
1914259b007fSCarlos Bilbao=======================	===============	===============
1915259b007fSCarlos BilbaoGENERAL			mb()		smp_mb()
1916259b007fSCarlos BilbaoWRITE			wmb()		smp_wmb()
1917259b007fSCarlos BilbaoREAD			rmb()		smp_rmb()
1918259b007fSCarlos BilbaoDEPEDENCIA DE DIRECCIÓN			READ_ONCE()
1919259b007fSCarlos Bilbao
1920259b007fSCarlos Bilbao
1921259b007fSCarlos BilbaoTodas las barreras de memoria, excepto las barreras de dependencia de
1922259b007fSCarlos Bilbaodirecciones, implican una barrera del compilador. Las dependencias de
1923259b007fSCarlos Bilbaodirecciones no imponen ningún orden de compilación adicional.
1924259b007fSCarlos Bilbao
1925259b007fSCarlos BilbaoAdemás: en el caso de las dependencias de direcciones, se esperaría que el
1926259b007fSCarlos Bilbaocompilador emita las cargas en el orden correcto (por ejemplo, `a[b]`
1927259b007fSCarlos Bilbaotendría que cargar el valor de b antes de cargar a[b]), sin embargo, no hay
1928259b007fSCarlos Bilbaogarantía alguna en la especificación de C sobre que el compilador no puede
1929259b007fSCarlos Bilbaoespecular el valor de b (por ejemplo, es igual a 1) y carga a[b] antes que
1930259b007fSCarlos Bilbaob (ej. tmp = a[1]; if (b != 1) tmp = a[b]; ). También existe el problema de
1931259b007fSCarlos Bilbaoque un compilador vuelva a cargar b después de haber cargado a[b], teniendo
1932259b007fSCarlos Bilbaoasí una copia más nueva de b que a[b]. Aún no se ha conseguido un consenso
1933259b007fSCarlos Bilbaoacerca de estos problemas, sin embargo, el macro READ_ONCE() es un buen
1934259b007fSCarlos Bilbaolugar para empezar a buscar.
1935259b007fSCarlos Bilbao
1936259b007fSCarlos BilbaoLas barreras de memoria SMP se reducen a barreras de compilador cuando se
1937259b007fSCarlos Bilbaocompila a monoprocesador, porque se supone que una CPU parecerá ser
1938259b007fSCarlos Bilbaoauto-consistente, y ordenará correctamente los accesos superpuestos
1939259b007fSCarlos Bilbaorespecto a sí misma. Sin embargo, consulte la subsección "Guests de
1940259b007fSCarlos Bilbaomáquinas virtuales" mas adelante.
1941259b007fSCarlos Bilbao
1942259b007fSCarlos Bilbao[!] Tenga en cuenta que las barreras de memoria SMP _deben_ usarse para
1943259b007fSCarlos Bilbaocontrolar el orden de referencias a memoria compartida en sistemas SMP,
1944259b007fSCarlos Bilbaoaunque el uso de bloqueo en su lugar sea suficiente.
1945259b007fSCarlos Bilbao
1946259b007fSCarlos BilbaoLas barreras obligatorias no deben usarse para controlar los efectos de
1947259b007fSCarlos BilbaoSMP, ya que dichas barreras imponen una sobrecarga innecesaria en los
1948259b007fSCarlos Bilbaosistemas SMP y UP. Se pueden, sin embargo, usar para controlar los efectos
1949259b007fSCarlos BilbaoMMIO en los accesos a través de ventanas E/S de memoria relajada. Estas
1950259b007fSCarlos Bilbaobarreras son necesarias incluso en sistemas que no son SMP, ya que afectan
1951259b007fSCarlos Bilbaoal orden en que las operaciones de memoria aparecen en un dispositivo, al
1952259b007fSCarlos Bilbaoprohibir tanto al compilador como a la CPU que sean reordenados.
1953259b007fSCarlos Bilbao
1954259b007fSCarlos Bilbao
1955259b007fSCarlos BilbaoHay algunas funciones de barrera más avanzadas:
1956259b007fSCarlos Bilbao
1957259b007fSCarlos Bilbao (*) smp_store_mb(var, valor)
1958259b007fSCarlos Bilbao
1959259b007fSCarlos Bilbao     Asigna el valor a la variable y luego inserta una barrera de memoria
1960259b007fSCarlos Bilbao     completa después de ella. No se garantiza insertar nada más que una
1961259b007fSCarlos Bilbao     barrera del compilador en una compilación UP.
1962259b007fSCarlos Bilbao
1963259b007fSCarlos Bilbao
1964259b007fSCarlos Bilbao (*) smp_mb__before_atomic();
1965259b007fSCarlos Bilbao (*) smp_mb__after_atomic();
1966259b007fSCarlos Bilbao
1967259b007fSCarlos Bilbao     Estos se pueden usar con funciones RMW atómicas que no implican
1968259b007fSCarlos Bilbao     barreras de memoria, pero donde el código necesita una barrera de
1969259b007fSCarlos Bilbao     memoria. Ejemplos de funciones RMW atómicas que no implican una
1970259b007fSCarlos Bilbao     barrera de memoria son, por ejemplo, agregar, restar, operaciones
1971259b007fSCarlos Bilbao     condicionales (fallidas), funciones _relaxed, pero no atomic_read o
1972259b007fSCarlos Bilbao     atomic_set. Un ejemplo común donde se puede requerir una barrera es
1973259b007fSCarlos Bilbao     cuando se usan operaciones atómicas como referencia de contador.
1974259b007fSCarlos Bilbao
1975259b007fSCarlos Bilbao     Estos también se utilizan para funciones atómicas RMW bitop que no
1976259b007fSCarlos Bilbao     implican una barrera de memoria (como set_bit y clear_bit).
1977259b007fSCarlos Bilbao
1978259b007fSCarlos Bilbao     Como ejemplo, considere una pieza de código que marca un objeto como
1979259b007fSCarlos Bilbao     muerto y luego disminuye el contador de referencias del objeto:
1980259b007fSCarlos Bilbao
1981259b007fSCarlos Bilbao	obj->dead = 1;
1982259b007fSCarlos Bilbao	smp_mb__before_atomic();
1983259b007fSCarlos Bilbao	atomic_dec(&obj->ref_count);
1984259b007fSCarlos Bilbao
1985259b007fSCarlos Bilbao     Esto asegura que la marca de muerte en el objeto se perciba como
1986259b007fSCarlos Bilbao     fijada *antes* de que disminuya el contador de referencia.
1987259b007fSCarlos Bilbao
1988259b007fSCarlos Bilbao     Consulte Documentation/atomic_{t,bitops}.txt para obtener más
1989259b007fSCarlos Bilbao     información.
1990259b007fSCarlos Bilbao
1991259b007fSCarlos Bilbao
1992259b007fSCarlos Bilbao (*) dma_wmb();
1993259b007fSCarlos Bilbao (*) dma_rmb();
1994259b007fSCarlos Bilbao (*) dma_mb();
1995259b007fSCarlos Bilbao
1996259b007fSCarlos Bilbao     Estos son usados con memoria consistente para garantizar el orden de
1997259b007fSCarlos Bilbao     escrituras o lecturas de memoria compartida accesible tanto para la
1998259b007fSCarlos Bilbao     CPU como para un dispositivo compatible con DMA.
1999259b007fSCarlos Bilbao
2000259b007fSCarlos Bilbao     Por ejemplo, considere un controlador de dispositivo que comparte
2001259b007fSCarlos Bilbao     memoria con otro dispositivo y usa un valor de estado del descriptor
2002259b007fSCarlos Bilbao     para indicar si el descriptor pertenece al dispositivo o a la CPU, y
2003259b007fSCarlos Bilbao     un "doorbell" (timbre, punto de acceso) para avisarle cuando haya
2004259b007fSCarlos Bilbao     nuevos descriptores disponibles:
2005259b007fSCarlos Bilbao
2006259b007fSCarlos Bilbao	if (desc->status != DEVICE_OWN) {
2007259b007fSCarlos Bilbao		/* no leer los datos hasta que tengamos el descriptor */
2008259b007fSCarlos Bilbao		dma_rmb();
2009259b007fSCarlos Bilbao
2010259b007fSCarlos Bilbao		/* leer/modificar datos */
2011259b007fSCarlos Bilbao		read_data = desc->data;
2012259b007fSCarlos Bilbao		desc->data = write_data;
2013259b007fSCarlos Bilbao
2014259b007fSCarlos Bilbao		/* flush de modificaciones antes de la actualización de estado */
2015259b007fSCarlos Bilbao		dma_wmb();
2016259b007fSCarlos Bilbao
2017259b007fSCarlos Bilbao		/* asignar propiedad */
2018259b007fSCarlos Bilbao		desc->status = DEVICE_OWN;
2019259b007fSCarlos Bilbao
2020259b007fSCarlos Bilbao		/* notificar al dispositivo de nuevos descriptores */
2021259b007fSCarlos Bilbao		writel(DESC_NOTIFY, doorbell);
2022259b007fSCarlos Bilbao	}
2023259b007fSCarlos Bilbao
2024259b007fSCarlos Bilbao     El dma_rmb() nos permite garantizar que el dispositivo ha liberado su
2025259b007fSCarlos Bilbao     propiedad antes de que leamos los datos del descriptor, y el dma_wmb()
2026259b007fSCarlos Bilbao     permite garantizar que los datos se escriben en el descriptor antes de
2027259b007fSCarlos Bilbao     que el dispositivo pueda ver que ahora tiene la propiedad. El dma_mb()
2028259b007fSCarlos Bilbao     implica tanto un dma_rmb() como un dma_wmb(). Tenga en cuenta que, al
2029259b007fSCarlos Bilbao     usar writel(), no se necesita un wmb() anterior para garantizar que
2030259b007fSCarlos Bilbao     las escrituras de la memoria caché coherente se hayan completado antes
2031259b007fSCarlos Bilbao     escribiendo a la región MMIO. El writel_relaxed() más barato no
2032259b007fSCarlos Bilbao     proporciona esta garantía y no debe utilizarse aquí.
2033259b007fSCarlos Bilbao
2034259b007fSCarlos Bilbao     Consulte la subsección "Efectos de barrera de E/S del kernel" para
2035259b007fSCarlos Bilbao     obtener más información sobre accesorios de E/S relajados y el archivo
2036259b007fSCarlos Bilbao     Documentation/core-api/dma-api.rst para más información sobre memoria
2037259b007fSCarlos Bilbao     consistente.
2038259b007fSCarlos Bilbao
2039259b007fSCarlos Bilbao (*) pmem_wmb();
2040259b007fSCarlos Bilbao
2041259b007fSCarlos Bilbao     Es es para uso con memoria persistente para garantizar que los stores
2042259b007fSCarlos Bilbao     para los que las modificaciones se escriben en el almacenamiento
2043259b007fSCarlos Bilbao     persistente llegaron a dominio de durabilidad de la plataforma.
2044259b007fSCarlos Bilbao
2045259b007fSCarlos Bilbao     Por ejemplo, después de una escritura no temporal en la región pmem,
2046259b007fSCarlos Bilbao     usamos pmem_wmb() para garantizar que los stores hayan alcanzado el
2047259b007fSCarlos Bilbao     dominio de durabilidad de la plataforma. Esto garantiza que los stores
2048259b007fSCarlos Bilbao     han actualizado el almacenamiento persistente antes de cualquier
2049259b007fSCarlos Bilbao     acceso a datos o transferencia de datos causada por instrucciones
2050259b007fSCarlos Bilbao     posteriores. Esto es además del orden realizado por wmb().
2051259b007fSCarlos Bilbao
2052259b007fSCarlos Bilbao     Para la carga desde memoria persistente, las barreras de memoria de
2053259b007fSCarlos Bilbao     lectura existentes son suficientes para garantizar el orden de
2054259b007fSCarlos Bilbao     lectura.
2055259b007fSCarlos Bilbao
2056259b007fSCarlos Bilbao (*) io_stop_wc();
2057259b007fSCarlos Bilbao
2058259b007fSCarlos Bilbao     Para accesos a memoria con atributos de combinación de escritura (por
2059259b007fSCarlos Bilbao     ejemplo, los devueltos por ioremap_wc(), la CPU puede esperar a que
2060259b007fSCarlos Bilbao     los accesos anteriores se junten con posteriores. io_stop_wc() se
2061259b007fSCarlos Bilbao     puede utilizar para evitar la combinación de accesos a memoria de
2062259b007fSCarlos Bilbao     de escritura antes de esta macro, con los posteriores, cuando dicha
2063259b007fSCarlos Bilbao     espera tenga implicaciones en el rendimiento.
2064259b007fSCarlos Bilbao
2065259b007fSCarlos Bilbao=========================================
2066259b007fSCarlos BilbaoBARRERAS DE MEMORIA IMPLÍCITAS DEL KERNEL
2067259b007fSCarlos Bilbao=========================================
2068259b007fSCarlos Bilbao
2069259b007fSCarlos BilbaoAlgunas de las otras funciones en el kernel Linux implican barreras de
2070259b007fSCarlos Bilbaomemoria, entre estas encontramos funciones de bloqueo y planificación
2071259b007fSCarlos Bilbao("scheduling").
2072259b007fSCarlos Bilbao
2073259b007fSCarlos BilbaoEsta especificación es una garantía _mínima_; cualquier arquitectura
2074259b007fSCarlos Bilbaoparticular puede proporcionar garantías más sustanciales, pero no se puede
2075259b007fSCarlos Bilbaoconfiar en estas fuera de código específico de arquitectura.
2076259b007fSCarlos Bilbao
2077259b007fSCarlos Bilbao
2078259b007fSCarlos BilbaoFUNCIONES DE ADQUISICIÓN DE CERROJO
2079259b007fSCarlos Bilbao-----------------------------------
2080259b007fSCarlos Bilbao
2081259b007fSCarlos BilbaoEl kernel Linux tiene una serie de abstracciones de bloqueo:
2082259b007fSCarlos Bilbao
2083259b007fSCarlos Bilbao (*) spin locks (cerrojos en loop)
2084259b007fSCarlos Bilbao (*) R/W spin lock (cerrojos de escritura/lectura)
2085259b007fSCarlos Bilbao (*) mutex
2086259b007fSCarlos Bilbao (*) semáforos
2087259b007fSCarlos Bilbao (*) R/W semáforos
2088259b007fSCarlos Bilbao
2089259b007fSCarlos BilbaoEn todos los casos existen variantes de las operaciones "ACQUIRE" y
2090259b007fSCarlos Bilbao"RELEASE" para cada uno de ellos. Todas estas operaciones implican ciertas
2091259b007fSCarlos Bilbaobarreras:
2092259b007fSCarlos Bilbao
2093259b007fSCarlos Bilbao (1) Implicaciones de la operación ACQUIRE:
2094259b007fSCarlos Bilbao
2095259b007fSCarlos Bilbao     Las operaciones de memoria emitidas después del ACQUIRE se completarán
2096259b007fSCarlos Bilbao     después de que la operación ACQUIRE haya finalizado.
2097259b007fSCarlos Bilbao
2098259b007fSCarlos Bilbao     Las operaciones de memoria emitidas antes de ACQUIRE pueden
2099259b007fSCarlos Bilbao     completarse después que la operación ACQUIRE se ha completado.
2100259b007fSCarlos Bilbao
2101259b007fSCarlos Bilbao (2) Implicaciones de la operación RELEASE:
2102259b007fSCarlos Bilbao
2103259b007fSCarlos Bilbao     Las operaciones de memoria emitidas antes de la RELEASE se
2104259b007fSCarlos Bilbao     completarán antes de que la operación de RELEASE se haya completado.
2105259b007fSCarlos Bilbao
2106259b007fSCarlos Bilbao     Las operaciones de memoria emitidas después de la RELEASE pueden
2107259b007fSCarlos Bilbao     completarse antes de que la operación de RELEASE se haya completado.
2108259b007fSCarlos Bilbao
2109259b007fSCarlos Bilbao (3) Implicación de ACQUIRE vs ACQUIRE:
2110259b007fSCarlos Bilbao
2111259b007fSCarlos Bilbao     Todas las operaciones ACQUIRE emitidas antes de otra operación
2112259b007fSCarlos Bilbao     ACQUIRE serán completadas antes de esa operación ACQUIRE.
2113259b007fSCarlos Bilbao
2114259b007fSCarlos Bilbao (4) Implicación de ACQUIRE vs RELEASE:
2115259b007fSCarlos Bilbao
2116259b007fSCarlos Bilbao     Todas las operaciones ACQUIRE emitidas antes de una operación RELEASE
2117259b007fSCarlos Bilbao     serán completadas antes de la operación RELEASE.
2118259b007fSCarlos Bilbao
2119259b007fSCarlos Bilbao (5) Implicación de ACQUIRE condicional fallido:
2120259b007fSCarlos Bilbao
2121259b007fSCarlos Bilbao     Ciertas variantes de bloqueo de la operación ACQUIRE pueden fallar, ya
2122259b007fSCarlos Bilbao     sea debido a no poder obtener el bloqueo de inmediato, o debido a que
2123259b007fSCarlos Bilbao     recibieron una señal de desbloqueo mientras dormían esperando que el
2124259b007fSCarlos Bilbao     cerrojo estuviera disponible. Los fallos en cerrojos no implican
2125259b007fSCarlos Bilbao     ningún tipo de barrera.
2126259b007fSCarlos Bilbao
2127259b007fSCarlos Bilbao[!] Nota: una de las consecuencias de que los cerrojos en ACQUIRE y RELEASE
2128259b007fSCarlos Bilbaosean barreras unidireccionales, es que los efectos de las instrucciones
2129259b007fSCarlos Bilbaofuera de una sección crítica pueden filtrarse al interior de la sección
2130259b007fSCarlos Bilbaocrítica.
2131259b007fSCarlos Bilbao
2132259b007fSCarlos BilbaoNo se puede suponer que un ACQUIRE seguido de una RELEASE sea una barrera
2133259b007fSCarlos Bilbaode memoria completa dado que es posible que un acceso anterior a ACQUIRE
2134259b007fSCarlos Bilbaosuceda después del ACQUIRE, y un acceso posterior a la RELEASE suceda antes
2135259b007fSCarlos Bilbaodel RELEASE, y los dos accesos puedan entonces cruzarse:
2136259b007fSCarlos Bilbao
2137259b007fSCarlos Bilbao	*A = a;
2138259b007fSCarlos Bilbao	ACQUIRE M
2139259b007fSCarlos Bilbao	RELEASE M
2140259b007fSCarlos Bilbao	*B = b;
2141259b007fSCarlos Bilbao
2142259b007fSCarlos Bilbaopuede ocurrir como:
2143259b007fSCarlos Bilbao
2144259b007fSCarlos Bilbao	ACQUIRE M, STORE *B, STORE *A, RELEASE M
2145259b007fSCarlos Bilbao
2146259b007fSCarlos BilbaoCuando ACQUIRE y RELEASE son bloqueo de adquisición y liberación,
2147259b007fSCarlos Bilbaorespectivamente, este mismo orden puede ocurrir si el cerrojo ACQUIRE y
2148259b007fSCarlos BilbaoRELEASE son para la misma variable de bloqueo, pero solo desde la
2149259b007fSCarlos Bilbaoperspectiva de otra CPU que no tiene ese bloqueo. En resumen, un ACQUIRE
2150259b007fSCarlos Bilbaoseguido de un RELEASE NO puede entenderse como una barrera de memoria
2151259b007fSCarlos Bilbaocompleta.
2152259b007fSCarlos Bilbao
2153259b007fSCarlos BilbaoDe manera similar, el caso inverso de un RELEASE seguido de un ACQUIRE no
2154259b007fSCarlos Bilbaoimplica una barrera de memoria completa. Por lo tanto, la ejecución de la
2155259b007fSCarlos BilbaoCPU de los tramos críticos correspondientes a la RELEASE y la ACQUIRE
2156259b007fSCarlos Bilbaopueden cruzarse, de modo que:
2157259b007fSCarlos Bilbao
2158259b007fSCarlos Bilbao	*A = a;
2159259b007fSCarlos Bilbao	RELEASE M
2160259b007fSCarlos Bilbao	ACQUIRE N
2161259b007fSCarlos Bilbao	*B = b;
2162259b007fSCarlos Bilbao
2163259b007fSCarlos Bilbaopuede ocurrir como:
2164259b007fSCarlos Bilbao
2165259b007fSCarlos Bilbao	ACQUIRE N, STORE *B, STORE *A, RELEASE M
2166259b007fSCarlos Bilbao
2167259b007fSCarlos BilbaoPodría parecer que este nuevo orden podría introducir un punto muerto.
2168259b007fSCarlos BilbaoSin embargo, esto no puede suceder porque si tal punto muerto amenazara
2169259b007fSCarlos Bilbaocon suceder, el RELEASE simplemente se completaría, evitando así el
2170259b007fSCarlos Bilbaointerbloqueo ("deadlock", punto muerto).
2171259b007fSCarlos Bilbao
2172259b007fSCarlos Bilbao	¿Por qué funciona esto?
2173259b007fSCarlos Bilbao
2174259b007fSCarlos Bilbao	Un punto clave es que solo estamos hablando de la CPU re-haciendo el
2175259b007fSCarlos Bilbao  orden, no el compilador. Si el compilador (o, ya puestos, el
2176259b007fSCarlos Bilbao  desarrollador) cambió las operaciones, un deadlock -podría- ocurrir.
2177259b007fSCarlos Bilbao
2178259b007fSCarlos Bilbao	Pero supongamos que la CPU reordenó las operaciones. En este caso, el
2179259b007fSCarlos Bilbao	desbloqueo precede al bloqueo en el código ensamblador. La CPU
2180259b007fSCarlos Bilbao  simplemente eligió intentar ejecutar primero la última operación de
2181259b007fSCarlos Bilbao  bloqueo. Si hay un interbloqueo, esta operación de bloqueo simplemente
2182259b007fSCarlos Bilbao  esperará (o tratará de dormir, pero hablaremos de eso más adelante). La
2183259b007fSCarlos Bilbao  CPU eventualmente ejecutará la operación de desbloqueo (que precedió a la
2184259b007fSCarlos Bilbao	operación de bloqueo en el código ensamblador), lo que desenmascará el
2185259b007fSCarlos Bilbao  potencial punto muerto, permitiendo que la operación de bloqueo tenga
2186259b007fSCarlos Bilbao  éxito.
2187259b007fSCarlos Bilbao
2188259b007fSCarlos Bilbao	Pero, ¿y si el cerrojo es un cerrojo que duerme ("sleeplock")? En tal
2189259b007fSCarlos Bilbao  caso, el código intentará entrar al scheduler, donde eventualmente
2190259b007fSCarlos Bilbao  encontrará una barrera de memoria, que forzará la operación de desbloqueo
2191259b007fSCarlos Bilbao  anterior para completar, nuevamente desentrañando el punto muerto. Podría
2192259b007fSCarlos Bilbao	haber una carrera de desbloqueo del sueño ("sleep-unlock race"), pero la
2193259b007fSCarlos Bilbao  primitiva de bloqueo necesita resolver tales carreras correctamente en
2194259b007fSCarlos Bilbao  cualquier caso.
2195259b007fSCarlos Bilbao
2196259b007fSCarlos BilbaoEs posible que los cerrojos y los semáforos no proporcionen ninguna
2197259b007fSCarlos Bilbaogarantía de orden en sistemas compilados en UP, por lo que no se puede
2198259b007fSCarlos Bilbaocontar con tal situación para lograr realmente nada en absoluto,
2199259b007fSCarlos Bilbaoespecialmente con respecto a los accesos de E/S, a menos que se combinen
2200259b007fSCarlos Bilbaocon operaciones de inhabilitación de interrupciones.
2201259b007fSCarlos Bilbao
2202259b007fSCarlos BilbaoConsulte también la sección "Efectos de barrera adquiriendo intra-CPU".
2203259b007fSCarlos Bilbao
2204259b007fSCarlos Bilbao
2205259b007fSCarlos BilbaoComo ejemplo, considere lo siguiente:
2206259b007fSCarlos Bilbao
2207259b007fSCarlos Bilbao	*A = a;
2208259b007fSCarlos Bilbao	*B = b;
2209259b007fSCarlos Bilbao	ACQUIRE
2210259b007fSCarlos Bilbao	*C = c;
2211259b007fSCarlos Bilbao	*D = d;
2212259b007fSCarlos Bilbao	RELEASE
2213259b007fSCarlos Bilbao	*E = e;
2214259b007fSCarlos Bilbao	*F = f;
2215259b007fSCarlos Bilbao
2216259b007fSCarlos BilbaoLa siguiente secuencia de eventos es aceptable:
2217259b007fSCarlos Bilbao
2218259b007fSCarlos Bilbao	ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE
2219259b007fSCarlos Bilbao
2220259b007fSCarlos Bilbao  [+] Tenga en cuenta que {*F,*A} indica un acceso combinado.
2221259b007fSCarlos Bilbao
2222259b007fSCarlos BilbaoPero ninguno de los siguientes lo son:
2223259b007fSCarlos Bilbao
2224259b007fSCarlos Bilbao	{*F,*A}, *B,	ACQUIRE, *C, *D,	RELEASE, *E
2225259b007fSCarlos Bilbao	*A, *B, *C,	ACQUIRE, *D,		RELEASE, *E, *F
2226259b007fSCarlos Bilbao	*A, *B,		ACQUIRE, *C,		RELEASE, *D, *E, *F
2227259b007fSCarlos Bilbao	*B,		ACQUIRE, *C, *D,	RELEASE, {*F,*A}, *E
2228259b007fSCarlos Bilbao
2229259b007fSCarlos Bilbao
2230259b007fSCarlos Bilbao
2231259b007fSCarlos BilbaoFUNCIONES DE DESACTIVACIÓN DE INTERRUPCIONES
2232259b007fSCarlos Bilbao--------------------------------------------
2233259b007fSCarlos Bilbao
2234259b007fSCarlos BilbaoLas funciones que deshabilitan interrupciones (equivalentes a ACQUIRE) y
2235259b007fSCarlos Bilbaohabilitan interrupciones (equivalentes a RELEASE) actuarán únicamente como
2236259b007fSCarlos Bilbaobarrera del compilador. Por consiguiente, si la memoria o la E/S requieren
2237259b007fSCarlos Bilbaobarreras en tal situación, deben ser provistas por algún otro medio.
2238259b007fSCarlos Bilbao
2239259b007fSCarlos Bilbao
2240259b007fSCarlos BilbaoFUNCIONES DE DORMIR Y DESPERTAR
2241259b007fSCarlos Bilbao-------------------------------
2242259b007fSCarlos Bilbao
2243259b007fSCarlos BilbaoDormir y despertar son eventos marcados ("flagged") en los datos globales
2244259b007fSCarlos Bilbaoque se pueden ver como una interacción entre dos piezas de datos: el estado
2245259b007fSCarlos Bilbaode la task (hilo, proceso, tarea) que espera el evento y los datos globales
2246259b007fSCarlos Bilbaoutilizados para indicar el evento. Para asegurarse de que estos parezcan
2247259b007fSCarlos Bilbaosuceder en el orden correcto, las primitivas para comenzar el proceso de ir
2248259b007fSCarlos Bilbaoa dormir, y las primitivas para iniciar un despertar implican ciertas
2249259b007fSCarlos Bilbaobarreras.
2250259b007fSCarlos Bilbao
2251259b007fSCarlos BilbaoEn primer lugar, el agente durmiente normalmente sigue algo similar a esta
2252259b007fSCarlos Bilbaosecuencia de eventos:
2253259b007fSCarlos Bilbao
2254259b007fSCarlos Bilbao	for (;;) {
2255259b007fSCarlos Bilbao		set_current_state(TASK_UNINTERRUPTIBLE);
2256259b007fSCarlos Bilbao		if (evento_indicado)
2257259b007fSCarlos Bilbao			break;
2258259b007fSCarlos Bilbao		schedule(); // planificar
2259259b007fSCarlos Bilbao	}
2260259b007fSCarlos Bilbao
2261259b007fSCarlos BilbaoUna barrera de memoria general se obtiene automáticamente mediante
2262259b007fSCarlos Bilbaoset_current_state() después de haber alterado el estado de la tarea:
2263259b007fSCarlos Bilbao
2264259b007fSCarlos Bilbao	CPU 1
2265259b007fSCarlos Bilbao	===============================
2266259b007fSCarlos Bilbao	set_current_state(); // hacer_estado_actual()
2267259b007fSCarlos Bilbao	  smp_store_mb();
2268259b007fSCarlos Bilbao	    STORE current->state
2269259b007fSCarlos Bilbao	    <barrera general>
2270259b007fSCarlos Bilbao	LOAD evento_indicado
2271259b007fSCarlos Bilbao
2272259b007fSCarlos Bilbaoset_current_state() puede estar envuelto por:
2273259b007fSCarlos Bilbao
2274259b007fSCarlos Bilbao	prepare_to_wait(); // preparese_para_esperar();
2275259b007fSCarlos Bilbao	prepare_to_wait_exclusive(); // prepararse_para_solo_esperar();
2276259b007fSCarlos Bilbao
2277259b007fSCarlos Bilbaoque por lo tanto también implican una barrera de memoria general después de
2278259b007fSCarlos Bilbaoestablecer el estado. Toda la secuencia anterior está disponible en varias
2279259b007fSCarlos Bilbaoformas, todas las cuales obtienen la barrera de memoria en el lugar
2280259b007fSCarlos Bilbaocorrecto:
2281259b007fSCarlos Bilbao
2282259b007fSCarlos Bilbao	wait_event();
2283259b007fSCarlos Bilbao	wait_event_interruptible();
2284259b007fSCarlos Bilbao	wait_event_interruptible_exclusive();
2285259b007fSCarlos Bilbao	wait_event_interruptible_timeout();
2286259b007fSCarlos Bilbao	wait_event_killable();
2287259b007fSCarlos Bilbao	wait_event_timeout();
2288259b007fSCarlos Bilbao	wait_on_bit();
2289259b007fSCarlos Bilbao	wait_on_bit_lock();
2290259b007fSCarlos Bilbao
2291259b007fSCarlos Bilbao
2292259b007fSCarlos BilbaoEn segundo lugar, el código que realiza una activación normalmente se
2293259b007fSCarlos Bilbaoasemeja a algo como esto:
2294259b007fSCarlos Bilbao
2295259b007fSCarlos Bilbao	evento_indicado = 1;
2296259b007fSCarlos Bilbao	wake_up(&event_wait_queue); // despertar
2297259b007fSCarlos Bilbao
2298259b007fSCarlos Bilbaoo:
2299259b007fSCarlos Bilbao
2300259b007fSCarlos Bilbao	evento_indicado = 1;
2301259b007fSCarlos Bilbao	wake_up_process(event_daemon); // despertar proceso
2302259b007fSCarlos Bilbao
2303259b007fSCarlos Bilbaowake_up() ejecuta una barrera de memoria general si despierta algo. Si no
2304259b007fSCarlos Bilbaodespierta nada, entonces una barrera de memoria puede o no ser ejecutada;
2305259b007fSCarlos Bilbaono debe confiar en ello. La barrera se produce antes del acceso al estado
2306259b007fSCarlos Bilbaode la tarea. En particular, se encuentra entre el STORE para indicar el
2307259b007fSCarlos Bilbaoevento y el STORE para configurar TASK_RUNNING (hilo ejecutando):
2308259b007fSCarlos Bilbao
2309259b007fSCarlos Bilbao	CPU 1 (Durmiente)			CPU 2 (Despertadora)
2310259b007fSCarlos Bilbao	===============================	===============================
2311259b007fSCarlos Bilbao	set_current_state();		STORE evento_indicado
2312259b007fSCarlos Bilbao	  smp_store_mb();		wake_up();
2313259b007fSCarlos Bilbao	    STORE current->state	  ...
2314259b007fSCarlos Bilbao	    <barrera general>		  <barrera general>
2315259b007fSCarlos Bilbao	LOAD evento_indicado		  if ((LOAD task->state) & TASK_NORMAL)
2316259b007fSCarlos Bilbao					    STORE task->state
2317259b007fSCarlos Bilbao
2318259b007fSCarlos Bilbaodonde "task" es el subproceso que se está despertando y es igual al
2319259b007fSCarlos Bilbao"current" (hilo actual) de la CPU 1.
2320259b007fSCarlos Bilbao
2321259b007fSCarlos BilbaoPara reiterar, se garantiza la ejecución de una barrera de memoria general
2322259b007fSCarlos Bilbaomediante wake_up() si algo está realmente despierto, pero de lo contrario
2323259b007fSCarlos Bilbaono existe tal garantía. Para entender esto, considere la siguiente
2324259b007fSCarlos Bilbaosecuencia de eventos, donde X e Y son ambos cero inicialmente:
2325259b007fSCarlos Bilbao
2326259b007fSCarlos Bilbao	CPU 1				CPU 2
2327259b007fSCarlos Bilbao	===============================	===============================
2328259b007fSCarlos Bilbao	X = 1;				Y = 1;
2329259b007fSCarlos Bilbao	smp_mb();			wake_up();
2330259b007fSCarlos Bilbao	LOAD Y				LOAD X
2331259b007fSCarlos Bilbao
2332259b007fSCarlos BilbaoSi ocurre una reactivación ("wakeup"), una (al menos) de las dos cargas
2333259b007fSCarlos Bilbaodebe ver 1. Si, por otro lado, no ocurre una reactivación, ambas cargas
2334259b007fSCarlos Bilbaopueden ver 0.
2335259b007fSCarlos Bilbao
2336259b007fSCarlos Bilbaowake_up_process() siempre ejecuta una barrera de memoria general. La
2337259b007fSCarlos Bilbaobarrera, de nuevo, ocurre antes de que se acceda al estado del hilo. En
2338259b007fSCarlos Bilbaoparticular, si wake_up(), en el fragmento anterior, fuera reemplazado por
2339259b007fSCarlos Bilbaouna llamada a wake_up_process(), las dos cargas verían 1, garantizado.
2340259b007fSCarlos Bilbao
2341259b007fSCarlos BilbaoLas funciones de activación disponibles incluyen:
2342259b007fSCarlos Bilbao
2343259b007fSCarlos Bilbao	complete();
2344259b007fSCarlos Bilbao	wake_up();
2345259b007fSCarlos Bilbao	wake_up_all();
2346259b007fSCarlos Bilbao	wake_up_bit();
2347259b007fSCarlos Bilbao	wake_up_interruptible();
2348259b007fSCarlos Bilbao	wake_up_interruptible_all();
2349259b007fSCarlos Bilbao	wake_up_interruptible_nr();
2350259b007fSCarlos Bilbao	wake_up_interruptible_poll();
2351259b007fSCarlos Bilbao	wake_up_interruptible_sync();
2352259b007fSCarlos Bilbao	wake_up_interruptible_sync_poll();
2353259b007fSCarlos Bilbao	wake_up_locked();
2354259b007fSCarlos Bilbao	wake_up_locked_poll();
2355259b007fSCarlos Bilbao	wake_up_nr();
2356259b007fSCarlos Bilbao	wake_up_poll();
2357259b007fSCarlos Bilbao	wake_up_process();
2358259b007fSCarlos Bilbao
2359259b007fSCarlos BilbaoEn términos de orden de la memoria, todas estas funciones proporcionan las
2360259b007fSCarlos Bilbaomismas garantías que un wake_up() (o más fuertes).
2361259b007fSCarlos Bilbao
2362259b007fSCarlos Bilbao[!] Tenga en cuenta que las barreras de la memoria implicadas por el
2363259b007fSCarlos Bilbaodurmiente y el despierto _no_ ordenan varios stores antes del despertar con
2364259b007fSCarlos Bilbaorespecto a cargas de los valores guardados después de que el durmiente haya
2365259b007fSCarlos Bilbaollamado a set_current_state(). Por ejemplo, si el durmiente hace:
2366259b007fSCarlos Bilbao
2367259b007fSCarlos Bilbao	set_current_state(TASK_INTERRUPTIBLE);
2368259b007fSCarlos Bilbao	if (evento_indicado)
2369259b007fSCarlos Bilbao		break;
2370259b007fSCarlos Bilbao	__set_current_state(TASK_RUNNING);
2371259b007fSCarlos Bilbao	hacer_algo(my_data);
2372259b007fSCarlos Bilbao
2373259b007fSCarlos Bilbaoy el que despierta hace:
2374259b007fSCarlos Bilbao
2375259b007fSCarlos Bilbao	my_data = valor;
2376259b007fSCarlos Bilbao	evento_indicado = 1;
2377259b007fSCarlos Bilbao	wake_up(&event_wait_queue);
2378259b007fSCarlos Bilbao
2379259b007fSCarlos Bilbaono existe garantía de que el cambio a event_indicated sea percibido por
2380259b007fSCarlos Bilbaoel durmiente de manera que venga después del cambio a my_data. En tal
2381259b007fSCarlos Bilbaocircunstancia, el código en ambos lados debe sacar sus propias barreras de
2382259b007fSCarlos Bilbaomemoria entre los separados accesos a datos. Por lo tanto, el durmiente
2383259b007fSCarlos Bilbaoanterior debería hacer:
2384259b007fSCarlos Bilbao
2385259b007fSCarlos Bilbao	set_current_state(TASK_INTERRUPTIBLE);
2386259b007fSCarlos Bilbao	if (evento_indicado) {
2387259b007fSCarlos Bilbao		smp_rmb();
2388259b007fSCarlos Bilbao		hacer_algo(my_data);
2389259b007fSCarlos Bilbao	}
2390259b007fSCarlos Bilbao
2391259b007fSCarlos Bilbaoy el que despierta debería hacer:
2392259b007fSCarlos Bilbao
2393259b007fSCarlos Bilbao	my_data = value;
2394259b007fSCarlos Bilbao	smp_wmb();
2395259b007fSCarlos Bilbao	evento_indicado = 1;
2396259b007fSCarlos Bilbao	wake_up(&event_wait_queue);
2397259b007fSCarlos Bilbao
2398259b007fSCarlos BilbaoFUNCIONES VARIAS
2399259b007fSCarlos Bilbao----------------
2400259b007fSCarlos Bilbao
2401259b007fSCarlos BilbaoOtras funciones que implican barreras:
2402259b007fSCarlos Bilbao
2403259b007fSCarlos Bilbao (*) schedule() y similares implican barreras completas de memoria.
2404259b007fSCarlos Bilbao
2405259b007fSCarlos Bilbao
2406259b007fSCarlos Bilbao========================================
2407259b007fSCarlos BilbaoEFECTOS DE BARRERA ADQUIRIENDO INTRA-CPU
2408259b007fSCarlos Bilbao========================================
2409259b007fSCarlos Bilbao
2410259b007fSCarlos BilbaoEn los sistemas SMP, las primitivas de bloqueo proveen una forma más
2411259b007fSCarlos Bilbaosustancial de barrera: una que afecta el orden de acceso a la memoria en
2412259b007fSCarlos Bilbaootras CPU, dentro del contexto de conflicto en cualquier bloqueo en
2413259b007fSCarlos Bilbaoparticular.
2414259b007fSCarlos Bilbao
2415259b007fSCarlos Bilbao
2416259b007fSCarlos BilbaoADQUISICIÓN VS ACCESOS A MEMORIA
2417259b007fSCarlos Bilbao--------------------------------
2418259b007fSCarlos Bilbao
2419259b007fSCarlos BilbaoConsidere lo siguiente: el sistema tiene un par de spinlocks (M) y (Q), y
2420259b007fSCarlos Bilbaotres CPU; entonces la siguiente secuencia de eventos debería ocurrir:
2421259b007fSCarlos Bilbao
2422259b007fSCarlos Bilbao	CPU 1				CPU 2
2423259b007fSCarlos Bilbao	===============================	===============================
2424259b007fSCarlos Bilbao	WRITE_ONCE(*A, a);		WRITE_ONCE(*E, e);
2425259b007fSCarlos Bilbao	ACQUIRE M			ACQUIRE Q
2426259b007fSCarlos Bilbao	WRITE_ONCE(*B, b);		WRITE_ONCE(*F, f);
2427259b007fSCarlos Bilbao	WRITE_ONCE(*C, c);		WRITE_ONCE(*G, g);
2428259b007fSCarlos Bilbao	RELEASE M			RELEASE Q
2429259b007fSCarlos Bilbao	WRITE_ONCE(*D, d);		WRITE_ONCE(*H, h);
2430259b007fSCarlos Bilbao
2431259b007fSCarlos BilbaoEntonces no hay garantía sobre en qué orden verá la CPU 3 los accesos a *A
2432259b007fSCarlos Bilbaohasta que *H ocurra, además de las restricciones impuestas por los bloqueos
2433259b007fSCarlos Bilbaoseparados en las distintas CPUs. Podría, por ejemplo, ver:
2434259b007fSCarlos Bilbao
2435259b007fSCarlos Bilbao	*E, ACQUIRE M, ACQUIRE Q, *G, *C, *F, *A, *B, RELEASE Q, *D, *H, RELEASE M
2436259b007fSCarlos Bilbao
2437259b007fSCarlos BilbaoPero no verá ninguno de:
2438259b007fSCarlos Bilbao
2439259b007fSCarlos Bilbao	*B, *C or *D preceding ACQUIRE M
2440259b007fSCarlos Bilbao	*A, *B or *C following RELEASE M
2441259b007fSCarlos Bilbao	*F, *G or *H preceding ACQUIRE Q
2442259b007fSCarlos Bilbao	*E, *F or *G following RELEASE Q
2443259b007fSCarlos Bilbao
2444259b007fSCarlos Bilbao========================================
2445259b007fSCarlos Bilbao¿DÓNDE SE NECESITAN BARRERAS DE MEMORIA?
2446259b007fSCarlos Bilbao========================================
2447259b007fSCarlos Bilbao
2448259b007fSCarlos BilbaoBajo operación normal, el re-ordenamiento de una operación de memoria
2449259b007fSCarlos Bilbaogeneralmente no va a suponer un problema, ya que para una pieza de código
2450259b007fSCarlos Bilbaolineal de un solo subproceso seguirá pareciendo que funciona correctamente,
2451259b007fSCarlos Bilbaoincluso si está en un kernel SMP. Existen, sin embargo, cuatro
2452259b007fSCarlos Bilbaocircunstancias en las que reordenar definitivamente _podría_ ser un
2453259b007fSCarlos Bilbaoproblema:
2454259b007fSCarlos Bilbao
2455259b007fSCarlos Bilbao (*) Interacción entre procesadores.
2456259b007fSCarlos Bilbao
2457259b007fSCarlos Bilbao (*) Operaciones atómicas.
2458259b007fSCarlos Bilbao
2459259b007fSCarlos Bilbao (*) Acceso a dispositivos.
2460259b007fSCarlos Bilbao
2461259b007fSCarlos Bilbao (*) Interrupciones.
2462259b007fSCarlos Bilbao
2463259b007fSCarlos Bilbao
2464259b007fSCarlos BilbaoINTERACCIÓN ENTRE PROCESADORES
2465259b007fSCarlos Bilbao------------------------------
2466259b007fSCarlos Bilbao
2467259b007fSCarlos BilbaoCuando se da un sistema con más de un procesador, más de una CPU en el
2468259b007fSCarlos Bilbaosistema puede estar trabajando en el mismo conjunto de datos al mismo
2469259b007fSCarlos Bilbaotiempo. Esto puede causar problemas de sincronización, y la forma habitual
2470259b007fSCarlos Bilbaode tratar con estos es utilizar cerrojos. Sin embargo, los cerrojos son
2471259b007fSCarlos Bilbaobastante caros, por lo que puede ser preferible operar sin el uso de un
2472259b007fSCarlos Bilbaocerrojo a ser posible. En cuyo caso, es posible que las operaciones que
2473259b007fSCarlos Bilbaoafectan a ambas CPU deban ordenarse cuidadosamente para evitar un
2474259b007fSCarlos Bilbaofuncionamiento incorrecto.
2475259b007fSCarlos Bilbao
2476259b007fSCarlos BilbaoConsidere, por ejemplo, la ruta lenta del semáforo R/W. Aquí hay un proceso
2477259b007fSCarlos Bilbaode espera en cola del semáforo, en virtud de que tiene una parte de su pila
2478259b007fSCarlos Bilbaovinculada a la lista de procesos en espera del semáforo:
2479259b007fSCarlos Bilbao
2480259b007fSCarlos Bilbao	struct rw_semaphore {
2481259b007fSCarlos Bilbao		...
2482259b007fSCarlos Bilbao		spinlock_t lock;
2483259b007fSCarlos Bilbao		struct list_head waiters;
2484259b007fSCarlos Bilbao	};
2485259b007fSCarlos Bilbao
2486259b007fSCarlos Bilbao	struct rwsem_waiter {
2487259b007fSCarlos Bilbao		struct list_head list;
2488259b007fSCarlos Bilbao		struct task_struct *task;
2489259b007fSCarlos Bilbao	};
2490259b007fSCarlos Bilbao
2491259b007fSCarlos BilbaoPara despertar a un proceso que espera ("waiter") en particular, las
2492259b007fSCarlos Bilbaofunciones up_read() o up_write() tienen que:
2493259b007fSCarlos Bilbao
2494259b007fSCarlos Bilbao (1) leer el siguiente puntero del registro de este proceso que espera,
2495259b007fSCarlos Bilbao     para saber dónde está el registro del siguiente waiter;
2496259b007fSCarlos Bilbao
2497259b007fSCarlos Bilbao (2) leer el puntero a la estructura de tareas del waiter;
2498259b007fSCarlos Bilbao
2499259b007fSCarlos Bilbao (3) borrar el puntero de la tarea para decirle al waiter que se le ha dado
2500259b007fSCarlos Bilbao     el semáforo;
2501259b007fSCarlos Bilbao
2502259b007fSCarlos Bilbao (4) llamar a wake_up_process() en la tarea; y
2503259b007fSCarlos Bilbao
2504259b007fSCarlos Bilbao (5) liberar la referencia retenida en la estructura de tareas del waiter.
2505259b007fSCarlos Bilbao
2506259b007fSCarlos BilbaoEn otras palabras, tiene que realizar esta secuencia de eventos:
2507259b007fSCarlos Bilbao
2508259b007fSCarlos Bilbao	LOAD waiter->list.next;
2509259b007fSCarlos Bilbao	LOAD waiter->task;
2510259b007fSCarlos Bilbao	STORE waiter->task;
2511259b007fSCarlos Bilbao	CALL wakeup
2512259b007fSCarlos Bilbao	RELEASE task
2513259b007fSCarlos Bilbao
2514259b007fSCarlos Bilbaoy si alguno de estos pasos ocurre fuera de orden, entonces todo puede que
2515259b007fSCarlos Bilbaofuncione defectuosamente.
2516259b007fSCarlos Bilbao
2517259b007fSCarlos BilbaoUna vez que se ha puesto en cola y soltado el bloqueo de semáforo, el
2518259b007fSCarlos Bilbaoproceso que espera no consigue el candado de nuevo; en cambio, solo espera
2519259b007fSCarlos Bilbaoa que se borre su puntero de tarea antes de continuar. Dado que el registro
2520259b007fSCarlos Bilbaoestá en la pila del proceso que espera, esto significa que si el puntero de
2521259b007fSCarlos Bilbaola tarea se borra _antes_ de que se lea el siguiente puntero de la lista,
2522259b007fSCarlos Bilbaootra CPU podría comenzar a procesar el proceso que espera y podría romper
2523259b007fSCarlos Bilbaoel stack del proceso que espera antes de que la función up*() tenga la
2524259b007fSCarlos Bilbaooportunidad de leer el puntero que sigue.
2525259b007fSCarlos Bilbao
2526259b007fSCarlos BilbaoConsidere entonces lo que podría suceder con la secuencia de eventos
2527259b007fSCarlos Bilbaoanterior:
2528259b007fSCarlos Bilbao
2529259b007fSCarlos Bilbao	CPU 1				CPU 2
2530259b007fSCarlos Bilbao	===============================	===============================
2531259b007fSCarlos Bilbao					down_xxx()
2532259b007fSCarlos Bilbao					Poner waiter en la "queue" (cola)
2533259b007fSCarlos Bilbao					Dormir
2534259b007fSCarlos Bilbao	up_yyy()
2535259b007fSCarlos Bilbao	LOAD waiter->task;
2536259b007fSCarlos Bilbao	STORE waiter->task;
2537259b007fSCarlos Bilbao					Despertado por otro evento
2538259b007fSCarlos Bilbao	<preempt>
2539259b007fSCarlos Bilbao					Reanudar el procesamiento
2540259b007fSCarlos Bilbao					down_xxx() regresa
2541259b007fSCarlos Bilbao					llamada a foo()
2542259b007fSCarlos Bilbao					foo() estropea *waiter
2543259b007fSCarlos Bilbao	</preempt>
2544259b007fSCarlos Bilbao	LOAD waiter->list.next;
2545259b007fSCarlos Bilbao	--- OOPS ---
2546259b007fSCarlos Bilbao
2547259b007fSCarlos BilbaoEsto podría solucionarse usando el bloqueo de semáforo, pero luego la
2548259b007fSCarlos Bilbaofunción down_xxx() tiene que obtener innecesariamente el spinlock
2549259b007fSCarlos Bilbaonuevamente, después de ser despertado el hilo.
2550259b007fSCarlos Bilbao
2551259b007fSCarlos BilbaoLa forma de lidiar con esto es insertar una barrera de memoria SMP general:
2552259b007fSCarlos Bilbao
2553259b007fSCarlos Bilbao	LOAD waiter->list.next;
2554259b007fSCarlos Bilbao	LOAD waiter->task;
2555259b007fSCarlos Bilbao	smp_mb();
2556259b007fSCarlos Bilbao	STORE waiter->task;
2557259b007fSCarlos Bilbao	CALL wakeup
2558259b007fSCarlos Bilbao	RELEASE task
2559259b007fSCarlos Bilbao
2560259b007fSCarlos BilbaoEn este caso, la barrera garantiza que todos los accesos a memoria antes de
2561259b007fSCarlos Bilbaola barrera parecerán suceder antes de todos los accesos a memoria después
2562259b007fSCarlos Bilbaode dicha barrera con respecto a las demás CPU del sistema. _No_ garantiza
2563259b007fSCarlos Bilbaoque todos los accesos a memoria antes de la barrera se completarán en el
2564259b007fSCarlos Bilbaomomento en que la instrucción de la barrera en sí se complete.
2565259b007fSCarlos Bilbao
2566259b007fSCarlos BilbaoEn un sistema UP, donde esto no sería un problema, la función smp_mb() es
2567259b007fSCarlos Bilbaosolo una barrera del compilador, asegurándose así de que el compilador
2568259b007fSCarlos Bilbaoemita las instrucciones en el orden correcto sin realmente intervenir en la
2569259b007fSCarlos BilbaoCPU. Como solo hay un CPU, la lógica de orden de dependencias de esa CPU se
2570259b007fSCarlos Bilbaoencargará de todo lo demás.
2571259b007fSCarlos Bilbao
2572259b007fSCarlos Bilbao
2573259b007fSCarlos BilbaoOPERACIONES ATÓMICAS
2574259b007fSCarlos Bilbao--------------------
2575259b007fSCarlos Bilbao
2576259b007fSCarlos BilbaoSi bien son, técnicamente, consideraciones de interacción entre
2577259b007fSCarlos Bilbaoprocesadores, las operaciones atómicas se destacan especialmente porque
2578259b007fSCarlos Bilbaoalgunas de ellas implican barreras de memoria completa y algunas otras no,
2579259b007fSCarlos Bilbaopero se confía mucho en ellos en su conjunto a lo largo del kernel.
2580259b007fSCarlos Bilbao
2581259b007fSCarlos BilbaoConsulte Documentation/atomic_t.txt para obtener más información.
2582259b007fSCarlos Bilbao
2583259b007fSCarlos Bilbao
2584259b007fSCarlos BilbaoACCESO A DISPOSITIVOS
2585259b007fSCarlos Bilbao---------------------
2586259b007fSCarlos Bilbao
2587259b007fSCarlos BilbaoUn driver puede ser interrumpido por su propia rutina de servicio de
2588259b007fSCarlos Bilbaointerrupción y, por lo tanto, las dos partes del driver pueden interferir
2589259b007fSCarlos Bilbaocon los intentos de controlar o acceder al dispositivo.
2590259b007fSCarlos Bilbao
2591259b007fSCarlos BilbaoEsto puede aliviarse, al menos en parte, desactivando las interrupciones
2592259b007fSCarlos Bilbaolocales (una forma de bloqueo), de modo que las operaciones críticas sean
2593259b007fSCarlos Bilbaotodas contenidas dentro la sección de interrupción desactivada en el
2594259b007fSCarlos Bilbaocontrolador. Mientras la interrupción del driver está ejecutando la rutina,
2595259b007fSCarlos Bilbaoes posible que el "core" del controlador no se ejecute en la misma CPU y no
2596259b007fSCarlos Bilbaose permita que su interrupción vuelva a ocurrir hasta que la interrupción
2597259b007fSCarlos Bilbaoactual haya sido resuelta, por lo tanto, el controlador de interrupción no
2598259b007fSCarlos Bilbaonecesita bloquearse contra esto.
2599259b007fSCarlos Bilbao
2600259b007fSCarlos BilbaoSin embargo, considere un driver que estaba hablando con una tarjeta
2601259b007fSCarlos Bilbaoethernet que tiene un registro de direcciones y un registro de datos. Si
2602259b007fSCarlos Bilbaoel core de ese controlador habla con la tarjeta estando en desactivación de
2603259b007fSCarlos Bilbaointerrupción y luego se invoca el controlador de interrupción del
2604259b007fSCarlos Bilbaocontrolador:
2605259b007fSCarlos Bilbao
2606259b007fSCarlos Bilbao	IRQ LOCALES DESACTIVADAS
2607259b007fSCarlos Bilbao	writew(ADDR, 3);
2608259b007fSCarlos Bilbao	writew(DATA, y);
2609259b007fSCarlos Bilbao	IRQ LOCALES ACTIVADAS
2610259b007fSCarlos Bilbao	<interrupción>
2611259b007fSCarlos Bilbao	writew(ADDR, 4);
2612259b007fSCarlos Bilbao	q = readw(DATA);
2613259b007fSCarlos Bilbao	</interrupción>
2614259b007fSCarlos Bilbao
2615259b007fSCarlos BilbaoEl almacenamiento en el registro de datos puede ocurrir después del segundo
2616259b007fSCarlos Bilbaoalmacenamiento en el registro de direcciones si las reglas de orden son lo
2617259b007fSCarlos Bilbaosuficientemente relajadas:
2618259b007fSCarlos Bilbao
2619259b007fSCarlos Bilbao  	STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA
2620259b007fSCarlos Bilbao
2621259b007fSCarlos BilbaoSi se relajan las reglas de orden, se debe asumir que los accesos
2622259b007fSCarlos Bilbaorealizados dentro de la sección con interrupción deshabilitada pueden
2623259b007fSCarlos Bilbaofiltrarse fuera de esta y pueden intercalarse con accesos realizados en una
2624259b007fSCarlos Bilbaointerrupción - y viceversa - a menos que se utilicenn barreras implícita o
2625259b007fSCarlos Bilbaoexplícitas.
2626259b007fSCarlos Bilbao
2627259b007fSCarlos BilbaoNormalmente, esto no será un problema porque los accesos de E/S realizados
2628259b007fSCarlos Bilbaodentro de tales secciones incluirán operaciones de carga síncronas en
2629259b007fSCarlos Bilbaoregistros E/S estrictamente ordenados, que forman barreras de E/S
2630259b007fSCarlos Bilbaoimplícitas.
2631259b007fSCarlos Bilbao
2632259b007fSCarlos Bilbao
2633259b007fSCarlos BilbaoUna situación similar puede ocurrir entre una rutina de interrupción y dos
2634259b007fSCarlos Bilbaorutinas ejecutándose en separadas CPU que se comunican entre sí. Si tal
2635259b007fSCarlos Bilbaocaso es probable, entonces se deben usar bloqueos de desactivación de
2636259b007fSCarlos Bilbaointerrupciones para garantizar el orden.
2637259b007fSCarlos Bilbao
2638259b007fSCarlos Bilbao
2639259b007fSCarlos Bilbao=====================================
2640259b007fSCarlos Bilbao Efectos de barrera de E/S del kernel
2641259b007fSCarlos Bilbao=====================================
2642259b007fSCarlos Bilbao
2643259b007fSCarlos BilbaoLa interfaz con periféricos a través de accesos de E/S es profundamente
2644259b007fSCarlos Bilbaoespecífica para cada arquitectura y dispositivo. Por lo tanto, los drivers
2645259b007fSCarlos Bilbaoque son inherentemente no portátiles pueden depender de comportamientos
2646259b007fSCarlos Bilbaoespecíficos de sus sistemas de destino, con el fin de lograr la
2647259b007fSCarlos Bilbaosincronización de la manera más ligera posible. Para drivers que deseen ser
2648259b007fSCarlos Bilbaoportátiles entre múltiples arquitecturas e implementaciones de bus, el
2649259b007fSCarlos Bilbaokernel ofrece una serie de funciones de acceso que proporcionan varios
2650259b007fSCarlos Bilbaogrados de garantías de orden:
2651259b007fSCarlos Bilbao
2652259b007fSCarlos Bilbao (*) readX(), writeX():
2653259b007fSCarlos Bilbao
2654259b007fSCarlos Bilbao	Las funciones de acceso MMIO readX() y writeX() usan un puntero al
2655259b007fSCarlos Bilbao	periférico al que se accede como un parámetro __iomem *. para punteros
2656259b007fSCarlos Bilbao	asignados los atributos de E/S predeterminados (por ejemplo, los
2657259b007fSCarlos Bilbao        devueltos por ioremap()), las garantías de orden son las siguientes:
2658259b007fSCarlos Bilbao
2659259b007fSCarlos Bilbao	1. Se ordenan todos los accesos readX() y writeX() a un mismo periférico
2660259b007fSCarlos Bilbao	   entre estos. Esto asegura que los registros de acceso MMIO por el
2661259b007fSCarlos Bilbao	   mismo subproceso de la CPU a un dispositivo en particular llegarán en
2662259b007fSCarlos Bilbao	   el orden del programa.
2663259b007fSCarlos Bilbao
2664259b007fSCarlos Bilbao	2. Se ordena un writeX() emitido por un subproceso de CPU que contiene un
2665259b007fSCarlos Bilbao	   spinlock antes de un writeX() al mismo periférico desde otro
2666259b007fSCarlos Bilbao           subproceso de CPU, si emitido después de una adquisición posterior del
2667259b007fSCarlos Bilbao	   mismo spinlock. Esto garantiza que ese registro MMIO escribe en un
2668259b007fSCarlos Bilbao           dispositivo en particular, mientras que se obtiene un spinlock en un
2669259b007fSCarlos Bilbao           orden consistente con las adquisiciones del cerrojo.
2670259b007fSCarlos Bilbao
2671259b007fSCarlos Bilbao	3. Un writeX() por un subproceso de la CPU al periférico primero esperará
2672259b007fSCarlos Bilbao	   a la finalización de todas las escrituras anteriores en la memoria
2673259b007fSCarlos Bilbao           emitidas por, o bien propagadas por, el mismo subproceso. Esto asegura
2674259b007fSCarlos Bilbao	   que las escrituras de la CPU a un búfer DMA de salida asignadas por
2675259b007fSCarlos Bilbao           dma_alloc_coherent() serán visibles para un motor ("engine") DMA
2676259b007fSCarlos Bilbao           cuando la CPU escriba en sus registros de control MMIO, para activar
2677259b007fSCarlos Bilbao           la transferencia.
2678259b007fSCarlos Bilbao
2679259b007fSCarlos Bilbao	4. Un readX() de un subproceso del CPU, desde el periférico, se
2680259b007fSCarlos Bilbao	   completará antes de que cualquier lectura subsiguiente de memoria por
2681259b007fSCarlos Bilbao	   el mismo subproceso pueda comenzar. Esto asegura que las lecturas de
2682259b007fSCarlos Bilbao           la CPU desde un búfer DMA entrantes asignadas por
2683259b007fSCarlos Bilbao           dma_alloc_coherent(), no verán datos obsoletos después de leer el
2684259b007fSCarlos Bilbao           registro de estado MMIO del motor DMA, para establecer que la
2685259b007fSCarlos Bilbao           transferencia DMA se haya completado.
2686259b007fSCarlos Bilbao
2687259b007fSCarlos Bilbao	5. Un readX() por un subproceso del CPU, desde el periférico, se
2688259b007fSCarlos Bilbao	   completará antes de que cualquier bucle delay() subsiguiente pueda
2689259b007fSCarlos Bilbao           comenzar a ejecutarse en el mismo subproceso. Esto asegura que dos
2690259b007fSCarlos Bilbao           escrituras del CPU a registros MMIO en un periférico llegarán al menos
2691259b007fSCarlos Bilbao	   con 1us de diferencia, si la primera escritura se lee inmediatamente
2692259b007fSCarlos Bilbao           de vuelta con readX() y se llama a udelay(1) antes del segundo
2693259b007fSCarlos Bilbao           writeX():
2694259b007fSCarlos Bilbao
2695259b007fSCarlos Bilbao		writel(42, DEVICE_REGISTER_0); // Llega al dispositivo ...
2696259b007fSCarlos Bilbao		readl(DEVICE_REGISTER_0);
2697259b007fSCarlos Bilbao		udelay(1);
2698259b007fSCarlos Bilbao		writel(42, DEVICE_REGISTER_1); // al menos 1us antes de esto....
2699259b007fSCarlos Bilbao
2700259b007fSCarlos BilbaoLas propiedades de orden de los punteros __iomem obtenidos con valores de
2701259b007fSCarlos Bilbaoatributos que no sean los valores por defecto (por ejemplo, los devueltos
2702259b007fSCarlos Bilbaopor ioremap_wc()) son específicos de la arquitectura subyacente y, por lo
2703259b007fSCarlos Bilbaotanto, las garantías enumeradas anteriormente no pueden por lo general ser
2704259b007fSCarlos Bilbaoaseguradas para accesos a este tipo de "mappings" (asignaciones).
2705259b007fSCarlos Bilbao
2706259b007fSCarlos Bilbao (*) readX_relaxed(), writeX_relaxed():
2707259b007fSCarlos Bilbao
2708259b007fSCarlos Bilbao	Son similares a readX() y writeX(), pero proporcionan una garantía de
2709259b007fSCarlos Bilbao        orden de memoria más débil. Específicamente, no garantizan orden con
2710259b007fSCarlos Bilbao	respecto al bloqueo, los accesos normales a la memoria o los bucles
2711259b007fSCarlos Bilbao        delay() (es decir, los puntos 2-5 arriba) pero todavía se garantiza que
2712259b007fSCarlos Bilbao        se ordenarán con respecto a otros accesos desde el mismo hilo de la CPU,
2713259b007fSCarlos Bilbao        al mismo periférico, cuando se opera en punteros __iomem asignados con el
2714259b007fSCarlos Bilbao        valor predeterminado para los atributos de E/S.
2715259b007fSCarlos Bilbao
2716259b007fSCarlos Bilbao (*) readsX(), writesX():
2717259b007fSCarlos Bilbao
2718259b007fSCarlos Bilbao	Los puntos de entrada readsX() y writesX() MMIO están diseñados para
2719259b007fSCarlos Bilbao        acceder FIFOs mapeados en memoria y basados en registros que residen en
2720259b007fSCarlos Bilbao        periféricos, que no son capaces de realizar DMA. Por tanto, sólo
2721259b007fSCarlos Bilbao        proporcionan garantías de orden readX_relaxed() y writeX_relaxed(), como
2722259b007fSCarlos Bilbao        se documentó anteriormente.
2723259b007fSCarlos Bilbao
2724259b007fSCarlos Bilbao (*) inX(), outX():
2725259b007fSCarlos Bilbao
2726259b007fSCarlos Bilbao	Los puntos de entrada inX() y outX() están destinados a acceder a mapas
2727259b007fSCarlos Bilbao        de puertos "legacy" (antiguos) de periféricos de E/S, que pueden requerir
2728259b007fSCarlos Bilbao	instrucciones especiales en algunas arquitecturas (especialmente, en
2729259b007fSCarlos Bilbao        x86). El número de puerto del periférico que se está accedido se pasa
2730259b007fSCarlos Bilbao        como un argumento.
2731259b007fSCarlos Bilbao
2732259b007fSCarlos Bilbao	Dado que muchas arquitecturas de CPU acceden finalmente a estos
2733259b007fSCarlos Bilbao        periféricos a través de un mapeo interno de memoria virtual, las
2734259b007fSCarlos Bilbao        garantías de orden portátiles proporcionadas por inX() y outX() son las
2735259b007fSCarlos Bilbao        mismas que las proporcionadas por readX() y writeX(), respectivamente, al
2736259b007fSCarlos Bilbao        acceder a una asignación con los valores de atributos de E/S
2737259b007fSCarlos Bilbao        predeterminados (los que haya por defecto).
2738259b007fSCarlos Bilbao
2739259b007fSCarlos Bilbao        Los drivers de dispositivos pueden esperar que outX() emita una
2740259b007fSCarlos Bilbao        transacción de escritura no publicada, que espera una respuesta de
2741259b007fSCarlos Bilbao        finalización del periférico de E/S antes de regresar. Esto no está
2742259b007fSCarlos Bilbao        garantizado por todas las arquitecturas y por lo tanto no forma parte de
2743259b007fSCarlos Bilbao        la semántica de orden portátil.
2744259b007fSCarlos Bilbao
2745259b007fSCarlos Bilbao (*) insX(), outsX():
2746259b007fSCarlos Bilbao
2747259b007fSCarlos Bilbao        Como arriba, los puntos de entrada insX() y outsX() proporcionan el mismo
2748259b007fSCarlos Bilbao        orden garantizado por readsX() y writesX() respectivamente, al acceder a
2749259b007fSCarlos Bilbao        un mapping con los atributos de E/S predeterminados.
2750259b007fSCarlos Bilbao
2751259b007fSCarlos Bilbao (*) ioreadX(), iowriteX():
2752259b007fSCarlos Bilbao
2753259b007fSCarlos Bilbao        Estos funcionarán adecuadamente para el tipo de acceso que realmente están
2754259b007fSCarlos Bilbao        haciendo, ya sea inX()/outX() o readX()/writeX().
2755259b007fSCarlos Bilbao
2756259b007fSCarlos BilbaoCon la excepción de los puntos de entrada (insX(), outsX(), readsX() y
2757259b007fSCarlos BilbaowritesX()), todo lo anterior supone que el periférico subyacente es
2758259b007fSCarlos Bilbaolittle-endian y, por lo tanto, realizará operaciones de intercambio de
2759259b007fSCarlos Bilbaobytes en arquitecturas big-endian.
2760259b007fSCarlos Bilbao
2761259b007fSCarlos Bilbao
2762259b007fSCarlos Bilbao===========================================
2763259b007fSCarlos BilbaoMODELO DE ORDEN MÍNIMO DE EJECUCIÓN ASUMIDO
2764259b007fSCarlos Bilbao===========================================
2765259b007fSCarlos Bilbao
2766259b007fSCarlos BilbaoDebe suponerse que la CPU conceptual está débilmente ordenada, pero que
2767259b007fSCarlos Bilbaomantiene la apariencia de causalidad del programa con respecto a sí misma.
2768259b007fSCarlos BilbaoAlgunas CPU (como i386 o x86_64) están más limitadas que otras (como
2769259b007fSCarlos Bilbaopowerpc o frv), por lo que el caso más relajado (es decir, DEC Alpha) se
2770259b007fSCarlos Bilbaodebe asumir fuera de código específico de arquitectura.
2771259b007fSCarlos Bilbao
2772259b007fSCarlos BilbaoEsto significa que se debe considerar que la CPU ejecutará su flujo de
2773259b007fSCarlos Bilbaoinstrucciones en el orden que se quiera - o incluso en paralelo - siempre
2774259b007fSCarlos Bilbaoque si una instrucción en el flujo depende de una instrucción anterior,
2775259b007fSCarlos Bilbaoentonces dicha instrucción anterior debe ser lo suficientemente completa[*]
2776259b007fSCarlos Bilbaoantes de que la posterior instrucción puede proceder; en otras palabras:
2777259b007fSCarlos Bilbaosiempre que la apariencia de causalidad se mantenga.
2778259b007fSCarlos Bilbao
2779259b007fSCarlos Bilbao [*] Algunas instrucciones tienen más de un efecto, como cambiar el
2780259b007fSCarlos Bilbao     código de condición, cambio de registros o cambio de memoria - y
2781259b007fSCarlos Bilbao     distintas instrucciones pueden depender de diferentes efectos.
2782259b007fSCarlos Bilbao
2783259b007fSCarlos BilbaoUna CPU puede también descartar cualquier secuencia de instrucciones que
2784259b007fSCarlos Bilbaotermine sin tener efecto final. Por ejemplo, si dos instrucciones
2785259b007fSCarlos Bilbaoadyacentes cargan un valor inmediato en el mismo registro, la primera puede
2786259b007fSCarlos Bilbaodescartarse.
2787259b007fSCarlos Bilbao
2788259b007fSCarlos Bilbao
2789259b007fSCarlos BilbaoDe manera similar, se debe suponer que el compilador podría reordenar la
2790259b007fSCarlos Bilbaocorriente de instrucciones de la manera que crea conveniente, nuevamente
2791259b007fSCarlos Bilbaosiempre que la apariencia de causalidad se mantenga.
2792259b007fSCarlos Bilbao
2793259b007fSCarlos Bilbao
2794259b007fSCarlos Bilbao=====================================
2795259b007fSCarlos BilbaoEFECTOS DE LA MEMORIA CACHÉ DE LA CPU
2796259b007fSCarlos Bilbao=====================================
2797259b007fSCarlos Bilbao
2798259b007fSCarlos BilbaoLa forma en que se perciben las operaciones de memoria caché en todo el
2799259b007fSCarlos Bilbaosistema se ve afectada, hasta cierto punto, por los cachés que se
2800259b007fSCarlos Bilbaoencuentran entre las CPU y la memoria, y por el sistema de coherencia en
2801259b007fSCarlos Bilbaomemoria que mantiene la consistencia de estado en el sistema.
2802259b007fSCarlos Bilbao
2803259b007fSCarlos BilbaoEn cuanto a la forma en que una CPU interactúa con otra parte del sistema a
2804259b007fSCarlos Bilbaotravés del caché, el sistema de memoria tiene que incluir los cachés de la
2805259b007fSCarlos BilbaoCPU y barreras de memoria, que en su mayor parte actúan en la interfaz
2806259b007fSCarlos Bilbaoentre la CPU y su caché (las barreras de memoria lógicamente actúan sobre
2807259b007fSCarlos Bilbaola línea de puntos en el siguiente diagrama):
2808259b007fSCarlos Bilbao
2809259b007fSCarlos Bilbao	    <--- CPU --->         :       <----------- Memoria ----------->
2810259b007fSCarlos Bilbao	                          :
2811259b007fSCarlos Bilbao	+--------+    +--------+  :   +--------+    +-----------+
2812259b007fSCarlos Bilbao	|  Core  |    | Cola   |  :   | Cache  |    |           |    +---------+
2813259b007fSCarlos Bilbao	|  CPU   |    | de     |  :   | CPU    |    |           |    |         |
2814259b007fSCarlos Bilbao	|        |--->| acceso |----->|        |<-->|           |    |         |
2815259b007fSCarlos Bilbao	|        |    | a      |  :   |        |    |           |--->| Memoria |
2816259b007fSCarlos Bilbao	|        |    | memoria|  :   |        |    |           |    |         |
2817259b007fSCarlos Bilbao	+--------+    +--------+  :   +--------+    | Mecanismo |    |         |
2818259b007fSCarlos Bilbao	                          :                 | de        |    +---------+
2819259b007fSCarlos Bilbao	                          :                 | Coherencia|
2820259b007fSCarlos Bilbao	                          :                 | de la     |    +--------+
2821259b007fSCarlos Bilbao	+--------+    +--------+  :   +--------+    | cache     |    |	      |
2822259b007fSCarlos Bilbao	|  Core  |    | Cola   |  :   | Cache  |    |           |    |        |
2823259b007fSCarlos Bilbao	|  CPU   |    | de     |  :   | CPU    |    |           |--->| Dispos |
2824259b007fSCarlos Bilbao	|        |--->| acceso |----->|        |<-->|           |    | itivo  |
2825259b007fSCarlos Bilbao	|        |    | a      |  :   |        |    |           |    |        |
2826259b007fSCarlos Bilbao	|        |    | memoria|  :   |        |    |           |    +--------+
2827259b007fSCarlos Bilbao	+--------+    +--------+  :   +--------+    +-----------+
2828259b007fSCarlos Bilbao	                          :
2829259b007fSCarlos Bilbao	                          :
2830259b007fSCarlos Bilbao
2831259b007fSCarlos BilbaoAunque es posible que una carga o store en particular no aparezca fuera de
2832259b007fSCarlos Bilbaola CPU que lo emitió, ya que puede haber sido satisfecha dentro del propio
2833259b007fSCarlos Bilbaocaché de la CPU, seguirá pareciendo como si el acceso total a la memoria
2834259b007fSCarlos Bilbaohubiera tenido lugar para las otras CPUs, ya que los mecanismos de
2835259b007fSCarlos Bilbaocoherencia de caché migrarán la cacheline sobre la CPU que accede y se
2836259b007fSCarlos Bilbaopropagarán los efectos en caso de conflicto.
2837259b007fSCarlos Bilbao
2838259b007fSCarlos BilbaoEl núcleo de la CPU puede ejecutar instrucciones en el orden que considere
2839259b007fSCarlos Bilbaoadecuado, siempre que parezca mantenerse la causalidad esperada del
2840259b007fSCarlos Bilbaoprograma. Algunas de las instrucciones generan operaciones de carga y
2841259b007fSCarlos Bilbaoalmacenamiento que luego van a la cola de accesos a memoria a realizar. El
2842259b007fSCarlos Bilbaonúcleo puede colocarlos en la cola en cualquier orden que desee, y
2843259b007fSCarlos Bilbaocontinuar su ejecución hasta que se vea obligado a esperar que una
2844259b007fSCarlos Bilbaoinstrucción sea completada.
2845259b007fSCarlos Bilbao
2846259b007fSCarlos BilbaoDe lo que se ocupan las barreras de la memoria es de controlar el orden en
2847259b007fSCarlos Bilbaoque los accesos cruzan, desde el lado de la CPU, hasta el lado de memoria,
2848259b007fSCarlos Bilbaoy el orden en que los otros observadores perciben los efectos en el sistema
2849259b007fSCarlos Bilbaoque sucedan por esto.
2850259b007fSCarlos Bilbao
2851259b007fSCarlos Bilbao[!] Las barreras de memoria _no_ son necesarias dentro de una CPU
2852259b007fSCarlos Bilbaodeterminada, ya que las CPU siempre ven sus propias cargas y stores como si
2853259b007fSCarlos Bilbaohubieran sucedido en el orden del programa.
2854259b007fSCarlos Bilbao
2855259b007fSCarlos Bilbao[!] Los accesos a MMIO u otros dispositivos pueden pasar por alto el
2856259b007fSCarlos Bilbaosistema de caché. Esto depende de las propiedades de la ventana de memoria
2857259b007fSCarlos Bilbaoa través de la cual se accede a los dispositivos y/o el uso de
2858259b007fSCarlos Bilbaoinstrucciones especiales de comunicación con dispositivo que pueda tener la
2859259b007fSCarlos BilbaoCPU.
2860259b007fSCarlos Bilbao
2861259b007fSCarlos Bilbao
2862259b007fSCarlos BilbaoCOHERENCIA DE CACHÉ FRENTE A DMA
2863259b007fSCarlos Bilbao---------------------------------
2864259b007fSCarlos Bilbao
2865259b007fSCarlos BilbaoNo todos los sistemas mantienen coherencia de caché con respecto a los
2866259b007fSCarlos Bilbaodispositivos que realizan DMA. En tales casos, un dispositivo que intente
2867259b007fSCarlos BilbaoDMA puede obtener datos obsoletos de la RAM, porque las líneas de caché
2868259b007fSCarlos Bilbao"sucias" pueden residir en los cachés de varias CPU, y es posible que no
2869259b007fSCarlos Bilbaose hayan vuelto a escribir en la RAM todavía. Para hacer frente a esto, la
2870259b007fSCarlos Bilbaoparte apropiada del kernel debe vaciar los bits superpuestos de caché en
2871259b007fSCarlos Bilbaocada CPU (y tal vez también invalidarlos).
2872259b007fSCarlos Bilbao
2873259b007fSCarlos BilbaoAdemás, los datos enviados por DMA a RAM, por un dispositivo, pueden ser
2874259b007fSCarlos Bilbaosobrescritos por líneas de caché sucias que se escriben de nuevo en la RAM
2875259b007fSCarlos Bilbaodesde el caché de una CPU, después de que el dispositivo haya puesto sus
2876259b007fSCarlos Bilbaopropios datos, o las líneas de caché presentes en el caché de la CPU pueden
2877259b007fSCarlos Bilbaosimplemente ocultar el hecho de que la memoria RAM se haya actualizado,
2878259b007fSCarlos Bilbaohasta el momento en que la caché se descarta de la memoria caché de la CPU
2879259b007fSCarlos Bilbaoy se vuelve a cargar. Para hacer frente a esto, la parte apropiada del
2880259b007fSCarlos Bilbaokernel debe invalidar los bits superpuestos del caché en cada CPU.
2881259b007fSCarlos Bilbao
2882259b007fSCarlos BilbaoConsulte Documentation/core-api/cachetlb.rst para obtener más información
2883259b007fSCarlos Bilbaosobre administración de la memoria caché.
2884259b007fSCarlos Bilbao
2885259b007fSCarlos Bilbao
2886259b007fSCarlos BilbaoCOHERENCIA DE CACHÉ FRENTE A MMIO
2887259b007fSCarlos Bilbao---------------------------------
2888259b007fSCarlos Bilbao
2889259b007fSCarlos BilbaoLa E/S mapeada en memoria generalmente se lleva a cabo a través de
2890259b007fSCarlos Bilbaoubicaciones de memoria que forman parte de una ventana del espacio de
2891259b007fSCarlos Bilbaomemoria de la CPU, que tiene diferentes propiedades asignadas que la
2892259b007fSCarlos Bilbaoventana habitual dirigida a RAM.
2893259b007fSCarlos Bilbao
2894259b007fSCarlos BilbaoEntre dichas propiedades, suele existir el hecho de que tales accesos
2895259b007fSCarlos Bilbaoeluden el almacenamiento en caché por completo e ir directamente a los
2896259b007fSCarlos Bilbaobuses del dispositivo. Esto significa que los accesos MMIO pueden, en
2897259b007fSCarlos Bilbaoefecto, superar los accesos a la memoria caché que se emitieron
2898259b007fSCarlos Bilbaoanteriormente. Una barrera de memoria no es suficiente en tal caso, sino
2899259b007fSCarlos Bilbaoque el caché debe ser vaciado entre la escritura de la memoria caché, y el
2900259b007fSCarlos Bilbaoacceso MMIO, si los dos son de cualquier manera dependiente.
2901259b007fSCarlos Bilbao
2902259b007fSCarlos Bilbao
2903259b007fSCarlos Bilbao=======================
2904259b007fSCarlos BilbaoCOSAS QUE HACEN LAS CPU
2905259b007fSCarlos Bilbao=======================
2906259b007fSCarlos Bilbao
2907259b007fSCarlos BilbaoUn programador podría dar por sentado que la CPU realizará las operaciones
2908259b007fSCarlos Bilbaode memoria exactamente en el orden especificado, de modo que si a la CPU se
2909259b007fSCarlos Bilbaoentrega, por ejemplo, el siguiente fragmento de código a ejecutar:
2910259b007fSCarlos Bilbao
2911259b007fSCarlos Bilbao	a = READ_ONCE(*A);
2912259b007fSCarlos Bilbao	WRITE_ONCE(*B, b);
2913259b007fSCarlos Bilbao	c = READ_ONCE(*C);
2914259b007fSCarlos Bilbao	d = READ_ONCE(*D);
2915259b007fSCarlos Bilbao	WRITE_ONCE(*E, e);
2916259b007fSCarlos Bilbao
2917259b007fSCarlos Bilbaoesperarían entonces que la CPU complete la operación de memoria para cada
2918259b007fSCarlos Bilbaoinstrucción antes de pasar a la siguiente, lo que lleva a una definida
2919259b007fSCarlos Bilbaosecuencia de operaciones vistas por observadores externos en el sistema:
2920259b007fSCarlos Bilbao
2921259b007fSCarlos Bilbao  	LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.
2922259b007fSCarlos Bilbao
2923259b007fSCarlos BilbaoLa realidad es, por supuesto, mucho más intrincada. Para muchas CPU y
2924259b007fSCarlos Bilbaocompiladores, la anterior suposición no se sostiene porque:
2925259b007fSCarlos Bilbao
2926259b007fSCarlos Bilbao (*) es más probable que las cargas deban completarse de inmediato para
2927259b007fSCarlos Bilbao     permitir progreso en la ejecución, mientras que los stores a menudo se
2928259b007fSCarlos Bilbao     pueden aplazar sin problema;
2929259b007fSCarlos Bilbao
2930259b007fSCarlos Bilbao (*) las cargas se pueden hacer especulativamente, y el resultado es
2931259b007fSCarlos Bilbao     descartado si resulta innecesario;
2932259b007fSCarlos Bilbao
2933259b007fSCarlos Bilbao (*) las cargas se pueden hacer de forma especulativa, lo que lleva a que
2934259b007fSCarlos Bilbao     se haya obtenido el resultado en el momento equivocado de la secuencia
2935259b007fSCarlos Bilbao     de eventos esperada;
2936259b007fSCarlos Bilbao
2937259b007fSCarlos Bilbao (*) el orden de los accesos a memoria se puede reorganizar para promover
2938259b007fSCarlos Bilbao     un mejor uso de los buses y cachés de la CPU;
2939259b007fSCarlos Bilbao
2940259b007fSCarlos Bilbao (*) las cargas y los stores se pueden combinar para mejorar el rendimiento
2941259b007fSCarlos Bilbao     cuando se habla con memoria o hardware de E/S, que puede realizar
2942259b007fSCarlos Bilbao     accesos por lotes a ubicaciones adyacentes, reduciendo así los costes
2943259b007fSCarlos Bilbao     de configuración de transacciones (la memoria y los dispositivos PCI
2944259b007fSCarlos Bilbao     pueden ambos pueden hacer esto); y
2945259b007fSCarlos Bilbao
2946259b007fSCarlos Bilbao (*) la caché de datos de la CPU puede afectar al orden, y mientras sus
2947259b007fSCarlos Bilbao     mecanismos de coherencia pueden aliviar esto, una vez que el store
2948259b007fSCarlos Bilbao     haya accedido al caché- no hay garantía de que la gestión de la
2949259b007fSCarlos Bilbao     coherencia se propague en orden a otras CPU.
2950259b007fSCarlos Bilbao
2951259b007fSCarlos BilbaoEntonces, digamos que lo que otra CPU podría observar en el fragmento de
2952259b007fSCarlos Bilbaocódigo anterior es:
2953259b007fSCarlos Bilbao
2954259b007fSCarlos Bilbao	LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B
2955259b007fSCarlos Bilbao
2956259b007fSCarlos Bilbao	(Donde "LOAD {*C,*D}" es una carga combinada)
2957259b007fSCarlos Bilbao
2958259b007fSCarlos Bilbao
2959259b007fSCarlos BilbaoSin embargo, se garantiza que una CPU es autoconsistente: verá que sus
2960259b007fSCarlos Bilbao _propios_ accesos parecen estar correctamente ordenados, sin necesidad de
2961259b007fSCarlos Bilbaobarrera de memoria. Por ejemplo con el siguiente código:
2962259b007fSCarlos Bilbao
2963259b007fSCarlos Bilbao	U = READ_ONCE(*A);
2964259b007fSCarlos Bilbao	WRITE_ONCE(*A, V);
2965259b007fSCarlos Bilbao	WRITE_ONCE(*A, W);
2966259b007fSCarlos Bilbao	X = READ_ONCE(*A);
2967259b007fSCarlos Bilbao	WRITE_ONCE(*A, Y);
2968259b007fSCarlos Bilbao	Z = READ_ONCE(*A);
2969259b007fSCarlos Bilbao
2970259b007fSCarlos Bilbaoy asumiendo que no hay intervención de una influencia externa, se puede
2971259b007fSCarlos Bilbaosuponer que el resultado final se parecerá a:
2972259b007fSCarlos Bilbao
2973259b007fSCarlos Bilbao	U == el valor original de *A
2974259b007fSCarlos Bilbao	X == W
2975259b007fSCarlos Bilbao	Z == Y
2976259b007fSCarlos Bilbao	*A == Y
2977259b007fSCarlos Bilbao
2978259b007fSCarlos BilbaoEl código anterior puede hacer que la CPU genere la secuencia completa de
2979259b007fSCarlos Bilbaoaccesos de memoria:
2980259b007fSCarlos Bilbao
2981259b007fSCarlos Bilbao	U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A
2982259b007fSCarlos Bilbao
2983259b007fSCarlos Bilbaoen ese orden, pero, sin intervención, la secuencia puede contener casi
2984259b007fSCarlos Bilbaocualquier combinación de elementos combinados o descartados, siempre que la
2985259b007fSCarlos Bilbaoperspectiva del programa del mundo siga siendo consistente. Tenga en cuenta
2986259b007fSCarlos Bilbaoque READ_ONCE() y WRITE_ONCE() -no- son opcionales en el ejemplo anterior,
2987259b007fSCarlos Bilbaoya que hay arquitecturas donde una CPU determinada podría reordenar cargas
2988259b007fSCarlos Bilbaosucesivas en la misma ubicación. En tales arquitecturas, READ_ONCE() y
2989259b007fSCarlos BilbaoWRITE_ONCE() hacen lo que sea necesario para evitar esto, por ejemplo, en
2990259b007fSCarlos BilbaoItanium los casts volátiles utilizados por READ_ONCE() y WRITE_ONCE() hacen
2991259b007fSCarlos Bilbaoque GCC emita las instrucciones especiales ld.acq y st.rel
2992259b007fSCarlos Bilbao(respectivamente) que impiden dicha reordenación.
2993259b007fSCarlos Bilbao
2994259b007fSCarlos BilbaoEl compilador también puede combinar, descartar o diferir elementos de la
2995259b007fSCarlos Bilbaosecuencia antes incluso de que la CPU los vea.
2996259b007fSCarlos Bilbao
2997259b007fSCarlos BilbaoPor ejemplo:
2998259b007fSCarlos Bilbao
2999259b007fSCarlos Bilbao	*A = V;
3000259b007fSCarlos Bilbao	*A = W;
3001259b007fSCarlos Bilbao
3002259b007fSCarlos Bilbaopuede reducirse a:
3003259b007fSCarlos Bilbao
3004259b007fSCarlos Bilbao	*A = W;
3005259b007fSCarlos Bilbao
3006259b007fSCarlos Bilbaoya que, sin una barrera de escritura o WRITE_ONCE(), puede que se asuma
3007259b007fSCarlos Bilbaoque el efecto del almacenamiento de V a *A se pierde. Similarmente:
3008259b007fSCarlos Bilbao
3009259b007fSCarlos Bilbao  	*A = Y;
3010259b007fSCarlos Bilbao  	Z = *A;
3011259b007fSCarlos Bilbao
3012259b007fSCarlos Bilbaopuede, sin una barrera de memoria o un READ_ONCE() y WRITE_ONCE(), esto
3013259b007fSCarlos Bilbaosea reducido a:
3014259b007fSCarlos Bilbao
3015259b007fSCarlos Bilbao  	*A = Y;
3016259b007fSCarlos Bilbao  	Z = Y;
3017259b007fSCarlos Bilbao
3018259b007fSCarlos Bilbaoy la operación LOAD nunca aparezca fuera de la CPU.
3019259b007fSCarlos Bilbao
3020259b007fSCarlos Bilbao
3021259b007fSCarlos BilbaoY LUEGO ESTÁ EL ALFA
3022259b007fSCarlos Bilbao--------------------
3023259b007fSCarlos Bilbao
3024259b007fSCarlos BilbaoLa CPU DEC Alpha es una de las CPU más relajadas que existen. No solo eso,
3025259b007fSCarlos Bilbaoalgunas versiones de la CPU Alpha tienen un caché de datos dividido, lo que
3026259b007fSCarlos Bilbaoles permite tener dos líneas de caché relacionadas semánticamente,
3027259b007fSCarlos Bilbaoactualizadas en momentos separados. Aquí es donde la barrera de dependencia
3028259b007fSCarlos Bilbaode dirección realmente se vuelve necesaria, ya que se sincronizan ambos
3029259b007fSCarlos Bilbaocachés con el sistema de coherencia de memoria, lo que hace que parezca un
3030259b007fSCarlos Bilbaocambio en el puntero, frente a que los nuevos datos se produzcan en el
3031259b007fSCarlos Bilbaoorden correcto.
3032259b007fSCarlos Bilbao
3033259b007fSCarlos BilbaoAlpha define el modelo de memoria del kernel Linux, aunque a partir de
3034259b007fSCarlos Bilbaov4.15, la adición al kernel de Linux de smp_mb() a READ_ONCE() en Alpha
3035259b007fSCarlos Bilbaoredujo en gran medida su impacto en el modelo de memoria.
3036259b007fSCarlos Bilbao
3037259b007fSCarlos Bilbao
3038259b007fSCarlos BilbaoGUESTS DE MÁQUINAS VIRTUALES
3039259b007fSCarlos Bilbao-----------------------------
3040259b007fSCarlos Bilbao
3041259b007fSCarlos BilbaoLos "guests" (invitados) que se ejecutan en máquinas virtuales pueden verse
3042259b007fSCarlos Bilbaoafectados por los efectos de SMP incluso si el "host" (huésped) en sí se
3043259b007fSCarlos Bilbaocompila sin compatibilidad con SMP. Este es un efecto de la interacción con
3044259b007fSCarlos Bilbaoun host SMP mientras ejecuta un kernel UP. El uso obligatorio de barreras
3045259b007fSCarlos Bilbaopara este caso de uso sería posible, pero a menudo no son óptimas.
3046259b007fSCarlos Bilbao
3047259b007fSCarlos BilbaoPara hacer frente a este caso de manera óptima, están disponibles macros de
3048259b007fSCarlos Bilbaobajo nivel virt_mb() etc. Estas tienen el mismo efecto que smp_mb(), etc.
3049259b007fSCarlos Bilbaocuando SMP está habilitado, pero generan código idéntico para sistemas SMP
3050259b007fSCarlos Bilbaoy no SMP. Por ejemplo, los invitados de máquinas virtuales debería usar
3051259b007fSCarlos Bilbaovirt_mb() en lugar de smp_mb() al sincronizar contra un (posiblemente SMP)
3052259b007fSCarlos Bilbaoanfitrión.
3053259b007fSCarlos Bilbao
3054259b007fSCarlos BilbaoEstos son equivalentes a sus contrapartes smp_mb() etc. en todos los demás
3055259b007fSCarlos Bilbaoaspectos, en particular, no controlan los efectos MMIO: para controlar los
3056259b007fSCarlos Bilbaoefectos MMIO, utilice barreras obligatorias.
3057259b007fSCarlos Bilbao
3058259b007fSCarlos Bilbao
3059259b007fSCarlos Bilbao================
3060259b007fSCarlos BilbaoEJEMPLOS DE USOS
3061259b007fSCarlos Bilbao================
3062259b007fSCarlos Bilbao
3063259b007fSCarlos BilbaoBUFFERS CIRCULARES
3064259b007fSCarlos Bilbao------------------
3065259b007fSCarlos Bilbao
3066259b007fSCarlos BilbaoLas barreras de memoria se pueden utilizar para implementar almacenamiento
3067259b007fSCarlos Bilbaoen búfer circular, sin necesidad de un cerrojo para serializar al productor
3068259b007fSCarlos Bilbaocon el consumidor. Vea:
3069259b007fSCarlos Bilbao
3070259b007fSCarlos Bilbao	Documentation/core-api/circular-buffers.rst
3071259b007fSCarlos Bilbao
3072259b007fSCarlos Bilbaopara más detalles.
3073259b007fSCarlos Bilbao
3074259b007fSCarlos Bilbao
3075259b007fSCarlos Bilbao===========
3076259b007fSCarlos BilbaoREFERENCIAS
3077259b007fSCarlos Bilbao===========
3078259b007fSCarlos Bilbao
3079259b007fSCarlos BilbaoAlpha AXP Architecture Reference Manual, Segunda Edición (por Sites & Witek,
3080259b007fSCarlos BilbaoDigital Press)
3081259b007fSCarlos Bilbao	Capítulo 5.2: Physical Address Space Characteristics
3082259b007fSCarlos Bilbao	Capítulo 5.4: Caches and Write Buffers
3083259b007fSCarlos Bilbao	Capítulo 5.5: Data Sharing
3084259b007fSCarlos Bilbao	Capítulo 5.6: Read/Write Ordering
3085259b007fSCarlos Bilbao
3086259b007fSCarlos BilbaoAMD64 Architecture Programmer's Manual Volumen 2: System Programming
3087259b007fSCarlos Bilbao	Capítulo 7.1: Memory-Access Ordering
3088259b007fSCarlos Bilbao	Capítulo 7.4: Buffering and Combining Memory Writes
3089259b007fSCarlos Bilbao
3090259b007fSCarlos BilbaoARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
3091259b007fSCarlos Bilbao	Capítulo B2: The AArch64 Application Level Memory Model
3092259b007fSCarlos Bilbao
3093259b007fSCarlos BilbaoIA-32 Intel Architecture Software Developer's Manual, Volumen 3:
3094259b007fSCarlos BilbaoSystem Programming Guide
3095259b007fSCarlos Bilbao	Capítulo 7.1: Locked Atomic Operations
3096259b007fSCarlos Bilbao	Capítulo 7.2: Memory Ordering
3097259b007fSCarlos Bilbao	Capítulo 7.4: Serializing Instructions
3098259b007fSCarlos Bilbao
3099259b007fSCarlos BilbaoThe SPARC Architecture Manual, Version 9
3100259b007fSCarlos Bilbao	Capítulo 8: Memory Models
3101259b007fSCarlos Bilbao	Appendix D: Formal Specification of the Memory Models
3102259b007fSCarlos Bilbao	Appendix J: Programming with the Memory Models
3103259b007fSCarlos Bilbao
3104259b007fSCarlos BilbaoStorage in the PowerPC (por Stone and Fitzgerald)
3105259b007fSCarlos Bilbao
3106259b007fSCarlos BilbaoUltraSPARC Programmer Reference Manual
3107259b007fSCarlos Bilbao	Capítulo 5: Memory Accesses and Cacheability
3108259b007fSCarlos Bilbao	Capítulo 15: Sparc-V9 Memory Models
3109259b007fSCarlos Bilbao
3110259b007fSCarlos BilbaoUltraSPARC III Cu User's Manual
3111259b007fSCarlos Bilbao	Capítulo 9: Memory Models
3112259b007fSCarlos Bilbao
3113259b007fSCarlos BilbaoUltraSPARC IIIi Processor User's Manual
3114259b007fSCarlos Bilbao	Capítulo 8: Memory Models
3115259b007fSCarlos Bilbao
3116259b007fSCarlos BilbaoUltraSPARC Architecture 2005
3117259b007fSCarlos Bilbao	Capítulo 9: Memory
3118259b007fSCarlos Bilbao	Appendix D: Formal Specifications of the Memory Models
3119259b007fSCarlos Bilbao
3120259b007fSCarlos BilbaoUltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
3121259b007fSCarlos Bilbao	Capítulo 8: Memory Models
3122259b007fSCarlos Bilbao	Appendix F: Caches and Cache Coherency
3123259b007fSCarlos Bilbao
3124259b007fSCarlos BilbaoSolaris Internals, Core Kernel Architecture, p63-68:
3125259b007fSCarlos Bilbao	Capítulo 3.3: Hardware Considerations for Locks and
3126259b007fSCarlos Bilbao			Synchronization
3127259b007fSCarlos Bilbao
3128259b007fSCarlos BilbaoUnix Systems for Modern Architectures, Symmetric Multiprocessing and Caching
3129259b007fSCarlos Bilbaofor Kernel Programmers:
3130259b007fSCarlos Bilbao	Capítulo 13: Other Memory Models
3131259b007fSCarlos Bilbao
3132259b007fSCarlos BilbaoIntel Itanium Architecture Software Developer's Manual: Volumen 1:
3133259b007fSCarlos Bilbao	Sección 2.6: Speculation
3134259b007fSCarlos Bilbao	Sección 4.4: Memory Access
3135