brintos

brintos / linux-shallow public Read only

0
0
Text · 123.8 KiB · 153e571 Raw
3135 lines · plain
1NOTE:2This is a version of Documentation/memory-barriers.txt translated into3Spanish by Carlos Bilbao <carlos.bilbao.osdev@gmail.com>. If you find any4difference between this document and the original file or a problem with5the translation, please contact the maintainer of this file. Please also6note that the purpose of this file is to be easier to read for non English7(read: Spanish) speakers and is not intended as a fork. So if you have any8comments or updates for this file please update the original English file9first. The English version is definitive, and readers should look there if10they have any doubt.11 12			 ======================================13			 BARRERAS DE MEMORIA EN EL KERNEL LINUX14			 ======================================15 16Documento original: David Howells <dhowells@redhat.com>17    Paul E. McKenney <paulmck@linux.ibm.com>18    Will Deacon <will.deacon@arm.com>19    Peter Zijlstra <peterz@infradead.org>20 21Traducido por: Carlos Bilbao <carlos.bilbao.osdev@gmail.com>22Nota: Si tiene alguna duda sobre la exactitud del contenido de esta23traducción, la única referencia válida es la documentación oficial en24inglés.25 26===========27ADVERTENCIA28===========29 30Este documento no es una especificación; es intencionalmente (por motivos31de brevedad) y sin querer (por ser humanos) incompleta. Este documento32pretende ser una guía para usar las diversas barreras de memoria33proporcionadas por Linux, pero ante cualquier duda (y hay muchas) por favor34pregunte. Algunas dudas pueden ser resueltas refiriéndose al modelo de35consistencia de memoria formal y documentación en tools/memory-model/. Sin36embargo, incluso este modelo debe ser visto como la opinión colectiva de37sus maintainers en lugar de que como un oráculo infalible.38 39De nuevo, este documento no es una especificación de lo que Linux espera40del hardware.41 42El propósito de este documento es doble:43 44 (1) especificar la funcionalidad mínima en la que se puede confiar para45     cualquier barrera en concreto, y46 47 (2) proporcionar una guía sobre cómo utilizar las barreras disponibles.48 49Tenga en cuenta que una arquitectura puede proporcionar más que el50requisito mínimo para cualquier barrera en particular, pero si la51arquitectura proporciona menos de eso, dicha arquitectura es incorrecta.52 53Tenga en cuenta también que es posible que una barrera no valga (sea no-op)54para alguna arquitectura porque por la forma en que funcione dicha55arquitectura, la barrera explícita resulte innecesaria en ese caso.56 57==========58CONTENIDOS59==========60 61 (*) Modelo abstracto de acceso a memoria.62 63     - Operaciones del dispositivo.64     - Garantías.65 66 (*) ¿Qué son las barreras de memoria?67 68     - Variedades de barrera de memoria.69     - ¿Qué no se puede asumir sobre las barreras de memoria?70     - Barreras de dirección-dependencia (históricas).71     - Dependencias de control.72     - Emparejamiento de barreras smp.73     - Ejemplos de secuencias de barrera de memoria.74     - Barreras de memoria de lectura frente a especulación de carga.75     - Atomicidad multicopia.76 77 (*) Barreras explícitas del kernel.78 79     - Barrera del compilador.80     - Barreras de memoria de la CPU.81 82 (*) Barreras de memoria implícitas del kernel.83 84     - Funciones de adquisición de cerrojo.85     - Funciones de desactivación de interrupciones.86     - Funciones de dormir y despertar.87     - Funciones varias.88 89 (*) Efectos de barrera adquiriendo intra-CPU.90 91     - Adquisición vs accesos a memoria.92 93 (*) ¿Dónde se necesitan barreras de memoria?94 95     - Interacción entre procesadores.96     - Operaciones atómicas.97     - Acceso a dispositivos.98     - Interrupciones.99 100 (*) Efectos de barrera de E/S del kernel.101 102 (*) Modelo de orden mínimo de ejecución asumido.103 104 (*) Efectos de la memoria caché de la CPU.105 106     - Coherencia de caché.107     - Coherencia de caché frente a DMA.108     - Coherencia de caché frente a MMIO.109 110 (*) Cosas que hacen las CPU.111 112     - Y luego está el Alfa.113     - Guests de máquinas virtuales.114 115 (*) Ejemplos de usos.116 117     - Buffers circulares.118 119 (*) Referencias.120 121 122====================================123MODELO ABSTRACTO DE ACCESO A MEMORIA124====================================125 126Considere el siguiente modelo abstracto del sistema:127 128		            :                :129		            :                :130		            :                :131		+-------+   :   +--------+   :   +-------+132		|       |   :   |        |   :   |       |133		|       |   :   |        |   :   |       |134		| CPU 1 |<----->| Memoria|<----->| CPU 2 |135		|       |   :   |        |   :   |       |136		|       |   :   |        |   :   |       |137		+-------+   :   +--------+   :   +-------+138		    ^       :       ^        :       ^139		    |       :       |        :       |140		    |       :       |        :       |141		    |       :       v        :       |142		    |       :   +--------+   :       |143		    |       :   |        |   :       |144		    |       :   | Disposi|   :       |145		    +---------->| tivo   |<----------+146		            :   |        |   :147		            :   |        |   :148		            :   +--------+   :149		            :                :150 151Cada CPU ejecuta un programa que genera operaciones de acceso a la memoria.152En la CPU abstracta, el orden de las operaciones de memoria es muy153relajado, y una CPU en realidad puede realizar las operaciones de memoria154en el orden que desee, siempre que la causalidad del programa parezca155mantenerse. De manera similar, el compilador también puede organizar las156instrucciones que emite en el orden que quiera, siempre que no afecte al157funcionamiento aparente del programa.158 159Entonces, en el diagrama anterior, los efectos de las operaciones de160memoria realizadas por un CPU son percibidos por el resto del sistema a161medida que las operaciones cruzan la interfaz entre la CPU y el resto del162sistema (las líneas discontinuas a puntos).163 164Por ejemplo, considere la siguiente secuencia de eventos:165 166	CPU 1		CPU 2167	===============	===============168	{ A == 1; B == 2 }169	A = 3;		x = B;170	B = 4;		y = A;171 172El conjunto de accesos visto por el sistema de memoria en el medio se puede173organizar en 24 combinaciones diferentes (donde LOAD es cargar y STORE es174guardar):175 176STORE A=3,	STORE B=4,	y=LOAD A->3,	x=LOAD B->4177STORE A=3,	STORE B=4,	x=LOAD B->4,	y=LOAD A->3178STORE A=3,	y=LOAD A->3,	STORE B=4,	x=LOAD B->4179STORE A=3,	y=LOAD A->3,	x=LOAD B->2,	STORE B=4180STORE A=3,	x=LOAD B->2,	STORE B=4,	y=LOAD A->3181STORE A=3,	x=LOAD B->2,	y=LOAD A->3,	STORE B=4182STORE B=4,	STORE A=3,	y=LOAD A->3,	x=LOAD B->4183STORE B=4, ...184...185 186y por lo tanto puede resultar en cuatro combinaciones diferentes de187valores:188 189x == 2, y == 1190x == 2, y == 3191x == 4, y == 1192x == 4, y == 3193 194Además, los stores asignados por una CPU al sistema de memoria pueden no195ser percibidos por los loads realizados por otra CPU en el mismo orden en196que fueron realizados.197 198Como otro ejemplo, considere esta secuencia de eventos:199 200	CPU 1		CPU 2201	===============	===============202	{ A == 1, B == 2, C == 3, P == &A, Q == &C }203	B = 4;		Q = P;204	P = &B;		D = *Q;205 206Aquí hay una dependencia obvia de la dirección, ya que el valor cargado en207D depende en la dirección recuperada de P por la CPU 2. Al final de la208secuencia, cualquiera de los siguientes resultados son posibles:209 210  (Q == &A) y (D == 1)211  (Q == &B) y (D == 2)212  (Q == &B) y (D == 4)213 214Tenga en cuenta que la CPU 2 nunca intentará cargar C en D porque la CPU215cargará P en Q antes de emitir la carga de *Q.216 217OPERACIONES DEL DISPOSITIVO218---------------------------219 220Algunos dispositivos presentan sus interfaces de control como colecciones221de ubicaciones de memoria, pero el orden en que se accede a los registros222de control es muy importante. Por ejemplo, imagine una tarjeta ethernet con223un conjunto de registros a los que se accede a través de un registro de224puerto de dirección (A) y un registro de datos del puerto (D). Para leer el225registro interno 5, el siguiente código podría entonces ser usado:226 227  *A = 5;228  x = *D;229 230pero esto podría aparecer como cualquiera de las siguientes dos secuencias:231 232  STORE *A = 5, x = LOAD *D233  x = LOAD *D, STORE *A = 5234 235el segundo de las cuales casi con certeza resultará en mal funcionamiento,236ya que se estableció la dirección _después_ de intentar leer el registro.237 238 239GARANTÍAS240---------241 242Hay algunas garantías mínimas que se pueden esperar de una CPU:243 244 (*) En cualquier CPU dada, los accesos a la memoria dependiente se245     emitirán en orden, con respeto a sí mismo. Esto significa que para:246 247	Q = READ_ONCE(P); D = READ_ONCE(*Q);248 249     donde READ_ONCE() es LEER_UNA_VEZ(), la CPU emitirá las siguientes250     operaciones de memoria:251 252	Q = LOAD P, D = LOAD *Q253 254     y siempre en ese orden. Sin embargo, en DEC Alpha, READ_ONCE() también255     emite una instrucción de barrera de memoria, de modo que una CPU DEC256     Alpha, sin embargo emite las siguientes operaciones de memoria:257 258	Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER259 260     Ya sea en DEC Alpha o no, READ_ONCE() también evita que el compilador261     haga cosas inapropiadas.262 263 (*) Los loads y stores superpuestos dentro de una CPU en particular264     parecerán ser ordenados dentro de esa CPU. Esto significa que para:265 266	a = READ_ONCE(*X); WRITE_ONCE(*X, b);267 268     donde WRITE_ONCE() es ESCRIBIR_UNA_VEZ(), la CPU solo emitirá la269     siguiente secuencia de operaciones de memoria:270 271	a = LOAD *X, STORE *X = b272 273     Y para:274 275	WRITE_ONCE(*X, c); d = READ_ONCE(*X);276 277     la CPU solo emitirá:278 279	STORE *X = c, d = LOAD *X280 281  (Los loads y stores se superponen si están destinados a piezas282  superpuestas de memoria).283 284Y hay una serie de cosas que _deben_ o _no_ deben asumirse:285 286 (*) _No_debe_ asumirse que el compilador hará lo que usted quiera287     con referencias de memoria que no están protegidas por READ_ONCE() y288     WRITE ONCE(). Sin ellos, el compilador tiene derecho a hacer todo tipo289     de transformaciones "creativas", que se tratan en la sección BARRERA290     DEL COMPILADOR.291 292   (*) _No_debe_ suponerse que se emitirán loads y stores independientes293       en el orden dado. Esto significa que para:294 295	X = *A; Y = *B; *D = Z;296 297     podemos obtener cualquiera de las siguientes secuencias:298 299    X = LOAD *A,  Y = LOAD *B,  STORE *D = Z300   	X = LOAD *A,  STORE *D = Z, Y = LOAD *B301   	Y = LOAD *B,  X = LOAD *A,  STORE *D = Z302   	Y = LOAD *B,  STORE *D = Z, X = LOAD *A303   	STORE *D = Z, X = LOAD *A,  Y = LOAD *B304   	STORE *D = Z, Y = LOAD *B,  X = LOAD *A305 306 (*) Se _debe_ suponer que los accesos de memoria superpuestos pueden307     fusionarse o ser descartados. Esto significa que para:308 309	X = *A; Y = *(A + 4);310 311  podemos obtener cualquiera de las siguientes secuencias:312 313X = LOAD *A; Y = LOAD *(A + 4);314Y = LOAD *(A + 4); X = LOAD *A;315{X, Y} = LOAD {*A, *(A + 4) };316 317  Y para:318 319*A = X; *(A + 4) = Y;320 321  podemos obtener cualquiera de:322 323STORE *A = X; STORE *(A + 4) = Y;324STORE *(A + 4) = Y; STORE *A = X;325STORE {*A, *(A + 4) } = {X, Y};326 327Y hay anti-garantías:328 329(*) Estas garantías no se aplican a los campos de bits, porque los330    compiladores a menudo generan código para modificarlos usando331    secuencias de lectura-modificación-escritura no atómica. No intente332    utilizar campos de bits para sincronizar algoritmos paralelos.333 334(*) Incluso en los casos en que los campos de bits están protegidos por335    cerrojos (o "cerrojos", o "locks"), todos los componentes en un campo336    de bits dado deben estar protegidos por un candado. Si dos campos en un337    campo de bits dado están protegidos por diferentes locks, las338    secuencias de lectura-modificación-escritura no atómicas del lock339    pueden causar una actualización a una campo para corromper el valor de340    un campo adyacente.341 342(*) Estas garantías se aplican solo a escalares correctamente alineados y343    dimensionados. De "tamaño adecuado" significa actualmente variables que344    son del mismo tamaño que "char", "short", "int" y "long".345    "Adecuadamente alineado" significa la alineación natural, por lo tanto,346    no hay restricciones para "char", alineación de dos bytes para "short",347    alineación de cuatro bytes para "int", y alineación de cuatro u ocho348    bytes para "long", en sistemas de 32 y 64 bits, respectivamente. Tenga349    en cuenta que estos garantías se introdujeron en el estándar C11, así350    que tenga cuidado cuando utilice compiladores anteriores a C11 (por351    ejemplo, gcc 4.6). La parte de la norma que contiene esta garantía es352    la Sección 3.14, que define "ubicación de memoria" de la siguiente353    manera:354 355    ubicación de memoria356  ya sea un objeto de tipo escalar, o una secuencia máxima357  de campos de bits adyacentes, todos con ancho distinto de cero358 359  NOTE 1: Dos hilos de ejecución pueden actualizar y acceder360  ubicaciones de memoria separadas sin interferir entre361  ellos.362 363  NOTE 2: Un campo de bits y un miembro adyacente que no es un campo de364  bits están en ubicaciones de memoria separadas. Lo mismo sucede con365  dos campos de bits, si uno se declara dentro de un declaración de366  estructura anidada y el otro no, o si las dos están separados por una367  declaración de campo de bits de longitud cero, o si están separados por368  un miembro no declarado como campo de bits. No es seguro actualizar369  simultáneamente dos campos de bits en la misma estructura si entre370  todos los miembros declarados también hay campos de bits, sin importar371  cuál resulta ser el tamaño de estos campos de bits intermedios.372 373 374==================================375¿QUÉ SON LAS BARRERAS DE MEMORIA?376==================================377 378Como se puede leer arriba, las operaciones independientes de memoria se379realizan de manera efectiva en orden aleatorio, pero esto puede ser un380problema para la interacción CPU-CPU y para la E/S ("I/O"). Lo que se381requiere es alguna forma de intervenir para instruir al compilador y al382CPU para restringir el orden.383 384Las barreras de memoria son este tipo de intervenciones. Imponen una385percepción de orden parcial, sobre las operaciones de memoria a ambos lados386de la barrera.387 388Tal cumplimiento es importante porque las CPUs y otros dispositivos en un389sistema pueden usar una variedad de trucos para mejorar el rendimiento,390incluido el reordenamiento, diferimiento y combinación de operaciones de391memoria; cargas especulativas; predicción de "branches" especulativos y392varios tipos de almacenamiento en caché. Las barreras de memoria se393utilizan para anular o suprimir estos trucos, permitiendo que el código394controle sensatamente la interacción de múltiples CPU y/o dispositivos.395 396 397VARIEDADES DE BARRERA DE MEMORIA398---------------------------------399 400Las barreras de memoria vienen en cuatro variedades básicas:401 402 (1) Barreras de memoria al escribir o almacenar (Write or store memory403     barriers).404 405     Una barrera de memoria de escritura garantiza que todas las406     operaciones de STORE especificadas antes de que la barrera aparezca407     suceden antes de todas las operaciones STORE especificadas después408     de la barrera, con respecto a los otros componentes del sistema.409 410     Una barrera de escritura es un orden parcial solo en los stores; No411     es requerido que tenga ningún efecto sobre los loads.412 413     Se puede considerar que una CPU envía una secuencia de operaciones de414     store al sistema de memoria a medida que pasa el tiempo. Todos los415     stores _antes_ de una barrera de escritura ocurrirán _antes_ de todos416     los stores después de la barrera de escritura.417 418     [!] Tenga en cuenta que las barreras de escritura normalmente deben419     combinarse con read o barreras de address-dependency barriers420     (dependencia de dirección); consulte la subsección421     "Emparejamiento de barreras smp".422 423 424 (2) Barrera de dependencia de dirección (histórico).425 426     Una barrera de dependencia de dirección es una forma más débil de427     barrera de lectura. En el caso de que se realicen dos loads de manera428     que la segunda dependa del resultado de la primera (por ejemplo: el429     primer load recupera la dirección a la que se dirigirá el segundo430     load), una barrera de dependencia de dirección sería necesaria para431     asegurarse de que el objetivo de la segunda carga esté actualizado432     después de acceder a la dirección obtenida por la primera carga.433 434     Una barrera de dependencia de direcciones es una ordenación parcial en435     laods de direcciones interdependientes; no se requiere que tenga436     ningún efecto en los stores, ya sean cargas de memoria o cargas437     de memoria superpuestas.438 439     Como se mencionó en (1), las otras CPU en el sistema pueden verse como440     secuencias de stores en el sistema de memoria que la considerada CPU441     puede percibir. Una barrera de dependencia de dirección emitida por442     la CPU en cuestión garantiza que para cualquier carga que la preceda,443     si esa carga toca alguna secuencia de stores de otra CPU, entonces444     en el momento en que la barrera se complete, los efectos de todos los445     stores antes del cambio del load serán perceptibles por cualquier446     carga emitida después la barrera de la dependencia de la dirección.447 448     Consulte la subsección "Ejemplos de secuencias de barrera de memoria"449     para ver los diagramas mostrando las restricciones de orden.450 451     [!] Tenga en cuenta que la primera carga realmente tiene que tener una452     dependencia de _dirección_ y no es una dependencia de control. Si la453     dirección para la segunda carga depende de la primera carga, pero la454     dependencia es a través de un condicional en lugar de -en realidad-455     cargando la dirección en sí, entonces es una dependencia de _control_456     y se requiere una barrera de lectura completa o superior. Consulte la457     subsección "Dependencias de control" para más información.458 459     [!] Tenga en cuenta que las barreras de dependencia de dirección460     normalmente deben combinarse con barreras de escritura; consulte la461     subsección "Emparejamiento de barreras smp".462 463     [!] Desde el kernel v5.9, se eliminó la API del kernel para barreras464     de memoria de direcciones explícitas. Hoy en día, las APIs para marcar465     cargas de variables compartidas, como READ_ONCE() y rcu_dereference(),466     proporcionan barreras de dependencia de dirección implícitas.467 468 (3) Barreras de memoria al leer o cargar (Read or load memory469    barriers).470 471     Una barrera de lectura es una barrera de dependencia de direcciones,472     más una garantía de que todas las operaciones de LOAD especificadas473     antes de la barrera parecerán ocurrir antes de todas las operaciones474     de LOAD especificadas después de la barrera con respecto a los demás475     componentes del sistema.476 477     Una barrera de lectura es un orden parcial solo en cargas; no es478     necesario que tenga ningún efecto en los stores.479 480     Las barreras de memoria de lectura implican barreras de dependencia de481     direcciones, y por tanto puede sustituirlas por estas.482 483     [!] Tenga en mente que las barreras de lectura normalmente deben484     combinarse con barreras de escritura; consulte la subsección485     "Emparejamiento de barreras smp".486 487 (4) Barreras de memoria generales488 489     Una barrera de memoria general proporciona la garantía de que todas490     las operaciones LOAD y STORE especificadas antes de que la barrera491     aparezca suceden antes de que todas las operaciones LOAD y STORE492     especificadas después de la barrera con respecto a los demás493     componentes del sistema.494 495     Una barrera de memoria general es un orden parcial tanto en496     operaciones de carga como de almacenamiento.497 498     Las barreras de memoria generales implican barreras de memoria tanto499     de lectura como de escritura, de modo que pueden sustituir a500     cualquiera.501 502Y un par de variedades implícitas:503 504 (5)  ACQUIRE (de adquisición).505 506     Esto actúa como una barrera permeable unidireccional. Garantiza que507     toda las operaciones de memoria después de la operación ACQUIRE508     parezcan suceder después de la ACQUIRE con respecto a los demás509     componentes del sistema. Las operaciones ACQUIRE incluyen operaciones510     LOCK y smp_load_acquire(), y operaciones smp_cond_load_acquire().511 512     Las operaciones de memoria que ocurren antes de una operación ACQUIRE513     pueden parecer suceder después de que se complete.514 515     Una operación ACQUIRE casi siempre debe estar emparejada con una516     operación RELEASE (de liberación).517 518 519 (6) Operaciones RELEASE (de liberación).520 521     Esto también actúa como una barrera permeable unidireccional.522     Garantiza que todas las operaciones de memoria antes de la operación523     RELEASE parecerán ocurrir antes de la operación RELEASE con respecto a524     los demás componentes del sistema. Las operaciones de RELEASE incluyen525     operaciones de UNLOCK y operaciones smp_store_release().526 527     Las operaciones de memoria que ocurren después de una operación528     RELEASE pueden parecer suceder antes de que se complete.529 530     El uso de las operaciones ACQUIRE y RELEASE generalmente excluye la531     necesidad de otros tipos de barrera de memoria. Además, un par532     RELEASE+ACQUIRE NO garantiza actuar como una barrera de memoria533     completa. Sin embargo, después de un ACQUIRE de una variable dada,534     todos los accesos a la memoria que preceden a cualquier anterior535     RELEASE en esa misma variable están garantizados como visibles. En536     otras palabras, dentro de la sección crítica de una variable dada,537     todos los accesos de todas las secciones críticas anteriores para esa538     variable habrán terminado de forma garantizada.539 540     Esto significa que ACQUIRE actúa como una operación mínima de541     "adquisición" y RELEASE actúa como una operación mínima de542     "liberación".543 544Un subconjunto de las operaciones atómicas descritas en atomic_t.txt545contiene variantes de ACQUIRE y RELEASE, además de definiciones546completamente ordenadas o relajadas (sin barrera semántica). Para547composiciones atómicas que realizan tanto un load como store, la semántica548ACQUIRE se aplica solo a la carga y la semántica RELEASE se aplica sólo a549la parte de la operación del store.550 551Las barreras de memoria solo son necesarias cuando existe la posibilidad de552interacción entre dos CPU o entre una CPU y un dispositivo. Si se puede553garantizar que no habrá tal interacción en ninguna pieza de código en554particular, entonces las barreras de memoria son innecesarias en ese555fragmento de código.556 557Tenga en cuenta que estas son las garantías _mínimas_. Diferentes558arquitecturas pueden proporcionar garantías más sustanciales, pero no se559puede confiar en estas fuera de esa arquitectura en específico.560 561 562¿QUÉ NO SE PUEDE ASUMIR SOBRE LAS BARRERAS DE LA MEMORIA?563---------------------------------------------------------564 565Hay ciertas cosas que las barreras de memoria del kernel Linux no566garantizan:567 568 (*) No hay garantía de que ninguno de los accesos a la memoria569     especificados antes de una barrera de memoria estará _completo_ al570     completarse una instrucción de barrera de memoria; se puede considerar571     que la barrera dibuja una línea en la cola de acceso del CPU que no572     pueden cruzar los accesos del tipo correspondiente.573 574 (*) No hay garantía de que la emisión de una barrera de memoria en una CPU575     tenga cualquier efecto directo en otra CPU o cualquier otro hardware576     en el sistema. El efecto indirecto será el orden en que la segunda CPU577     ve los efectos de los primeros accesos que ocurren de la CPU, pero lea578     el siguiente argumento:579 580 (*) No hay garantía de que una CPU vea el orden correcto de los efectos581     de los accesos de una segunda CPU, incluso _si_ la segunda CPU usa una582     barrera de memoria, a menos que la primera CPU _también_ use una583     barrera de memoria coincidente (vea el subapartado "Emparejamiento de584     barrera SMP").585 586 (*) No hay garantía de que alguna pieza intermedia fuera del hardware[*]587     del CPU no reordenará los accesos a la memoria. Los mecanismos de588     coherencia de caché del CPU deben propagar los efectos indirectos de589     una barrera de memoria entre las CPU, pero es posible que no lo hagan590     en orden.591 592	[*] Para obtener información sobre bus mastering DMA y coherencia, lea:593 594	    Documentation/driver-api/pci/pci.rst595	    Documentation/core-api/dma-api-howto.rst596	    Documentation/core-api/dma-api.rst597 598 599BARRERA DE DEPENDENCIA DE DIRECCIÓN (HISTÓRICO)600-----------------------------------------------601 602A partir de la versión 4.15 del kernel Linux, se agregó un smp_mb() a603READ_ONCE() para DEC Alpha, lo que significa que las únicas personas que604necesitan prestar atención a esta sección son aquellas que trabajan en el605código específico de la arquitectura DEC Alpha y aquellas que trabajan en606READ_ONCE() por dentro. Para aquellos que lo necesitan, y para aquellos que607estén interesados desde un punto de vista histórico, aquí está la historia608de las barreras de dependencia de dirección.609 610[!] Si bien las dependencias de direcciones se observan tanto en carga a611carga como en relaciones de carga a store, las barreras de dependencia de612dirección no son necesarias para situaciones de carga a store.613 614El requisito de las barreras de dependencia de dirección es un poco sutil,615y no siempre es obvio que sean necesarias. Para ilustrar, considere la616siguiente secuencia de eventos:617 618	CPU 1		      CPU 2619	===============	      ===============620	{ A == 1, B == 2, C == 3, P == &A, Q == &C }621	B = 4;622	<barrera de escritura>623	WRITE_ONCE(P, &B);624			      Q = READ_ONCE_OLD(P);625			      D = *Q;626 627[!] READ_ONCE_OLD() corresponde a READ_ONCE() del kernel anterior a 4.15,628que no implica una barrera de dependencia de direcciones.629 630Hay una clara dependencia de dirección aquí, y parecería que al final de631la secuencia, Q debe ser &A o &B, y que:632 633	(Q == &A) implica (D == 1)634	(Q == &B) implica (D == 4)635 636¡Pero! La percepción de la CPU 2 de P puede actualizarse _antes_ de su637percepción de B, por lo tanto dando lugar a la siguiente situación:638 639	(Q == &B) y (D == 2) ????640 641Si bien esto puede parecer una falla en el mantenimiento de la coherencia642o la causalidad, no lo es, y este comportamiento se puede observar en643ciertas CPU reales (como DEC Alfa).644 645Para lidiar con esto, READ_ONCE() proporciona una barrera de dependencia646de dirección implícita desde el lanzamiento del kernel v4.15:647 648	CPU 1		      CPU 2649	===============	      ===============650	{ A == 1, B == 2, C == 3, P == &A, Q == &C }651	B = 4;652	<barrera de escritura>653	WRITE_ONCE(P, &B);654			      Q = READ_ONCE(P);655			      <barrera de dependencia de dirección implícita>656			      D = *Q;657 658Esto refuerza la ocurrencia de una de las dos implicaciones, y previene la659tercera posibilidad de surgir.660 661 662[!] Tenga en cuenta que esta situación extremadamente contraria a la663intuición surge más fácilmente en máquinas con cachés divididos, de modo664que, por ejemplo, un banco de caché procesa líneas de caché pares y el otro665banco procesa líneas impares de caché. El puntero P podría almacenarse en666una línea de caché impar y la variable B podría almacenarse en una línea de667caché con número par. Entonces, si el banco de números pares de la memoria668caché de la CPU de lectura está extremadamente ocupado mientras que el669banco impar está inactivo, uno podría ver el nuevo valor del puntero P670(&B), pero el antiguo valor de la variable B (2).671 672 673No se requiere una barrera de dependencia de dirección para ordenar674escrituras dependientes porque las CPU que admite el kernel Linux no675escriben hasta que están seguros (1) de que la escritura realmente676sucederá, (2) de la ubicación de la escritura, y (3) del valor a escribir.677Pero, por favor, lea atentamente la sección "DEPENDENCIAS DEL CONTROL" y el678archivo Documentation/RCU/rcu_dereference.rst: el compilador puede romperse679y romper dependencias en muchas formas altamente creativas.680 681	CPU 1		      CPU 2682	===============	      ===============683	{ A == 1, B == 2, C = 3, P == &A, Q == &C }684	B = 4;685	<barrera de escritura>686	WRITE_ONCE(P, &B);687			      Q = READ_ONCE_OLD(P);688			      WRITE_ONCE(*Q, 5);689 690Por lo tanto, no se requiere ninguna barrera de dependencia de direcciones691para ordenar la lectura en Q con el load en *Q. En otras palabras, este692resultado está prohibido, incluso sin una barrera de dependencia de693dirección implícita del READ_ONCE() moderno:694 695	(Q == &B) && (B == 4)696 697Tenga en cuenta que este patrón debe ser raro. Después de todo, el objetivo698del orden de dependencia es -prevenir- escrituras en la estructura de699datos, junto con los costosos errores de caché asociados con tales700escrituras. Este patrón se puede utilizar para registrar raras condiciones701de error y similares, y el orden natural de las CPUs evita que se pierdan702tales registros.703 704 705Tenga en cuenta que el orden proporcionado por una dependencia de dirección706es local para la CPU que lo contiene. Lea la sección sobre "Atomicidad707multicopia" para más información.708 709 710La barrera de dependencia de dirección es muy importante para el sistema711RCU, por ejemplo. Vea rcu_assign_pointer() y rcu_dereference() en712include/linux/rcupdate.h. Esto permite que el objetivo actual de un puntero713RCU sea reemplazado con un nuevo objetivo modificado, sin que el objetivo714del reemplazo parezca estar inicializado de manera incompleta.715 716Consulte también la subsección sobre "Coherencia de caché" para obtener un717ejemplo más completo.718 719DEPENDENCIAS DE CONTROL720-----------------------721 722Las dependencias de control pueden ser un poco complicadas porque los723compiladores actuales no las entienden. El propósito de esta sección es724ayudarle a prevenir que la ignorancia del compilador rompa su código.725 726Una dependencia de control load-load (de carga a carga) requiere una727barrera de memoria de lectura completa, no simplemente una barrera728(implícita) de dependencia de direcciones para que funcione correctamente.729Considere el siguiente fragmento de código:730 731	q = READ_ONCE(a);732	<barrera implícita de dependencia de direcciones>733	if (q) {734		/* BUG: No hay dependencia de dirección!!! */735		p = READ_ONCE(b);736	}737 738Esto no tendrá el efecto deseado porque no hay una dependencia de dirección739real, sino más bien una dependencia de control que la CPU puede740cortocircuitar al intentar predecir el resultado por adelantado, para que741otras CPU vean la carga de b como si hubiera ocurrido antes que la carga de742a. En cuyo caso lo que realmente se requiere es:743 744  	q = READ_ONCE(a);745  	if (q) {746  		<barrera de lectura>747  		p = READ_ONCE(b);748  	}749 750Sin embargo, los stores no se especulan. Esto significa que ordenar -es-751provisto para dependencias de control de load-store, como en el siguiente752ejemplo:753 754	q = READ_ONCE(a);755	if (q) {756		WRITE_ONCE(b, 1);757	}758 759Las dependencias de control se emparejan normalmente con otros tipos de760barreras. Dicho esto, tenga en cuenta que ni READ_ONCE() ni WRITE_ONCE()761son opcionales! Sin READ_ONCE(), el compilador podría combinar la carga de762'a' con otras cargas de 'a'. Sin WRITE_ONCE(), el compilador podría763combinar el store de 'b' con otros stores de 'b'. Cualquiera de estos casos764puede dar lugar a efectos en el orden muy contrarios a la intuición.765 766Peor aún, si el compilador puede probar (decir) que el valor de la767variable 'a' siempre es distinta de cero, estaría dentro de sus derechos768para optimizar el ejemplo original eliminando la declaración "if", como:769 770	q = a;771	b = 1;  /* BUG: Compilador y CPU pueden ambos reordernar!!! */772 773Así que no deje de lado READ_ONCE().774 775Es tentador tratar de hacer cumplir el orden en stores idénticos en ambos776caminos del "if" de la siguiente manera:777 778	q = READ_ONCE(a);779	if (q) {780		barrier();781		WRITE_ONCE(b, 1);782		hacer_algo();783	} else {784		barrier();785		WRITE_ONCE(b, 1);786		hacer_otra_cosa();787	}788 789Desafortunadamente, los compiladores actuales transformarán esto de la790siguiente manera en casos de alto nivel de optimización:791 792  	q = READ_ONCE(a);793  	barrier();794  	WRITE_ONCE(b, 1);  /* BUG: No hay orden en load de a!!! */795  	if (q) {796  		/* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */797  		hacer_algo();798  	} else {799  		/* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */800  		hacer_otra_cosa();801  	}802 803Ahora no hay condicional entre la carga de 'a' y el store de 'b', lo que804significa que la CPU está en su derecho de reordenarlos: El condicional es805absolutamente necesario y debe estar presente en el código ensamblador806incluso después de que se hayan aplicado todas las optimizaciones del807compilador. Por lo tanto, si necesita ordenar en este ejemplo, necesita808explícitamente barreras de memoria, por ejemplo, smp_store_release():809 810 811	q = READ_ONCE(a);812	if (q) {813		smp_store_release(&b, 1);814		hacer_algo();815	} else {816		smp_store_release(&b, 1);817		hacer_otra_cosa();818	}819 820Por el contrario, sin barreras de memoria explícita, el control de un if821con dos opciones está garantizado solo cuando los stores difieren, por822ejemplo:823 824  	q = READ_ONCE(a);825  	if (q) {826  		WRITE_ONCE(b, 1);827  		hacer_algo();828  	} else {829  		WRITE_ONCE(b, 2);830  		hacer_otra_cosa();831  	}832 833Aún se requiere el inicial READ_ONCE() para evitar que el compilador toque834el valor de 'a'.835 836Además, debe tener cuidado con lo que hace con la variable local 'q', de lo837contrario, el compilador podría adivinar el valor y volver a eliminar el838necesario condicional. Por ejemplo:839 840  	q = READ_ONCE(a);841  	if (q % MAX) {842  		WRITE_ONCE(b, 1);843  		hacer_algo();844  	} else {845  		WRITE_ONCE(b, 2);846  		hacer_otra_cosa();847  	}848 849Si MAX se define como 1, entonces el compilador sabe que (q % MAX) es igual850a cero, en cuyo caso el compilador tiene derecho a transformar el código851anterior en el siguiente:852 853  	q = READ_ONCE(a);854  	WRITE_ONCE(b, 2);855  	hacer_otra_cosa();856 857Dada esta transformación, la CPU no está obligada a respetar el orden entre858la carga de la variable 'a' y el store de la variable 'b'. Es tentador859agregar una barrier(), pero esto no ayuda. El condicional se ha ido, y la860barrera no lo traerá de vuelta. Por lo tanto, si confia en este orden, debe861asegurarse de que MAX sea mayor que uno, tal vez de la siguiente manera:862 863  	q = READ_ONCE(a);864  	BUILD_BUG_ON(MAX <= 1); /* Orden de carga de a con store de b */865  	if (q % MAX) {866  		WRITE_ONCE(b, 1);867  		hacer_algo();868  	} else {869  		WRITE_ONCE(b, 2);870  		hacer_otra_cosa();871  	}872 873Tenga en cuenta una vez más que los stores de 'b' difieren. Si fueran874idénticos, como se señaló anteriormente, el compilador podría sacar ese875store fuera de la declaración 'if'.876 877También debe tener cuidado de no confiar demasiado en el cortocircuito878de la evaluación booleana. Considere este ejemplo:879 880  	q = READ_ONCE(a);881  	if (q || 1 > 0)882  	WRITE_ONCE(b, 1);883 884Debido a que la primera condición no puede fallar y la segunda condición es885siempre cierta, el compilador puede transformar este ejemplo de la886siguiente manera, rompiendo la dependencia del control:887 888  	q = READ_ONCE(a);889  	WRITE_ONCE(b, 1);890 891Este ejemplo subraya la necesidad de asegurarse de que el compilador no892pueda adivinar su código. Más generalmente, aunque READ_ONCE() fuerza893al compilador para emitir código para una carga dada, no fuerza al894compilador para usar los resultados.895 896Además, las dependencias de control se aplican solo a la cláusula then y897la cláusula else de la sentencia if en cuestión. En particular, no se898aplica necesariamente al código que sigue a la declaración if:899 900  	q = READ_ONCE(a);901  	if (q) {902  		WRITE_ONCE(b, 1);903  	} else {904  		WRITE_ONCE(b, 2);905  	}906  	WRITE_ONCE(c, 1);  /* BUG: No hay orden para la lectura de 'a'. */907 908Es tentador argumentar que, de hecho, existe un orden porque el compilador909no puede reordenar accesos volátiles y tampoco puede reordenar escrituras910en 'b' con la condición. Desafortunadamente para esta línea de911razonamiento, el compilador podría compilar las dos escrituras en 'b' como912instrucciones de movimiento condicional, como en este fantástico idioma913pseudo-ensamblador:914 915        	ld r1,a916        	cmp r1,$0917        	cmov,ne r4,$1918        	cmov,eq r4,$2919        	st r4,b920        	st $1,c921 922Una CPU débilmente ordenada no tendría dependencia de ningún tipo entre la923carga de 'a' y el store de 'c'. Las dependencias de control se extenderían924solo al par de instrucciones cmov y el store dependiente de ellas. En925resumen, las dependencias de control se aplican solo a los stores en la926cláusula then y la cláusula else de la sentencia if en cuestión (incluidas927las funciones invocado por esas dos cláusulas), no al código que sigue a928esa declaración if.929 930 931Tenga muy en cuenta que el orden proporcionado por una dependencia de932control es local a la CPU que lo contiene. Vea el apartado de "Atomicidad933multicopia" para más información.934 935 936En resumen:937 938  (*) Las dependencias de control pueden ordenar cargas anteriores para939      stores posteriores. Sin embargo, no garantizan ningún otro tipo de940      orden: No cargas previas contra cargas posteriores, ni941      almacenamientos previos y luego nada. Si necesita tales formas de942      orden, use smp_rmb(), smp_wmb() o, en el caso de stores anteriores y943      cargas posteriores, smp_mb().944 945  (*) Si ambos caminos de la declaración "if" comienzan con stores946      idénticos de la misma variable, entonces esos stores deben ser947      ordenados, ya sea precediéndoles a ambos con smp_mb() o usando948      smp_store_release() para realizar el store. Tenga en cuenta que -no-949      es suficiente usar barrier() al comienzo de cada caso de la950      declaración "if" porque, como se muestra en el ejemplo anterior, la951      optimización de los compiladores puede destruir la dependencia de952      control respetando al pie de la letra la ley de barrier().953 954  (*) Las dependencias de control requieren al menos un condicional en955      tiempo de ejecución entre la carga anterior y el almacenamiento956      posterior, y este condicional debe implicar la carga previa. Si el957      compilador es capaz de optimizar el condicional y quitarlo, también958      habrá optimizado el ordenar. El uso cuidadoso de READ_ONCE() y959      WRITE_ONCE() puede ayudar a preservar el necesario condicional.960 961  (*) Las dependencias de control requieren que el compilador evite962      reordenar las dependencia hasta su inexistencia. El uso cuidadoso de963      READ_ONCE() o atomic{,64}_read() puede ayudarle a preservar la964      dependencia de control. Consulte la sección BARRERA DEL COMPILADOR965      para obtener más información al respecto.966 967  (*) Las dependencias de control se aplican solo a la cláusula then y la968      cláusula else de la sentencia "if" que contiene la dependencia de969      control, incluyendo cualquier función a la que llamen dichas dos970      cláusulas. Las dependencias de control no se aplican al código que971      sigue a la instrucción if que contiene la dependencia de control.972 973  (*) Las dependencias de control se emparejan normalmente con otros tipos974      de barreras.975 976  (*) Las dependencias de control no proporcionan atomicidad multicopia. Si977      usted necesita todas las CPU para ver un store dado al mismo tiempo,978      emplee smp_mb().979 980  (*) Los compiladores no entienden las dependencias de control. Por lo981      tanto es su trabajo asegurarse de que no rompan su código.982 983 984EMPAREJAMIENTO DE BARRERAS SMP985------------------------------986 987Cuando se trata de interacciones CPU-CPU, ciertos tipos de barrera de988memoria deben estar siempre emparejados. La falta del apropiado989emparejamiento es casi seguro un error.990 991Las barreras generales se emparejan entre sí, aunque también se emparejan992con la mayoría de otro tipo de barreras, aunque sin atomicidad multicopia.993Una barrera de adquisición se empareja con una barrera de liberación, pero994ambas también pueden emparejarse con otras barreras, incluidas, por995supuesto, las barreras generales. Una barrera de escritura se empareja con996una barrera de dependencia de dirección, una dependencia de control, una997barrera de adquisición, una barrera de liberación, una barrera de lectura998o una barrera general. Del mismo modo, una barrera de lectura se empareja999con una de dependencia de control o barrera de dependencia de dirección con1000una barrera de escritura, una barrera de adquisición, una barrera de1001liberación o una barrera general:1002 1003	CPU 1		      CPU 21004	===============	      ===============1005	WRITE_ONCE(a, 1);1006	<barrera de escritura>1007	WRITE_ONCE(b, 2);     x = READ_ONCE(b);1008			      <barrera de lectura>1009			      y = READ_ONCE(a);1010 1011O bien:1012 1013	CPU 1		      CPU 21014	===============	      ===============================1015	a = 1;1016	<barrera de escritura>1017	WRITE_ONCE(b, &a);    x = READ_ONCE(b);1018			      <barrera de dependencia de dirección implícita>1019			      y = *x;1020 1021O incluso:1022 1023	CPU 1		      CPU 21024	===============	      ===============================1025	r1 = READ_ONCE(y);1026	<barrera general>1027	WRITE_ONCE(x, 1);     if (r2 = READ_ONCE(x)) {1028			         <barrera de control implícita>1029			         WRITE_ONCE(y, 1);1030			      }1031 1032	assert(r1 == 0 || r2 == 0);1033 1034Básicamente, la barrera de lectura siempre tiene que estar ahí, aunque1035puede ser del tipo "más débil".1036 1037[!] Tenga en cuenta que normalmente se esperaría que los stores antes de la1038barrera de escritura se hagan coincidir con los stores después de la1039barrera de lectura o la barrera de dependencia de dirección, y viceversa:1040 1041	CPU 1                               CPU 21042	===================                 ===================1043	WRITE_ONCE(a, 1);    }----   --->{  v = READ_ONCE(c);1044	WRITE_ONCE(b, 2);    }    \ /    {  w = READ_ONCE(d);1045	<barrera de escritura>            \        <barrera de lectura>1046	WRITE_ONCE(c, 3);    }    / \    {  x = READ_ONCE(a);1047	WRITE_ONCE(d, 4);    }----   --->{  y = READ_ONCE(b);1048 1049 1050EJEMPLOS DE SECUENCIAS DE BARRERA DE MEMORIA1051--------------------------------------------1052 1053En primer lugar, las barreras de escritura actúan como orden parcial en las1054operaciones de store. Considere la siguiente secuencia de eventos:1055 1056	CPU 11057	=======================1058	STORE A = 11059	STORE B = 21060	STORE C = 31061	<barrera de escritura>1062	STORE D = 41063	STORE E = 51064 1065Esta secuencia de eventos es finalizado para con el sistema de coherencia1066de memoria en un orden que el resto del sistema podría percibir como el1067conjunto desordenado { STORE A, STORE B, STORE C} todo ocurriendo antes del1068conjunto desordenado { STORE D, STORE E}:1069 1070 1071	+-------+       :      :1072	|       |       +------+1073	|       |------>| C=3  |     }     /\1074	|       |  :    +------+     }-----  \  -----> Eventos perceptibles para1075	|       |  :    | A=1  |     }        \/       el resto del sistema1076	|       |  :    +------+     }1077	| CPU 1 |  :    | B=2  |     }1078	|       |       +------+     }1079	|       |   wwwwwwwwwwwwwwww }   <--- En este momento la barrera de1080	|       |       +------+     }        escritura requiere que todos los1081	|       |  :    | E=5  |     }        stores anteriores a la barrera1082	|       |  :    +------+     }        sean confirmados antes de que otros1083	|       |------>| D=4  |     }        store puedan suceder1084	|       |       +------+1085	+-------+       :      :1086	                   |1087	                   | Secuencia por la cual los stores son confirmados al1088	                   | sistema de memoria por parte del CPU 11089	                   V1090 1091En segundo lugar, las barreras de dependencia de dirección actúan como1092órdenes parciales sobre la dirección de cargas dependientes. Considere la1093siguiente secuencia de eventos:1094 1095	CPU 1			CPU 21096	=======================	=======================1097		{ B = 7; X = 9; Y = 8; C = &Y }1098	STORE A = 11099	STORE B = 21100	<barrera de escritura>1101	STORE C = &B		LOAD X1102	STORE D = 4		LOAD C (consigue &B)1103				LOAD *C (lee B)1104 1105Sin intervención, la CPU 2 puede percibir los eventos en la CPU 1 en orden1106aleatorio a efectos prácticos, a pesar de la barrera de escritura emitida1107por la CPU 1:1108 1109	+-------+       :      :                :       :1110	|       |       +------+                +-------+  | Secuencia de1111	|       |------>| B=2  |-----       --->| Y->8  |  | actualizado de1112	|       |  :    +------+     \          +-------+  | percepción en CPU 21113	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |  V1114	|       |       +------+       |        +-------+1115	|       |   wwwwwwwwwwwwwwww   |        :       :1116	|       |       +------+       |        :       :1117	|       |  :    | C=&B |---    |        :       :       +-------+1118	|       |  :    +------+   \   |        +-------+       |       |1119	|       |------>| D=4  |    ----------->| C->&B |------>|       |1120	|       |       +------+       |        +-------+       |       |1121	+-------+       :      :       |        :       :       |       |1122	                               |        :       :       |       |1123	                               |        :       :       | CPU 2 |1124	                               |        +-------+       |       |1125	    Percepción de B      --->  |        | B->7  |------>|       |1126	    aparentemente incorrecta!  |        +-------+       |       |1127	                               |        :       :       |       |1128	                               |        +-------+       |       |1129	    La carga de X frena --->    \       | X->9  |------>|       |1130	    el mantenimiento de          \      +-------+       |       |1131	    la coherencia de B            ----->| B->2  |       +-------+1132	                                        +-------+1133	                                        :       :1134 1135 1136En el ejemplo anterior, la CPU 2 percibe que B es 7, a pesar de la carga de1137*C (que sería B) viniendo después del LOAD de C.1138 1139Sin embargo, si se colocara una barrera de dependencia de dirección entre1140la carga de C y la carga de *C (es decir: B) en la CPU 2:1141 1142	CPU 1			CPU 21143	=======================	=======================1144		{ B = 7; X = 9; Y = 8; C = &Y }1145	STORE A = 11146	STORE B = 21147	<barrera de escritura>1148	STORE C = &B		LOAD X1149	STORE D = 4		LOAD C (consigue &B)1150				<barrera de dependencia de dirección>1151				LOAD *C (reads B)1152 1153entonces ocurrirá lo siguiente:1154 1155	+-------+       :      :                :       :1156	|       |       +------+                +-------+1157	|       |------>| B=2  |-----       --->| Y->8  |1158	|       |  :    +------+     \          +-------+1159	| CPU 1 |  :    | A=1  |      \     --->| C->&Y |1160	|       |       +------+       |        +-------+1161	|       |   wwwwwwwwwwwwwwww   |        :       :1162	|       |       +------+       |        :       :1163	|       |  :    | C=&B |---    |        :       :       +-------+1164	|       |  :    +------+   \   |        +-------+       |       |1165	|       |------>| D=4  |    ----------->| C->&B |------>|       |1166	|       |       +------+       |        +-------+       |       |1167	+-------+       :      :       |        :       :       |       |1168	                               |        :       :       |       |1169	                               |        :       :       | CPU 2 |1170	                               |        +-------+       |       |1171	                               |        | X->9  |------>|       |1172	                               |        +-------+       |       |1173	  Se asegura de que      --->   \   aaaaaaaaaaaaaaaaa   |       |1174	  los efectos anteriores al      \      +-------+       |       |1175	  store de C sean percibidos      ----->| B->2  |------>|       |1176	  por los siguientes loads              +-------+       |       |1177	                                        :       :       +-------+1178 1179 1180Y en tercer lugar, una barrera de lectura actúa como un orden parcial sobre1181las cargas. Considere la siguiente secuencia de eventos:1182 1183	CPU 1			CPU 21184	=======================	=======================1185		{ A = 0, B = 9 }1186	STORE A=11187	<barrera de escritura>1188	STORE B=21189				LOAD B1190				LOAD A1191 1192Sin intervención, la CPU 2 puede elegir percibir los eventos en la CPU 1 en1193algún orden aleatorio a efectos prácticos, a pesar de la barrera de1194escritura emitida por la CPU 1:1195 1196	+-------+       :      :                :       :1197	|       |       +------+                +-------+1198	|       |------>| A=1  |------      --->| A->0  |1199	|       |       +------+      \         +-------+1200	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |1201	|       |       +------+        |       +-------+1202	|       |------>| B=2  |---     |       :       :1203	|       |       +------+   \    |       :       :       +-------+1204	+-------+       :      :    \   |       +-------+       |       |1205	                             ---------->| B->2  |------>|       |1206	                                |       +-------+       | CPU 2 |1207	                                |       | A->0  |------>|       |1208	                                |       +-------+       |       |1209	                                |       :       :       +-------+1210	                                 \      :       :1211	                                  \     +-------+1212	                                   ---->| A->1  |1213	                                        +-------+1214	                                        :       :1215 1216Sin embargo, si se colocara una barrera de lectura entre la carga de B y la1217carga de A en la CPU 2:1218 1219	CPU 1			CPU 21220	=======================	=======================1221		{ A = 0, B = 9 }1222	STORE A=11223	<barrera de escritura>1224	STORE B=21225				LOAD B1226				<barrera de lectura>1227				LOAD A1228 1229entonces el orden parcial impuesto por la CPU 1 será percibido1230correctamente por la CPU 2:1231 1232	+-------+       :      :                :       :1233	|       |       +------+                +-------+1234	|       |------>| A=1  |------      --->| A->0  |1235	|       |       +------+      \         +-------+1236	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |1237	|       |       +------+        |       +-------+1238	|       |------>| B=2  |---     |       :       :1239	|       |       +------+   \    |       :       :       +-------+1240	+-------+       :      :    \   |       +-------+       |       |1241	                             ---------->| B->2  |------>|       |1242	                                |       +-------+       | CPU 2 |1243	                                |       :       :       |       |1244	                                |       :       :       |       |1245	  En este punto la barrera ----> \  rrrrrrrrrrrrrrrrr   |       |1246	  de lectura consigue que         \     +-------+       |       |1247	  todos los efectos anteriores     ---->| A->1  |------>|       |1248	  al almacenamiento de B sean           +-------+       |       |1249	  perceptibles por la CPU 2             :       :       +-------+1250 1251 1252Para ilustrar esto de manera más completa, considere lo que podría pasar si1253el código contenía una carga de A a cada lado de la barrera de lectura:1254 1255	CPU 1			CPU 21256	=======================	=======================1257		{ A = 0, B = 9 }1258	STORE A=11259	<barrera de escritura>1260	STORE B=21261				LOAD B1262				LOAD A [primer load de A]1263				<rbarrera de lectura>1264				LOAD A [segundo load de A]1265 1266Aunque las dos cargas de A ocurren después de la carga de B, ambas pueden1267obtener diferentes valores:1268 1269	+-------+       :      :                :       :1270	|       |       +------+                +-------+1271	|       |------>| A=1  |------      --->| A->0  |1272	|       |       +------+      \         +-------+1273	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |1274	|       |       +------+        |       +-------+1275	|       |------>| B=2  |---     |       :       :1276	|       |       +------+   \    |       :       :       +-------+1277	+-------+       :      :    \   |       +-------+       |       |1278	                             ---------->| B->2  |------>|       |1279	                                |       +-------+       | CPU 2 |1280	                                |       :       :       |       |1281	                                |       :       :       |       |1282	                                |       +-------+       |       |1283	                                |       | A->0  |------>| 1st   |1284	                                |       +-------+       |       |1285	  En este punto la barrera ----> \  rrrrrrrrrrrrrrrrr   |       |1286	  de lectura consigue que         \     +-------+       |       |1287	  todos los efectos anteriores     ---->| A->1  |------>|       |1288	  al almacenamiento de B sean           +-------+       |       |1289	  perceptibles por la CPU 2             :       :       +-------+1290 1291Pero puede ser que la actualización a A desde la CPU 1 se vuelva1292perceptible para la CPU 2 antes de que la barrera de lectura se complete de1293todos modos:1294 1295	+-------+       :      :                :       :1296	|       |       +------+                +-------+1297	|       |------>| A=1  |------      --->| A->0  |1298	|       |       +------+      \         +-------+1299	| CPU 1 |   wwwwwwwwwwwwwwww   \    --->| B->9  |1300	|       |       +------+        |       +-------+1301	|       |------>| B=2  |---     |       :       :1302	|       |       +------+   \    |       :       :       +-------+1303	+-------+       :      :    \   |       +-------+       |       |1304	                             ---------->| B->2  |------>|       |1305	                                |       +-------+       | CPU 2 |1306	                                |       :       :       |       |1307	                                 \      :       :       |       |1308	                                  \     +-------+       |       |1309	                                   ---->| A->1  |------>| 1st   |1310	                                        +-------+       |       |1311	                                    rrrrrrrrrrrrrrrrr   |       |1312	                                        +-------+       |       |1313	                                        | A->1  |------>| 2nd   |1314	                                        +-------+       |       |1315	                                        :       :       +-------+1316 1317La garantía es que la segunda carga siempre dará como resultado A == 1 si1318la carga de B resultó en B == 2. No existe tal garantía para la primera1319carga de A; esto puede dar como resultado A == 0 o A == 1.1320 1321 1322BARRERAS DE MEMORIA DE LECTURA FRENTE A ESPECULACIÓN DE CARGA1323-------------------------------------------------------------1324 1325Muchas CPU especulan con las cargas: es decir, ven que necesitarán cargar1326un elemento de la memoria, y encuentran un momento en el que no están1327usando el bus para ningún otra carga, y también en la carga por adelantado,1328aunque en realidad no lo hayan llegado a ese punto en el flujo de ejecución1329de instrucciones todavía. Esto permite que la instrucción de carga real1330potencialmente complete de inmediato, porque la CPU ya tiene el valor a1331mano.1332 1333Puede resultar que la CPU en realidad no necesitara el valor, tal vez1334porque una condición eludió la carga, en cuyo caso puede descartar el valor1335o simplemente almacenar en caché para su uso posterior.1336 1337Considere:1338 1339	CPU 1			CPU 21340	=======================	=======================1341				LOAD B1342				DIVIDE		} Instrucciones de división1343				DIVIDE		} tardan mucho en terminar1344				LOAD A1345 1346donde DIVIDE es DIVIDIR. Que podría aparecer como esto:1347 1348	                                        :       :       +-------+1349	                                        +-------+       |       |1350	                                    --->| B->2  |------>|       |1351	                                        +-------+       | CPU 2 |1352	                                        :       :DIVIDE |       |1353	                                        +-------+       |       |1354	La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |1355	especula sobre el LOAD de A             +-------+   ~   |       |1356	                                        :       :   ~   |       |1357	                                        :       :DIVIDE |       |1358	                                        :       :   ~   |       |1359	Una vez completadas las divisiones  --> :       :   ~-->|       |1360	la CPU puede realizar el                :       :       |       |1361	LOAD con efecto inmediato               :       :       +-------+1362 1363 1364Colocando una barrera de lectura o una barrera de dependencia de dirección1365justo antes de la segundo carga:1366 1367 1368 1369	CPU 1			CPU 21370	=======================	=======================1371				LOAD B1372				DIVIDE1373				DIVIDE1374				<rbarrera de lectura>1375				LOAD A1376 1377obligará a reconsiderar cualquier valor obtenido especulativamente en una1378medida dependiente del tipo de barrera utilizada. Si no se hizo ningún1379cambio en la ubicación de memoria especulada, entonces el valor especulado1380solo se usará:1381 1382	                                        :       :       +-------+1383	                                        +-------+       |       |1384	                                    --->| B->2  |------>|       |1385	                                        +-------+       | CPU 2 |1386	                                        :       :DIVIDE |       |1387	                                        +-------+       |       |1388  La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |1389  especula sobre el LOAD de A             +-------+   ~   |       |1390	                                        :       :   ~   |       |1391	                                        :       :DIVIDE |       |1392	                                        :       :   ~   |       |1393	                                        :       :   ~   |       |1394	                                    rrrrrrrrrrrrrrrr~   |       |1395	                                        :       :   ~   |       |1396	                                        :       :   ~-->|       |1397	                                        :       :       |       |1398	                                        :       :       +-------+1399 1400 1401pero si había una actualización o una invalidación de otra CPU pendiente,1402entonces la especulación será cancelada y el valor recargado:1403 1404	                                        :       :       +-------+1405	                                        +-------+       |       |1406	                                    --->| B->2  |------>|       |1407	                                        +-------+       | CPU 2 |1408	                                        :       :DIVIDE |       |1409	                                        +-------+       |       |1410  La CPU ocupada con la división ---> --->| A->0  |~~~~   |       |1411  especula sobre el LOAD de A             +-------+   ~   |       |1412	                                        :       :   ~   |       |1413	                                        :       :DIVIDE |       |1414	                                        :       :   ~   |       |1415	                                        :       :   ~   |       |1416	                                    rrrrrrrrrrrrrrrrr   |       |1417	                                        +-------+       |       |1418	La especulación es descartada --->  --->| A->1  |------>|       |1419	y un valor actualizado                  +-------+       |       |1420	es conseguido                           :       :       +-------+1421 1422ATOMICIDAD MULTICOPIA1423---------------------1424 1425La atomicidad multicopia es una noción profundamente intuitiva sobre el1426orden que no es siempre proporcionada por los sistemas informáticos reales,1427a saber, que un determinada store se vuelve visible al mismo tiempo para1428todos las CPU o, alternativamente, que todas las CPU acuerdan el orden en1429que todos los stores se vuelven visibles. Sin embargo, el soporte para1430atomicidad multicopia completa descartaría valiosas optimizaciones1431hardware, por lo que una versión más débil conocida como ``otra atomicidad1432multicopia'' en cambio, solo garantiza que un store dado se vuelva visible1433al mismo tiempo en todas las -otras- CPUs. El resto de este documento1434discute esta versión más débil, pero por brevedad lo llamaremos simplemente1435``atomicidad multicopia''.1436 1437El siguiente ejemplo demuestra la atomicidad multicopia:1438 1439	CPU 1			CPU 2			CPU 31440	=======================	=======================	=======================1441		{ X = 0, Y = 0 }1442	STORE X=1		r1=LOAD X (reads 1)	LOAD Y (reads 1)1443				<barrera general>	<barrera de lectura>1444				STORE Y=r1		LOAD X1445 1446Suponga que la carga de la CPU 2 desde X devuelve 1, que luego almacena en1447Y, y la carga de la CPU 3 desde Y devuelve 1. Esto indica que el store de1448la CPU 1 a X precede a la carga de la CPU 2 desde X y el store de esa CPU 21449a Y precede la carga de la CPU 3 desde Y. Además, las barreras de memoria1450garantizan que la CPU 2 ejecuta su carga antes que su almacenamiento, y la1451CPU 3 carga desde Y antes de cargar desde X. La pregunta entonces es1452"¿Puede la carga de la CPU 3 desde X devolver 0?"1453 1454Debido a que la carga de la CPU 3 desde X en cierto sentido viene después1455de la carga de la CPU 2, es natural esperar que la carga de la CPU 3 desde1456X deba devolver 1. Esta expectativa se deriva de la atomicidad multicopia:1457si una carga que se ejecuta en la CPU B sigue una carga de la misma1458variable que se ejecuta en la CPU A (y la CPU A no almacenó originalmente1459el valor que leyó), entonces en sistemas atómicos multicopia, la carga de1460la CPU B debe devolver el mismo valor que hizo la carga de la CPU A o algún1461valor posterior. Sin embargo, el kernel Linux no requiere que los sistemas1462sean atómicos multicopia.1463 1464El uso de una barrera de memoria general en el ejemplo anterior compensa1465cualquier falta de atomicidad multicopia. En el ejemplo, si la carga de la1466CPU 2 de X devuelve 1 y la carga de la CPU 3 de Y devuelve 1, entonces la1467carga de la CPU 3 desde X debe de hecho también devolver 1.1468 1469Sin embargo, las dependencias, las barreras de lectura y las barreras de1470escritura no siempre son capaces de compensar la atomicidad no multicopia.1471Por ejemplo, supongamos que la barrera general de la CPU 2 se elimina del1472ejemplo anterior, dejando solo la dependencia de datos que se muestra a1473continuación:1474 1475	CPU 1			CPU 2			CPU 31476	=======================	=======================	=======================1477		{ X = 0, Y = 0 }1478	STORE X=1		r1=LOAD X (escribe 1)	LOAD Y (lee 1)1479				<dependencia de datos>	<barrera de lectura>1480				STORE Y=r1		LOAD X (lee 0)1481 1482Esta sustitución permite que la atomicidad no multicopia se desenfrene: en1483este ejemplo, es perfectamente legal que la carga de la CPU 2 desde X1484devuelva 1, la carga de la CPU 3 desde Y devuelva 1, y su carga desde X1485tenga valor 0.1486 1487El punto clave es que aunque la dependencia de datos de la CPU 2 ordena su1488carga y store, no garantiza ordenar el store de la CPU 1. De forma que, si1489este ejemplo se ejecuta en un sistema atómico no multicopia donde las CPU 11490y 2 comparten un buffer de almacenamiento o un nivel de caché, la CPU 21491podría tener acceso anticipado de escritura a CPU 1. Por lo tanto, se1492requieren barreras generales para garantizar que todas las CPU acurden el1493orden combinado de accesos múltiples.1494 1495Las barreras generales pueden compensar no solo la atomicidad no1496multicopia, pero también pueden generar orden adicional que puede asegurar1497que -todas- las CPU percibirán el mismo orden de -todas- las operaciones.1498Por el contrario, una cadena de parejas de liberación-adquisición no1499proporciona este orden adicional, lo que significa que solo se garantiza1500que las CPU de la cadena estén de acuerdo en el orden combinado de los1501accesos. Por ejemplo, cambiando a código C en deferencia al fantasma de1502Herman Hollerith:1503 1504	int u, v, x, y, z;1505 1506	void cpu0(void)1507	{1508		r0 = smp_load_acquire(&x);1509		WRITE_ONCE(u, 1);1510		smp_store_release(&y, 1);1511	}1512 1513	void cpu1(void)1514	{1515		r1 = smp_load_acquire(&y);1516		r4 = READ_ONCE(v);1517		r5 = READ_ONCE(u);1518		smp_store_release(&z, 1);1519	}1520 1521	void cpu2(void)1522	{1523		r2 = smp_load_acquire(&z);1524		smp_store_release(&x, 1);1525	}1526 1527	void cpu3(void)1528	{1529		WRITE_ONCE(v, 1);1530		smp_mb();1531		r3 = READ_ONCE(u);1532	}1533 1534Dado que cpu0(), cpu1() y cpu2() participan en una cadena de parejas1535smp_store_release()/smp_load_acquire(), el siguiente resultado estaría1536prohibido:1537 1538	r0 == 1 && r1 == 1 && r2 == 11539 1540Además, debido a la relación liberación-adquisición entre cpu0() y cpu1(),1541cpu1() debe ver las escrituras de cpu0(), de modo que el siguiente1542resultado estaría prohibido:1543 1544	r1 == 1 && r5 == 01545 1546Sin embargo, el orden proporcionado por una cadena de1547liberación-adquisición es local a las CPU que participan en esa cadena y no1548se aplica a cpu3(), al menos aparte de los stores. Por lo tanto, es posible1549el siguiente resultado:1550 1551	r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 01552 1553Por otro lado, también el siguiente resultado es posible:1554 1555	r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 && r5 == 11556 1557Aunque cpu0(), cpu1() y cpu2() verán sus respectivas lecturas y escrituras1558en orden, las CPU que no participan en la cadena de liberación-adquisición1559pueden estar en desacuerdo con el orden. Este desacuerdo se debe al hecho1560de que las instrucciones de barrera de memoria débiles utilizadas para1561implementar smp_load_acquire() y smp_store_release() no son necesarios para1562ordenar stores anteriores contra cargas posteriores en todos los casos.1563Esto significa que cpu3() puede ver el store de cpu0() suceder -después- de1564la carga de cpu1() desde v, aunque tanto cpu0() como cpu1() están de1565acuerdo en que estas dos operaciones ocurrieron en el orden previsto.1566 1567Sin embargo, tenga en cuenta que smp_load_acquire() no es mágico. En1568particular, simplemente lee de su argumento en orden. Es decir, -no-1569asegura que se leerá cualquier valor en particular. Por lo tanto, los1570siguiente resultados son posibles:1571 1572	r0 == 0 && r1 == 0 && r2 == 0 && r5 == 01573 1574Tenga en cuenta que este resultado puede ocurrir incluso en un mítico1575sistema, consistente en secuencia, donde nunca se reordena nada.1576 1577Para reiterar, si su código requiere un orden completo de todas las1578operaciones, utilice barreras generales en todo momento.1579 1580 1581==============================1582BARRERAS EXPLÍCITAS DEL KERNEL1583==============================1584 1585El kernel Linux tiene una variedad de diferentes barreras que actúan a1586diferentes niveles:1587 1588  (*) Barrera del compilador.1589 1590  (*) Barreras de memoria de la CPU.1591 1592 1593BARRERA DEL COMPILADOR1594-----------------------1595 1596El kernel de Linux tiene una función de barrera del compilador explícita1597que evita que el el compilador mueva los accesos a la memoria de cualquier1598lado al otro:1599 1600	barrier();1601 1602Esta es una barrera general: no hay variantes de barrier() para casos de1603lectura-lectura o escritura-escritura. Sin embargo, READ_ONCE() y1604WRITE_ONCE() pueden ser considerado como formas débiles de barrier() que1605afectan solo específicos accesos marcados por READ_ONCE() o WRITE_ONCE().1606 1607La función barrier() produce los siguientes efectos:1608 1609 (*) Evita que el compilador reordene los accesos tras barrier() para1610     preceder a cualquier acceso que preceda a barrier(). Un ejemplo de uso1611     de esta propiedad es facilitar la comunicación entre código del1612     interrupt-handler (encargo de gestionar interrupciones) y el código1613     que fue interrumpido.1614 1615 (*) Dentro de un bucle ("loop"), obliga al compilador a cargar las1616     variables utilizadas en ese loop condicional en cada paso a través de1617     ese loop.1618 1619Las funciones READ_ONCE() y WRITE_ONCE() pueden evitar cualquier cantidad1620de optimizaciones que, si bien son perfectamente seguras en código de un1621solo subproceso, pueden resultar fatales en código concurrente. Aquí hay1622algunos ejemplos de tal tipo de optimizaciones:1623 1624(*) El compilador está en su derecho de reordenar cargas y stores de la1625    misma variable, y en algunos casos, la CPU está dentro de su1626    derecho de reordenar cargas a la misma variable. Esto significa que1627    el siguiente código:1628 1629 a[0] = x;1630 a[1] = x;1631 1632     Podría resultar en un valor más antiguo de x almacenado en a[1] que en1633     a[0]. Evite que tanto el compilador como la CPU hagan esto de la1634     siguiente manera:1635 1636	a[0] = READ_ONCE(x);1637	a[1] = READ_ONCE(x);1638 1639     En resumen, READ_ONCE() y WRITE_ONCE() proporcionan coherencia de1640     caché para accesos desde múltiples CPUs a una sola variable.1641 1642     (*) El compilador tiene derecho a juntar cargas sucesivas de la misma1643         variable. Tal fusión puede hacer que el compilador "optimice" el1644         siguiente código:1645 1646    	while (tmp = a)1647    		hacer_algo_con(tmp);1648 1649        en el siguiente código, que, aunque en cierto sentido es legítimo1650        para un código de un solo subproceso, es casi seguro que no es lo1651        que el desarrollador pretendía:1652 1653   	if (tmp = a)1654   		for (;;)1655   			hacer_algo_con(tmp);1656 1657        Use READ_ONCE() para evitar que el compilador le haga esto:1658 1659   	while (tmp = READ_ONCE(a))1660   		hacer_algo_con(tmp);1661 1662 (*) El compilador tiene derecho a recargar una variable, por ejemplo,1663    en los casos en que la alta presión de los registros impida que el1664    compilador mantenga todos los datos de interés en registros. El1665    compilador podría por lo tanto, optimizar la variable 'tmp' de nuestro1666    ejemplo anterior:1667 1668	while (tmp = a)1669		hacer_algo_con(tmp);1670 1671     Esto podría resultar en el siguiente código, que es perfectamente1672     seguro en código de subproceso único, pero puede ser fatal en código1673     concurrente:1674 1675	while (a)1676		hacer_algo_con(a);1677 1678    Por ejemplo, la versión optimizada de este código podría resultar en1679    pasar un cero a hacer_algo_con() en el caso de que la variable a sea1680    modificada por alguna otra CPU, entre la instrucción "while" y la1681    llamada a hacer_algo_con().1682 1683    De nuevo, use READ_ONCE() para evitar que el compilador haga esto:1684 1685	while (tmp = READ_ONCE(a))1686		hacer_algo_con(tmp);1687 1688     Tenga en cuenta que si el compilador se queda sin registros, podría1689     guardar tmp en la pila ("stack"). El overhead (coste en eficiencia) de1690     este guardado y posterior restauración es por lo que los compiladores1691     recargan las variables. Hacerlo es perfectamente seguro para código de1692     subproceso único, por lo que debe informar al compilador sobre los1693     casos donde no sea seguro.1694 1695 (*) El compilador está en su derecho de omitir una carga por completo si1696     sabe cual será su valor. Por ejemplo, si el compilador puede probar1697     que el valor de la variable 'a' siempre es cero, puede optimizar este1698     código:1699 1700	while (tmp = a)1701		hacer_algo_con(tmp);1702 1703     En esto:1704 1705	do { } while (0);1706 1707     Esta transformación es una victoria para un código de un solo1708     subproceso, porque se deshace de una carga y un branch. El problema es1709     que el compilador llevará a cabo su prueba asumiendo que la CPU actual1710     es la única actualizando la variable 'a'. Si la variable 'a' es1711     compartida, entonces la prueba del compilador será errónea. Use1712     READ_ONCE() para decirle al compilador que no sabe tanto como cree:1713 1714	while (tmp = READ_ONCE(a))1715		hacer_algo_con(tmp);1716 1717     Pero, por favor, tenga en cuenta que el compilador también está1718     observando de cerca lo que usted hace con el valor después de1719     READ_ONCE(). Por ejemplo, suponga que Ud. hace lo siguiente y MAX es1720     una macro de preprocesador con el valor 1:1721 1722	while ((tmp = READ_ONCE(a)) % MAX)1723		hacer_algo_con(tmp);1724 1725     Entonces el compilador sabe que el resultado del operador "%" aplicado1726     a MAX siempre será cero, nuevamente permitiendo que el compilador1727     optimice el código hasta su casi inexistencia. (Aún se cargará desde1728     la variable 'a'.)1729 1730 (*) De manera similar, el compilador tiene derecho a omitir un store por1731     completo si sabe que la variable ya tiene el valor almacenado.1732     Nuevamente, el compilador asume que la CPU actual es la única que1733     almacena la variable, lo que puede hacer que el compilador haga1734     algo incorrecto para las variables compartidas. Por ejemplo, suponga1735     que tiene lo siguiente:1736 1737	a = 0;1738	... Código que no almacena la variable a ...1739	a = 0;1740 1741     El compilador observa que el valor de la variable 'a' ya es cero, por1742     lo que bien podría omitir el segundo store. Esto supondría una fatal1743     sorpresa, si alguna otra CPU hubiera almacenado la variable 'a'1744     mientras tanto.1745 1746     Use WRITE_ONCE() para evitar que el compilador haga este tipo de1747     suposición equivocada:1748 1749	WRITE_ONCE(a, 0);1750	... Código que no almacena la variable a  ...1751	WRITE_ONCE(a, 0);1752 1753  (*) El compilador tiene derecho a reordenar los accesos a memoria a menos1754     que le diga que no. Por ejemplo, considere la siguiente interacción1755     entre el código de nivel de proceso y un controlador de interrupción:1756 1757	void nivel_de_procesamiento(void)1758	{1759		msg = ACQUIRE_mensaje();1760		flag = true;1761	}1762 1763	void controlador_interrupcion(void)1764	{1765		if (flag)1766			procesar_mensaje(msg);1767	}1768 1769     No hay nada que impida que el compilador transforme1770     nivel_de_procesamiento() a lo siguiente, que de hecho, bien podría ser1771     una victoria para código de un solo subproceso:1772 1773	void nivel_de_procesamiento(void)1774	{1775		flag = true;1776		msg = ACQUIRE_mensaje();1777	}1778 1779     Si la interrupción ocurre entre estas dos declaraciones, entonces1780     controlador_interrupcion() podría recibir un mensaje ilegible. Use1781     READ_ONCE() para evitar esto de la siguiente manera:1782 1783	void nivel_de_procesamiento(void)1784	{1785		WRITE_ONCE(msg, ACQUIRE_mensaje());1786		WRITE_ONCE(flag, true);1787	}1788 1789	void controlador_interrupcion(void)1790	{1791		if (READ_ONCE(flag))1792			procesar_mensaje(READ_ONCE(msg));1793	}1794 1795     Tenga en cuenta que los envoltorios ("wrappers") READ_ONCE() y1796     WRITE_ONCE() en controlador_interrupcion() son necesarios si este1797     controlador de interrupciones puede ser interrumpido por algo que1798     también accede a 'flag' y 'msg', por ejemplo, una interrupción anidada1799     o un NMI. De lo contrario, READ_ONCE() y WRITE_ONCE() no son1800     necesarios en controlador_interrupcion() aparte de con fines de1801     documentación. (Tenga también en cuenta que las interrupciones1802     anidadas no ocurren típicamente en los kernels Linux modernos, de1803     hecho, si un controlador de interrupciones regresa con interrupciones1804     habilitadas, obtendrá un WARN_ONCE().)1805 1806     Debe suponer que el compilador puede mover READ_ONCE() y WRITE_ONCE()1807     a código que no contiene READ_ONCE(), WRITE_ONCE(), barrier(), o1808     primitivas similares.1809 1810     Este efecto también podría lograrse usando barrier(), pero READ_ONCE()1811     y WRITE_ONCE() son más selectivos: Con READ_ONCE() y WRITE_ONCE(), el1812     compilador solo necesita olvidar el contenido de ubicaciones de1813     memoria indicadas, mientras que con barrier() el compilador debe1814     descartar el valor de todas las ubicaciones de memoria que tiene1815     actualmente almacenadas en caché, en cualquier registro de la máquina.1816     Por supuesto, el compilador también debe respetar el orden en que1817     ocurren READ_ONCE() y WRITE_ONCE(), aunque la CPU, efectivamente, no1818     necesita hacerlo.1819 1820 (*) El compilador tiene derecho a inventar stores para una variable,1821     como en el siguiente ejemplo:1822 1823	if (a)1824		b = a;1825	else1826		b = 42;1827 1828    El compilador podría ahorrar un branch al optimizar esto de la1829    siguiente manera:1830 1831    	b = 42;1832    	if (a)1833    		b = a;1834 1835     En el código de un solo subproceso, esto no solo es seguro, sino que1836     también ahorra un branch. Desafortunadamente, en código concurrente,1837     esta optimización podría causar que alguna otra CPU vea un valor falso1838     de 42, incluso si la variable 'a' nunca fue cero, al cargar la1839     variable 'b'. Use WRITE_ONCE() para evitar esto de la siguiente1840     manera:1841 1842	if (a)1843		WRITE_ONCE(b, a);1844	else1845		WRITE_ONCE(b, 42);1846 1847    El compilador también puede inventar cargas. Estos casos suelen ser1848    menos perjudiciales, pero pueden dar como resultado "bouncing" de la1849    línea de caché y, por lo tanto, bajo rendimiento y escalabilidad.1850    Utilice READ_ONCE() para evitar cargas inventadas.1851 1852 (*) Para ubicaciones de memoria alineadas cuyo tamaño les permita1853     acceder con una sola instrucción de referencia de memoria, evite el1854     "desgarro de la carga" (load tearing) y "desgarro del store" (store1855     tearing), en el que un solo gran acceso es reemplazado por múltiples1856     accesos menores. Por ejemplo, dada una arquitectura que tiene1857     instrucciones de almacenamiento de 16 bits con campos inmediatos de 71858     bits, el compilador podría tener la tentación de usar dos1859     instrucciones inmediatas de almacenamiento de 16 bits para implementar1860     el siguiente store de 32 bits:1861 1862	p = 0x00010002;1863 1864     Tenga en cuenta que GCC realmente usa este tipo de optimización, lo1865     cual no es sorprendente dado que probablemente costaría más de dos1866     instrucciones el construir la constante y luego almacenarla. Por lo1867     tanto, esta optimización puede ser una victoria en un código de un1868     solo subproceso. De hecho, un error reciente (desde que se solucionó)1869     hizo que GCC usara incorrectamente esta optimización en un store1870     volátil. En ausencia de tales errores, el uso de WRITE_ONCE() evita el1871     desgarro del store en el siguiente ejemplo:1872 1873	struct __attribute__((__packed__)) foo {1874		short a;1875		int b;1876		short c;1877	};1878	struct foo foo1, foo2;1879	...1880 1881	foo2.a = foo1.a;1882	foo2.b = foo1.b;1883	foo2.c = foo1.c;1884 1885     Debido a que no hay envoltorios READ_ONCE() o WRITE_ONCE() y no1886     hay markings volátiles, el compilador estaría en su derecho de1887     implementar estas tres declaraciones de asignación como un par de1888     cargas de 32 bits, seguido de un par de stores de 32 bits. Esto1889     resultaría en una carga con desgarro en 'foo1.b' y store del desgarro1890     en 'foo2.b'. READ_ONCE() y WRITE_ONCE() nuevamente evitan el desgarro1891     en este ejemplo:1892 1893	foo2.a = foo1.a;1894	WRITE_ONCE(foo2.b, READ_ONCE(foo1.b));1895	foo2.c = foo1.c;1896 1897Aparte de esto, nunca es necesario usar READ_ONCE() y WRITE_ONCE() en una1898variable que se ha marcado como volátil. Por ejemplo, dado que 'jiffies'1899está marcado como volátil, nunca es necesario usar READ_ONCE(jiffies). La1900razón de esto es que READ_ONCE() y WRITE_ONCE() se implementan como1901conversiones volátiles, lo que no tiene efecto cuando su argumento ya está1902marcado como volátil.1903 1904Tenga en cuenta que estas barreras del compilador no tienen un efecto1905directo en la CPU, que luego puede reordenar las cosas como quiera.1906 1907 1908BARRERAS DE MEMORIA DE LA CPU1909-----------------------------1910 1911El kernel de Linux tiene siete barreras básicas de memoria de CPU:1912 1913TIPO			OBLIGATORIO	SMP CONDICIONAL1914=======================	===============	===============1915GENERAL			mb()		smp_mb()1916WRITE			wmb()		smp_wmb()1917READ			rmb()		smp_rmb()1918DEPEDENCIA DE DIRECCIÓN			READ_ONCE()1919 1920 1921Todas las barreras de memoria, excepto las barreras de dependencia de1922direcciones, implican una barrera del compilador. Las dependencias de1923direcciones no imponen ningún orden de compilación adicional.1924 1925Además: en el caso de las dependencias de direcciones, se esperaría que el1926compilador emita las cargas en el orden correcto (por ejemplo, `a[b]`1927tendría que cargar el valor de b antes de cargar a[b]), sin embargo, no hay1928garantía alguna en la especificación de C sobre que el compilador no puede1929especular el valor de b (por ejemplo, es igual a 1) y carga a[b] antes que1930b (ej. tmp = a[1]; if (b != 1) tmp = a[b]; ). También existe el problema de1931que un compilador vuelva a cargar b después de haber cargado a[b], teniendo1932así una copia más nueva de b que a[b]. Aún no se ha conseguido un consenso1933acerca de estos problemas, sin embargo, el macro READ_ONCE() es un buen1934lugar para empezar a buscar.1935 1936Las barreras de memoria SMP se reducen a barreras de compilador cuando se1937compila a monoprocesador, porque se supone que una CPU parecerá ser1938auto-consistente, y ordenará correctamente los accesos superpuestos1939respecto a sí misma. Sin embargo, consulte la subsección "Guests de1940máquinas virtuales" mas adelante.1941 1942[!] Tenga en cuenta que las barreras de memoria SMP _deben_ usarse para1943controlar el orden de referencias a memoria compartida en sistemas SMP,1944aunque el uso de bloqueo en su lugar sea suficiente.1945 1946Las barreras obligatorias no deben usarse para controlar los efectos de1947SMP, ya que dichas barreras imponen una sobrecarga innecesaria en los1948sistemas SMP y UP. Se pueden, sin embargo, usar para controlar los efectos1949MMIO en los accesos a través de ventanas E/S de memoria relajada. Estas1950barreras son necesarias incluso en sistemas que no son SMP, ya que afectan1951al orden en que las operaciones de memoria aparecen en un dispositivo, al1952prohibir tanto al compilador como a la CPU que sean reordenados.1953 1954 1955Hay algunas funciones de barrera más avanzadas:1956 1957 (*) smp_store_mb(var, valor)1958 1959     Asigna el valor a la variable y luego inserta una barrera de memoria1960     completa después de ella. No se garantiza insertar nada más que una1961     barrera del compilador en una compilación UP.1962 1963 1964 (*) smp_mb__before_atomic();1965 (*) smp_mb__after_atomic();1966 1967     Estos se pueden usar con funciones RMW atómicas que no implican1968     barreras de memoria, pero donde el código necesita una barrera de1969     memoria. Ejemplos de funciones RMW atómicas que no implican una1970     barrera de memoria son, por ejemplo, agregar, restar, operaciones1971     condicionales (fallidas), funciones _relaxed, pero no atomic_read o1972     atomic_set. Un ejemplo común donde se puede requerir una barrera es1973     cuando se usan operaciones atómicas como referencia de contador.1974 1975     Estos también se utilizan para funciones atómicas RMW bitop que no1976     implican una barrera de memoria (como set_bit y clear_bit).1977 1978     Como ejemplo, considere una pieza de código que marca un objeto como1979     muerto y luego disminuye el contador de referencias del objeto:1980 1981	obj->dead = 1;1982	smp_mb__before_atomic();1983	atomic_dec(&obj->ref_count);1984 1985     Esto asegura que la marca de muerte en el objeto se perciba como1986     fijada *antes* de que disminuya el contador de referencia.1987 1988     Consulte Documentation/atomic_{t,bitops}.txt para obtener más1989     información.1990 1991 1992 (*) dma_wmb();1993 (*) dma_rmb();1994 (*) dma_mb();1995 1996     Estos son usados con memoria consistente para garantizar el orden de1997     escrituras o lecturas de memoria compartida accesible tanto para la1998     CPU como para un dispositivo compatible con DMA.1999 2000     Por ejemplo, considere un controlador de dispositivo que comparte2001     memoria con otro dispositivo y usa un valor de estado del descriptor2002     para indicar si el descriptor pertenece al dispositivo o a la CPU, y2003     un "doorbell" (timbre, punto de acceso) para avisarle cuando haya2004     nuevos descriptores disponibles:2005 2006	if (desc->status != DEVICE_OWN) {2007		/* no leer los datos hasta que tengamos el descriptor */2008		dma_rmb();2009 2010		/* leer/modificar datos */2011		read_data = desc->data;2012		desc->data = write_data;2013 2014		/* flush de modificaciones antes de la actualización de estado */2015		dma_wmb();2016 2017		/* asignar propiedad */2018		desc->status = DEVICE_OWN;2019 2020		/* notificar al dispositivo de nuevos descriptores */2021		writel(DESC_NOTIFY, doorbell);2022	}2023 2024     El dma_rmb() nos permite garantizar que el dispositivo ha liberado su2025     propiedad antes de que leamos los datos del descriptor, y el dma_wmb()2026     permite garantizar que los datos se escriben en el descriptor antes de2027     que el dispositivo pueda ver que ahora tiene la propiedad. El dma_mb()2028     implica tanto un dma_rmb() como un dma_wmb(). Tenga en cuenta que, al2029     usar writel(), no se necesita un wmb() anterior para garantizar que2030     las escrituras de la memoria caché coherente se hayan completado antes2031     escribiendo a la región MMIO. El writel_relaxed() más barato no2032     proporciona esta garantía y no debe utilizarse aquí.2033 2034     Consulte la subsección "Efectos de barrera de E/S del kernel" para2035     obtener más información sobre accesorios de E/S relajados y el archivo2036     Documentation/core-api/dma-api.rst para más información sobre memoria2037     consistente.2038 2039 (*) pmem_wmb();2040 2041     Es es para uso con memoria persistente para garantizar que los stores2042     para los que las modificaciones se escriben en el almacenamiento2043     persistente llegaron a dominio de durabilidad de la plataforma.2044 2045     Por ejemplo, después de una escritura no temporal en la región pmem,2046     usamos pmem_wmb() para garantizar que los stores hayan alcanzado el2047     dominio de durabilidad de la plataforma. Esto garantiza que los stores2048     han actualizado el almacenamiento persistente antes de cualquier2049     acceso a datos o transferencia de datos causada por instrucciones2050     posteriores. Esto es además del orden realizado por wmb().2051 2052     Para la carga desde memoria persistente, las barreras de memoria de2053     lectura existentes son suficientes para garantizar el orden de2054     lectura.2055 2056 (*) io_stop_wc();2057 2058     Para accesos a memoria con atributos de combinación de escritura (por2059     ejemplo, los devueltos por ioremap_wc(), la CPU puede esperar a que2060     los accesos anteriores se junten con posteriores. io_stop_wc() se2061     puede utilizar para evitar la combinación de accesos a memoria de2062     de escritura antes de esta macro, con los posteriores, cuando dicha2063     espera tenga implicaciones en el rendimiento.2064 2065=========================================2066BARRERAS DE MEMORIA IMPLÍCITAS DEL KERNEL2067=========================================2068 2069Algunas de las otras funciones en el kernel Linux implican barreras de2070memoria, entre estas encontramos funciones de bloqueo y planificación2071("scheduling").2072 2073Esta especificación es una garantía _mínima_; cualquier arquitectura2074particular puede proporcionar garantías más sustanciales, pero no se puede2075confiar en estas fuera de código específico de arquitectura.2076 2077 2078FUNCIONES DE ADQUISICIÓN DE CERROJO2079-----------------------------------2080 2081El kernel Linux tiene una serie de abstracciones de bloqueo:2082 2083 (*) spin locks (cerrojos en loop)2084 (*) R/W spin lock (cerrojos de escritura/lectura)2085 (*) mutex2086 (*) semáforos2087 (*) R/W semáforos2088 2089En todos los casos existen variantes de las operaciones "ACQUIRE" y2090"RELEASE" para cada uno de ellos. Todas estas operaciones implican ciertas2091barreras:2092 2093 (1) Implicaciones de la operación ACQUIRE:2094 2095     Las operaciones de memoria emitidas después del ACQUIRE se completarán2096     después de que la operación ACQUIRE haya finalizado.2097 2098     Las operaciones de memoria emitidas antes de ACQUIRE pueden2099     completarse después que la operación ACQUIRE se ha completado.2100 2101 (2) Implicaciones de la operación RELEASE:2102 2103     Las operaciones de memoria emitidas antes de la RELEASE se2104     completarán antes de que la operación de RELEASE se haya completado.2105 2106     Las operaciones de memoria emitidas después de la RELEASE pueden2107     completarse antes de que la operación de RELEASE se haya completado.2108 2109 (3) Implicación de ACQUIRE vs ACQUIRE:2110 2111     Todas las operaciones ACQUIRE emitidas antes de otra operación2112     ACQUIRE serán completadas antes de esa operación ACQUIRE.2113 2114 (4) Implicación de ACQUIRE vs RELEASE:2115 2116     Todas las operaciones ACQUIRE emitidas antes de una operación RELEASE2117     serán completadas antes de la operación RELEASE.2118 2119 (5) Implicación de ACQUIRE condicional fallido:2120 2121     Ciertas variantes de bloqueo de la operación ACQUIRE pueden fallar, ya2122     sea debido a no poder obtener el bloqueo de inmediato, o debido a que2123     recibieron una señal de desbloqueo mientras dormían esperando que el2124     cerrojo estuviera disponible. Los fallos en cerrojos no implican2125     ningún tipo de barrera.2126 2127[!] Nota: una de las consecuencias de que los cerrojos en ACQUIRE y RELEASE2128sean barreras unidireccionales, es que los efectos de las instrucciones2129fuera de una sección crítica pueden filtrarse al interior de la sección2130crítica.2131 2132No se puede suponer que un ACQUIRE seguido de una RELEASE sea una barrera2133de memoria completa dado que es posible que un acceso anterior a ACQUIRE2134suceda después del ACQUIRE, y un acceso posterior a la RELEASE suceda antes2135del RELEASE, y los dos accesos puedan entonces cruzarse:2136 2137	*A = a;2138	ACQUIRE M2139	RELEASE M2140	*B = b;2141 2142puede ocurrir como:2143 2144	ACQUIRE M, STORE *B, STORE *A, RELEASE M2145 2146Cuando ACQUIRE y RELEASE son bloqueo de adquisición y liberación,2147respectivamente, este mismo orden puede ocurrir si el cerrojo ACQUIRE y2148RELEASE son para la misma variable de bloqueo, pero solo desde la2149perspectiva de otra CPU que no tiene ese bloqueo. En resumen, un ACQUIRE2150seguido de un RELEASE NO puede entenderse como una barrera de memoria2151completa.2152 2153De manera similar, el caso inverso de un RELEASE seguido de un ACQUIRE no2154implica una barrera de memoria completa. Por lo tanto, la ejecución de la2155CPU de los tramos críticos correspondientes a la RELEASE y la ACQUIRE2156pueden cruzarse, de modo que:2157 2158	*A = a;2159	RELEASE M2160	ACQUIRE N2161	*B = b;2162 2163puede ocurrir como:2164 2165	ACQUIRE N, STORE *B, STORE *A, RELEASE M2166 2167Podría parecer que este nuevo orden podría introducir un punto muerto.2168Sin embargo, esto no puede suceder porque si tal punto muerto amenazara2169con suceder, el RELEASE simplemente se completaría, evitando así el2170interbloqueo ("deadlock", punto muerto).2171 2172	¿Por qué funciona esto?2173 2174	Un punto clave es que solo estamos hablando de la CPU re-haciendo el2175  orden, no el compilador. Si el compilador (o, ya puestos, el2176  desarrollador) cambió las operaciones, un deadlock -podría- ocurrir.2177 2178	Pero supongamos que la CPU reordenó las operaciones. En este caso, el2179	desbloqueo precede al bloqueo en el código ensamblador. La CPU2180  simplemente eligió intentar ejecutar primero la última operación de2181  bloqueo. Si hay un interbloqueo, esta operación de bloqueo simplemente2182  esperará (o tratará de dormir, pero hablaremos de eso más adelante). La2183  CPU eventualmente ejecutará la operación de desbloqueo (que precedió a la2184	operación de bloqueo en el código ensamblador), lo que desenmascará el2185  potencial punto muerto, permitiendo que la operación de bloqueo tenga2186  éxito.2187 2188	Pero, ¿y si el cerrojo es un cerrojo que duerme ("sleeplock")? En tal2189  caso, el código intentará entrar al scheduler, donde eventualmente2190  encontrará una barrera de memoria, que forzará la operación de desbloqueo2191  anterior para completar, nuevamente desentrañando el punto muerto. Podría2192	haber una carrera de desbloqueo del sueño ("sleep-unlock race"), pero la2193  primitiva de bloqueo necesita resolver tales carreras correctamente en2194  cualquier caso.2195 2196Es posible que los cerrojos y los semáforos no proporcionen ninguna2197garantía de orden en sistemas compilados en UP, por lo que no se puede2198contar con tal situación para lograr realmente nada en absoluto,2199especialmente con respecto a los accesos de E/S, a menos que se combinen2200con operaciones de inhabilitación de interrupciones.2201 2202Consulte también la sección "Efectos de barrera adquiriendo intra-CPU".2203 2204 2205Como ejemplo, considere lo siguiente:2206 2207	*A = a;2208	*B = b;2209	ACQUIRE2210	*C = c;2211	*D = d;2212	RELEASE2213	*E = e;2214	*F = f;2215 2216La siguiente secuencia de eventos es aceptable:2217 2218	ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE2219 2220  [+] Tenga en cuenta que {*F,*A} indica un acceso combinado.2221 2222Pero ninguno de los siguientes lo son:2223 2224	{*F,*A}, *B,	ACQUIRE, *C, *D,	RELEASE, *E2225	*A, *B, *C,	ACQUIRE, *D,		RELEASE, *E, *F2226	*A, *B,		ACQUIRE, *C,		RELEASE, *D, *E, *F2227	*B,		ACQUIRE, *C, *D,	RELEASE, {*F,*A}, *E2228 2229 2230 2231FUNCIONES DE DESACTIVACIÓN DE INTERRUPCIONES2232--------------------------------------------2233 2234Las funciones que deshabilitan interrupciones (equivalentes a ACQUIRE) y2235habilitan interrupciones (equivalentes a RELEASE) actuarán únicamente como2236barrera del compilador. Por consiguiente, si la memoria o la E/S requieren2237barreras en tal situación, deben ser provistas por algún otro medio.2238 2239 2240FUNCIONES DE DORMIR Y DESPERTAR2241-------------------------------2242 2243Dormir y despertar son eventos marcados ("flagged") en los datos globales2244que se pueden ver como una interacción entre dos piezas de datos: el estado2245de la task (hilo, proceso, tarea) que espera el evento y los datos globales2246utilizados para indicar el evento. Para asegurarse de que estos parezcan2247suceder en el orden correcto, las primitivas para comenzar el proceso de ir2248a dormir, y las primitivas para iniciar un despertar implican ciertas2249barreras.2250 2251En primer lugar, el agente durmiente normalmente sigue algo similar a esta2252secuencia de eventos:2253 2254	for (;;) {2255		set_current_state(TASK_UNINTERRUPTIBLE);2256		if (evento_indicado)2257			break;2258		schedule(); // planificar2259	}2260 2261Una barrera de memoria general se obtiene automáticamente mediante2262set_current_state() después de haber alterado el estado de la tarea:2263 2264	CPU 12265	===============================2266	set_current_state(); // hacer_estado_actual()2267	  smp_store_mb();2268	    STORE current->state2269	    <barrera general>2270	LOAD evento_indicado2271 2272set_current_state() puede estar envuelto por:2273 2274	prepare_to_wait(); // preparese_para_esperar();2275	prepare_to_wait_exclusive(); // prepararse_para_solo_esperar();2276 2277que por lo tanto también implican una barrera de memoria general después de2278establecer el estado. Toda la secuencia anterior está disponible en varias2279formas, todas las cuales obtienen la barrera de memoria en el lugar2280correcto:2281 2282	wait_event();2283	wait_event_interruptible();2284	wait_event_interruptible_exclusive();2285	wait_event_interruptible_timeout();2286	wait_event_killable();2287	wait_event_timeout();2288	wait_on_bit();2289	wait_on_bit_lock();2290 2291 2292En segundo lugar, el código que realiza una activación normalmente se2293asemeja a algo como esto:2294 2295	evento_indicado = 1;2296	wake_up(&event_wait_queue); // despertar2297 2298o:2299 2300	evento_indicado = 1;2301	wake_up_process(event_daemon); // despertar proceso2302 2303wake_up() ejecuta una barrera de memoria general si despierta algo. Si no2304despierta nada, entonces una barrera de memoria puede o no ser ejecutada;2305no debe confiar en ello. La barrera se produce antes del acceso al estado2306de la tarea. En particular, se encuentra entre el STORE para indicar el2307evento y el STORE para configurar TASK_RUNNING (hilo ejecutando):2308 2309	CPU 1 (Durmiente)			CPU 2 (Despertadora)2310	===============================	===============================2311	set_current_state();		STORE evento_indicado2312	  smp_store_mb();		wake_up();2313	    STORE current->state	  ...2314	    <barrera general>		  <barrera general>2315	LOAD evento_indicado		  if ((LOAD task->state) & TASK_NORMAL)2316					    STORE task->state2317 2318donde "task" es el subproceso que se está despertando y es igual al2319"current" (hilo actual) de la CPU 1.2320 2321Para reiterar, se garantiza la ejecución de una barrera de memoria general2322mediante wake_up() si algo está realmente despierto, pero de lo contrario2323no existe tal garantía. Para entender esto, considere la siguiente2324secuencia de eventos, donde X e Y son ambos cero inicialmente:2325 2326	CPU 1				CPU 22327	===============================	===============================2328	X = 1;				Y = 1;2329	smp_mb();			wake_up();2330	LOAD Y				LOAD X2331 2332Si ocurre una reactivación ("wakeup"), una (al menos) de las dos cargas2333debe ver 1. Si, por otro lado, no ocurre una reactivación, ambas cargas2334pueden ver 0.2335 2336wake_up_process() siempre ejecuta una barrera de memoria general. La2337barrera, de nuevo, ocurre antes de que se acceda al estado del hilo. En2338particular, si wake_up(), en el fragmento anterior, fuera reemplazado por2339una llamada a wake_up_process(), las dos cargas verían 1, garantizado.2340 2341Las funciones de activación disponibles incluyen:2342 2343	complete();2344	wake_up();2345	wake_up_all();2346	wake_up_bit();2347	wake_up_interruptible();2348	wake_up_interruptible_all();2349	wake_up_interruptible_nr();2350	wake_up_interruptible_poll();2351	wake_up_interruptible_sync();2352	wake_up_interruptible_sync_poll();2353	wake_up_locked();2354	wake_up_locked_poll();2355	wake_up_nr();2356	wake_up_poll();2357	wake_up_process();2358 2359En términos de orden de la memoria, todas estas funciones proporcionan las2360mismas garantías que un wake_up() (o más fuertes).2361 2362[!] Tenga en cuenta que las barreras de la memoria implicadas por el2363durmiente y el despierto _no_ ordenan varios stores antes del despertar con2364respecto a cargas de los valores guardados después de que el durmiente haya2365llamado a set_current_state(). Por ejemplo, si el durmiente hace:2366 2367	set_current_state(TASK_INTERRUPTIBLE);2368	if (evento_indicado)2369		break;2370	__set_current_state(TASK_RUNNING);2371	hacer_algo(my_data);2372 2373y el que despierta hace:2374 2375	my_data = valor;2376	evento_indicado = 1;2377	wake_up(&event_wait_queue);2378 2379no existe garantía de que el cambio a event_indicated sea percibido por2380el durmiente de manera que venga después del cambio a my_data. En tal2381circunstancia, el código en ambos lados debe sacar sus propias barreras de2382memoria entre los separados accesos a datos. Por lo tanto, el durmiente2383anterior debería hacer:2384 2385	set_current_state(TASK_INTERRUPTIBLE);2386	if (evento_indicado) {2387		smp_rmb();2388		hacer_algo(my_data);2389	}2390 2391y el que despierta debería hacer:2392 2393	my_data = value;2394	smp_wmb();2395	evento_indicado = 1;2396	wake_up(&event_wait_queue);2397 2398FUNCIONES VARIAS2399----------------2400 2401Otras funciones que implican barreras:2402 2403 (*) schedule() y similares implican barreras completas de memoria.2404 2405 2406========================================2407EFECTOS DE BARRERA ADQUIRIENDO INTRA-CPU2408========================================2409 2410En los sistemas SMP, las primitivas de bloqueo proveen una forma más2411sustancial de barrera: una que afecta el orden de acceso a la memoria en2412otras CPU, dentro del contexto de conflicto en cualquier bloqueo en2413particular.2414 2415 2416ADQUISICIÓN VS ACCESOS A MEMORIA2417--------------------------------2418 2419Considere lo siguiente: el sistema tiene un par de spinlocks (M) y (Q), y2420tres CPU; entonces la siguiente secuencia de eventos debería ocurrir:2421 2422	CPU 1				CPU 22423	===============================	===============================2424	WRITE_ONCE(*A, a);		WRITE_ONCE(*E, e);2425	ACQUIRE M			ACQUIRE Q2426	WRITE_ONCE(*B, b);		WRITE_ONCE(*F, f);2427	WRITE_ONCE(*C, c);		WRITE_ONCE(*G, g);2428	RELEASE M			RELEASE Q2429	WRITE_ONCE(*D, d);		WRITE_ONCE(*H, h);2430 2431Entonces no hay garantía sobre en qué orden verá la CPU 3 los accesos a *A2432hasta que *H ocurra, además de las restricciones impuestas por los bloqueos2433separados en las distintas CPUs. Podría, por ejemplo, ver:2434 2435	*E, ACQUIRE M, ACQUIRE Q, *G, *C, *F, *A, *B, RELEASE Q, *D, *H, RELEASE M2436 2437Pero no verá ninguno de:2438 2439	*B, *C or *D preceding ACQUIRE M2440	*A, *B or *C following RELEASE M2441	*F, *G or *H preceding ACQUIRE Q2442	*E, *F or *G following RELEASE Q2443 2444========================================2445¿DÓNDE SE NECESITAN BARRERAS DE MEMORIA?2446========================================2447 2448Bajo operación normal, el re-ordenamiento de una operación de memoria2449generalmente no va a suponer un problema, ya que para una pieza de código2450lineal de un solo subproceso seguirá pareciendo que funciona correctamente,2451incluso si está en un kernel SMP. Existen, sin embargo, cuatro2452circunstancias en las que reordenar definitivamente _podría_ ser un2453problema:2454 2455 (*) Interacción entre procesadores.2456 2457 (*) Operaciones atómicas.2458 2459 (*) Acceso a dispositivos.2460 2461 (*) Interrupciones.2462 2463 2464INTERACCIÓN ENTRE PROCESADORES2465------------------------------2466 2467Cuando se da un sistema con más de un procesador, más de una CPU en el2468sistema puede estar trabajando en el mismo conjunto de datos al mismo2469tiempo. Esto puede causar problemas de sincronización, y la forma habitual2470de tratar con estos es utilizar cerrojos. Sin embargo, los cerrojos son2471bastante caros, por lo que puede ser preferible operar sin el uso de un2472cerrojo a ser posible. En cuyo caso, es posible que las operaciones que2473afectan a ambas CPU deban ordenarse cuidadosamente para evitar un2474funcionamiento incorrecto.2475 2476Considere, por ejemplo, la ruta lenta del semáforo R/W. Aquí hay un proceso2477de espera en cola del semáforo, en virtud de que tiene una parte de su pila2478vinculada a la lista de procesos en espera del semáforo:2479 2480	struct rw_semaphore {2481		...2482		spinlock_t lock;2483		struct list_head waiters;2484	};2485 2486	struct rwsem_waiter {2487		struct list_head list;2488		struct task_struct *task;2489	};2490 2491Para despertar a un proceso que espera ("waiter") en particular, las2492funciones up_read() o up_write() tienen que:2493 2494 (1) leer el siguiente puntero del registro de este proceso que espera,2495     para saber dónde está el registro del siguiente waiter;2496 2497 (2) leer el puntero a la estructura de tareas del waiter;2498 2499 (3) borrar el puntero de la tarea para decirle al waiter que se le ha dado2500     el semáforo;2501 2502 (4) llamar a wake_up_process() en la tarea; y2503 2504 (5) liberar la referencia retenida en la estructura de tareas del waiter.2505 2506En otras palabras, tiene que realizar esta secuencia de eventos:2507 2508	LOAD waiter->list.next;2509	LOAD waiter->task;2510	STORE waiter->task;2511	CALL wakeup2512	RELEASE task2513 2514y si alguno de estos pasos ocurre fuera de orden, entonces todo puede que2515funcione defectuosamente.2516 2517Una vez que se ha puesto en cola y soltado el bloqueo de semáforo, el2518proceso que espera no consigue el candado de nuevo; en cambio, solo espera2519a que se borre su puntero de tarea antes de continuar. Dado que el registro2520está en la pila del proceso que espera, esto significa que si el puntero de2521la tarea se borra _antes_ de que se lea el siguiente puntero de la lista,2522otra CPU podría comenzar a procesar el proceso que espera y podría romper2523el stack del proceso que espera antes de que la función up*() tenga la2524oportunidad de leer el puntero que sigue.2525 2526Considere entonces lo que podría suceder con la secuencia de eventos2527anterior:2528 2529	CPU 1				CPU 22530	===============================	===============================2531					down_xxx()2532					Poner waiter en la "queue" (cola)2533					Dormir2534	up_yyy()2535	LOAD waiter->task;2536	STORE waiter->task;2537					Despertado por otro evento2538	<preempt>2539					Reanudar el procesamiento2540					down_xxx() regresa2541					llamada a foo()2542					foo() estropea *waiter2543	</preempt>2544	LOAD waiter->list.next;2545	--- OOPS ---2546 2547Esto podría solucionarse usando el bloqueo de semáforo, pero luego la2548función down_xxx() tiene que obtener innecesariamente el spinlock2549nuevamente, después de ser despertado el hilo.2550 2551La forma de lidiar con esto es insertar una barrera de memoria SMP general:2552 2553	LOAD waiter->list.next;2554	LOAD waiter->task;2555	smp_mb();2556	STORE waiter->task;2557	CALL wakeup2558	RELEASE task2559 2560En este caso, la barrera garantiza que todos los accesos a memoria antes de2561la barrera parecerán suceder antes de todos los accesos a memoria después2562de dicha barrera con respecto a las demás CPU del sistema. _No_ garantiza2563que todos los accesos a memoria antes de la barrera se completarán en el2564momento en que la instrucción de la barrera en sí se complete.2565 2566En un sistema UP, donde esto no sería un problema, la función smp_mb() es2567solo una barrera del compilador, asegurándose así de que el compilador2568emita las instrucciones en el orden correcto sin realmente intervenir en la2569CPU. Como solo hay un CPU, la lógica de orden de dependencias de esa CPU se2570encargará de todo lo demás.2571 2572 2573OPERACIONES ATÓMICAS2574--------------------2575 2576Si bien son, técnicamente, consideraciones de interacción entre2577procesadores, las operaciones atómicas se destacan especialmente porque2578algunas de ellas implican barreras de memoria completa y algunas otras no,2579pero se confía mucho en ellos en su conjunto a lo largo del kernel.2580 2581Consulte Documentation/atomic_t.txt para obtener más información.2582 2583 2584ACCESO A DISPOSITIVOS2585---------------------2586 2587Un driver puede ser interrumpido por su propia rutina de servicio de2588interrupción y, por lo tanto, las dos partes del driver pueden interferir2589con los intentos de controlar o acceder al dispositivo.2590 2591Esto puede aliviarse, al menos en parte, desactivando las interrupciones2592locales (una forma de bloqueo), de modo que las operaciones críticas sean2593todas contenidas dentro la sección de interrupción desactivada en el2594controlador. Mientras la interrupción del driver está ejecutando la rutina,2595es posible que el "core" del controlador no se ejecute en la misma CPU y no2596se permita que su interrupción vuelva a ocurrir hasta que la interrupción2597actual haya sido resuelta, por lo tanto, el controlador de interrupción no2598necesita bloquearse contra esto.2599 2600Sin embargo, considere un driver que estaba hablando con una tarjeta2601ethernet que tiene un registro de direcciones y un registro de datos. Si2602el core de ese controlador habla con la tarjeta estando en desactivación de2603interrupción y luego se invoca el controlador de interrupción del2604controlador:2605 2606	IRQ LOCALES DESACTIVADAS2607	writew(ADDR, 3);2608	writew(DATA, y);2609	IRQ LOCALES ACTIVADAS2610	<interrupción>2611	writew(ADDR, 4);2612	q = readw(DATA);2613	</interrupción>2614 2615El almacenamiento en el registro de datos puede ocurrir después del segundo2616almacenamiento en el registro de direcciones si las reglas de orden son lo2617suficientemente relajadas:2618 2619  	STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA2620 2621Si se relajan las reglas de orden, se debe asumir que los accesos2622realizados dentro de la sección con interrupción deshabilitada pueden2623filtrarse fuera de esta y pueden intercalarse con accesos realizados en una2624interrupción - y viceversa - a menos que se utilicenn barreras implícita o2625explícitas.2626 2627Normalmente, esto no será un problema porque los accesos de E/S realizados2628dentro de tales secciones incluirán operaciones de carga síncronas en2629registros E/S estrictamente ordenados, que forman barreras de E/S2630implícitas.2631 2632 2633Una situación similar puede ocurrir entre una rutina de interrupción y dos2634rutinas ejecutándose en separadas CPU que se comunican entre sí. Si tal2635caso es probable, entonces se deben usar bloqueos de desactivación de2636interrupciones para garantizar el orden.2637 2638 2639=====================================2640 Efectos de barrera de E/S del kernel2641=====================================2642 2643La interfaz con periféricos a través de accesos de E/S es profundamente2644específica para cada arquitectura y dispositivo. Por lo tanto, los drivers2645que son inherentemente no portátiles pueden depender de comportamientos2646específicos de sus sistemas de destino, con el fin de lograr la2647sincronización de la manera más ligera posible. Para drivers que deseen ser2648portátiles entre múltiples arquitecturas e implementaciones de bus, el2649kernel ofrece una serie de funciones de acceso que proporcionan varios2650grados de garantías de orden:2651 2652 (*) readX(), writeX():2653 2654	Las funciones de acceso MMIO readX() y writeX() usan un puntero al2655	periférico al que se accede como un parámetro __iomem *. para punteros2656	asignados los atributos de E/S predeterminados (por ejemplo, los2657        devueltos por ioremap()), las garantías de orden son las siguientes:2658 2659	1. Se ordenan todos los accesos readX() y writeX() a un mismo periférico2660	   entre estos. Esto asegura que los registros de acceso MMIO por el2661	   mismo subproceso de la CPU a un dispositivo en particular llegarán en2662	   el orden del programa.2663 2664	2. Se ordena un writeX() emitido por un subproceso de CPU que contiene un2665	   spinlock antes de un writeX() al mismo periférico desde otro2666           subproceso de CPU, si emitido después de una adquisición posterior del2667	   mismo spinlock. Esto garantiza que ese registro MMIO escribe en un2668           dispositivo en particular, mientras que se obtiene un spinlock en un2669           orden consistente con las adquisiciones del cerrojo.2670 2671	3. Un writeX() por un subproceso de la CPU al periférico primero esperará2672	   a la finalización de todas las escrituras anteriores en la memoria2673           emitidas por, o bien propagadas por, el mismo subproceso. Esto asegura2674	   que las escrituras de la CPU a un búfer DMA de salida asignadas por2675           dma_alloc_coherent() serán visibles para un motor ("engine") DMA2676           cuando la CPU escriba en sus registros de control MMIO, para activar2677           la transferencia.2678 2679	4. Un readX() de un subproceso del CPU, desde el periférico, se2680	   completará antes de que cualquier lectura subsiguiente de memoria por2681	   el mismo subproceso pueda comenzar. Esto asegura que las lecturas de2682           la CPU desde un búfer DMA entrantes asignadas por2683           dma_alloc_coherent(), no verán datos obsoletos después de leer el2684           registro de estado MMIO del motor DMA, para establecer que la2685           transferencia DMA se haya completado.2686 2687	5. Un readX() por un subproceso del CPU, desde el periférico, se2688	   completará antes de que cualquier bucle delay() subsiguiente pueda2689           comenzar a ejecutarse en el mismo subproceso. Esto asegura que dos2690           escrituras del CPU a registros MMIO en un periférico llegarán al menos2691	   con 1us de diferencia, si la primera escritura se lee inmediatamente2692           de vuelta con readX() y se llama a udelay(1) antes del segundo2693           writeX():2694 2695		writel(42, DEVICE_REGISTER_0); // Llega al dispositivo ...2696		readl(DEVICE_REGISTER_0);2697		udelay(1);2698		writel(42, DEVICE_REGISTER_1); // al menos 1us antes de esto....2699 2700Las propiedades de orden de los punteros __iomem obtenidos con valores de2701atributos que no sean los valores por defecto (por ejemplo, los devueltos2702por ioremap_wc()) son específicos de la arquitectura subyacente y, por lo2703tanto, las garantías enumeradas anteriormente no pueden por lo general ser2704aseguradas para accesos a este tipo de "mappings" (asignaciones).2705 2706 (*) readX_relaxed(), writeX_relaxed():2707 2708	Son similares a readX() y writeX(), pero proporcionan una garantía de2709        orden de memoria más débil. Específicamente, no garantizan orden con2710	respecto al bloqueo, los accesos normales a la memoria o los bucles2711        delay() (es decir, los puntos 2-5 arriba) pero todavía se garantiza que2712        se ordenarán con respecto a otros accesos desde el mismo hilo de la CPU,2713        al mismo periférico, cuando se opera en punteros __iomem asignados con el2714        valor predeterminado para los atributos de E/S.2715 2716 (*) readsX(), writesX():2717 2718	Los puntos de entrada readsX() y writesX() MMIO están diseñados para2719        acceder FIFOs mapeados en memoria y basados en registros que residen en2720        periféricos, que no son capaces de realizar DMA. Por tanto, sólo2721        proporcionan garantías de orden readX_relaxed() y writeX_relaxed(), como2722        se documentó anteriormente.2723 2724 (*) inX(), outX():2725 2726	Los puntos de entrada inX() y outX() están destinados a acceder a mapas2727        de puertos "legacy" (antiguos) de periféricos de E/S, que pueden requerir2728	instrucciones especiales en algunas arquitecturas (especialmente, en2729        x86). El número de puerto del periférico que se está accedido se pasa2730        como un argumento.2731 2732	Dado que muchas arquitecturas de CPU acceden finalmente a estos2733        periféricos a través de un mapeo interno de memoria virtual, las2734        garantías de orden portátiles proporcionadas por inX() y outX() son las2735        mismas que las proporcionadas por readX() y writeX(), respectivamente, al2736        acceder a una asignación con los valores de atributos de E/S2737        predeterminados (los que haya por defecto).2738 2739        Los drivers de dispositivos pueden esperar que outX() emita una2740        transacción de escritura no publicada, que espera una respuesta de2741        finalización del periférico de E/S antes de regresar. Esto no está2742        garantizado por todas las arquitecturas y por lo tanto no forma parte de2743        la semántica de orden portátil.2744 2745 (*) insX(), outsX():2746 2747        Como arriba, los puntos de entrada insX() y outsX() proporcionan el mismo2748        orden garantizado por readsX() y writesX() respectivamente, al acceder a2749        un mapping con los atributos de E/S predeterminados.2750 2751 (*) ioreadX(), iowriteX():2752 2753        Estos funcionarán adecuadamente para el tipo de acceso que realmente están2754        haciendo, ya sea inX()/outX() o readX()/writeX().2755 2756Con la excepción de los puntos de entrada (insX(), outsX(), readsX() y2757writesX()), todo lo anterior supone que el periférico subyacente es2758little-endian y, por lo tanto, realizará operaciones de intercambio de2759bytes en arquitecturas big-endian.2760 2761 2762===========================================2763MODELO DE ORDEN MÍNIMO DE EJECUCIÓN ASUMIDO2764===========================================2765 2766Debe suponerse que la CPU conceptual está débilmente ordenada, pero que2767mantiene la apariencia de causalidad del programa con respecto a sí misma.2768Algunas CPU (como i386 o x86_64) están más limitadas que otras (como2769powerpc o frv), por lo que el caso más relajado (es decir, DEC Alpha) se2770debe asumir fuera de código específico de arquitectura.2771 2772Esto significa que se debe considerar que la CPU ejecutará su flujo de2773instrucciones en el orden que se quiera - o incluso en paralelo - siempre2774que si una instrucción en el flujo depende de una instrucción anterior,2775entonces dicha instrucción anterior debe ser lo suficientemente completa[*]2776antes de que la posterior instrucción puede proceder; en otras palabras:2777siempre que la apariencia de causalidad se mantenga.2778 2779 [*] Algunas instrucciones tienen más de un efecto, como cambiar el2780     código de condición, cambio de registros o cambio de memoria - y2781     distintas instrucciones pueden depender de diferentes efectos.2782 2783Una CPU puede también descartar cualquier secuencia de instrucciones que2784termine sin tener efecto final. Por ejemplo, si dos instrucciones2785adyacentes cargan un valor inmediato en el mismo registro, la primera puede2786descartarse.2787 2788 2789De manera similar, se debe suponer que el compilador podría reordenar la2790corriente de instrucciones de la manera que crea conveniente, nuevamente2791siempre que la apariencia de causalidad se mantenga.2792 2793 2794=====================================2795EFECTOS DE LA MEMORIA CACHÉ DE LA CPU2796=====================================2797 2798La forma en que se perciben las operaciones de memoria caché en todo el2799sistema se ve afectada, hasta cierto punto, por los cachés que se2800encuentran entre las CPU y la memoria, y por el sistema de coherencia en2801memoria que mantiene la consistencia de estado en el sistema.2802 2803En cuanto a la forma en que una CPU interactúa con otra parte del sistema a2804través del caché, el sistema de memoria tiene que incluir los cachés de la2805CPU y barreras de memoria, que en su mayor parte actúan en la interfaz2806entre la CPU y su caché (las barreras de memoria lógicamente actúan sobre2807la línea de puntos en el siguiente diagrama):2808 2809	    <--- CPU --->         :       <----------- Memoria ----------->2810	                          :2811	+--------+    +--------+  :   +--------+    +-----------+2812	|  Core  |    | Cola   |  :   | Cache  |    |           |    +---------+2813	|  CPU   |    | de     |  :   | CPU    |    |           |    |         |2814	|        |--->| acceso |----->|        |<-->|           |    |         |2815	|        |    | a      |  :   |        |    |           |--->| Memoria |2816	|        |    | memoria|  :   |        |    |           |    |         |2817	+--------+    +--------+  :   +--------+    | Mecanismo |    |         |2818	                          :                 | de        |    +---------+2819	                          :                 | Coherencia|2820	                          :                 | de la     |    +--------+2821	+--------+    +--------+  :   +--------+    | cache     |    |	      |2822	|  Core  |    | Cola   |  :   | Cache  |    |           |    |        |2823	|  CPU   |    | de     |  :   | CPU    |    |           |--->| Dispos |2824	|        |--->| acceso |----->|        |<-->|           |    | itivo  |2825	|        |    | a      |  :   |        |    |           |    |        |2826	|        |    | memoria|  :   |        |    |           |    +--------+2827	+--------+    +--------+  :   +--------+    +-----------+2828	                          :2829	                          :2830 2831Aunque es posible que una carga o store en particular no aparezca fuera de2832la CPU que lo emitió, ya que puede haber sido satisfecha dentro del propio2833caché de la CPU, seguirá pareciendo como si el acceso total a la memoria2834hubiera tenido lugar para las otras CPUs, ya que los mecanismos de2835coherencia de caché migrarán la cacheline sobre la CPU que accede y se2836propagarán los efectos en caso de conflicto.2837 2838El núcleo de la CPU puede ejecutar instrucciones en el orden que considere2839adecuado, siempre que parezca mantenerse la causalidad esperada del2840programa. Algunas de las instrucciones generan operaciones de carga y2841almacenamiento que luego van a la cola de accesos a memoria a realizar. El2842núcleo puede colocarlos en la cola en cualquier orden que desee, y2843continuar su ejecución hasta que se vea obligado a esperar que una2844instrucción sea completada.2845 2846De lo que se ocupan las barreras de la memoria es de controlar el orden en2847que los accesos cruzan, desde el lado de la CPU, hasta el lado de memoria,2848y el orden en que los otros observadores perciben los efectos en el sistema2849que sucedan por esto.2850 2851[!] Las barreras de memoria _no_ son necesarias dentro de una CPU2852determinada, ya que las CPU siempre ven sus propias cargas y stores como si2853hubieran sucedido en el orden del programa.2854 2855[!] Los accesos a MMIO u otros dispositivos pueden pasar por alto el2856sistema de caché. Esto depende de las propiedades de la ventana de memoria2857a través de la cual se accede a los dispositivos y/o el uso de2858instrucciones especiales de comunicación con dispositivo que pueda tener la2859CPU.2860 2861 2862COHERENCIA DE CACHÉ FRENTE A DMA2863---------------------------------2864 2865No todos los sistemas mantienen coherencia de caché con respecto a los2866dispositivos que realizan DMA. En tales casos, un dispositivo que intente2867DMA puede obtener datos obsoletos de la RAM, porque las líneas de caché2868"sucias" pueden residir en los cachés de varias CPU, y es posible que no2869se hayan vuelto a escribir en la RAM todavía. Para hacer frente a esto, la2870parte apropiada del kernel debe vaciar los bits superpuestos de caché en2871cada CPU (y tal vez también invalidarlos).2872 2873Además, los datos enviados por DMA a RAM, por un dispositivo, pueden ser2874sobrescritos por líneas de caché sucias que se escriben de nuevo en la RAM2875desde el caché de una CPU, después de que el dispositivo haya puesto sus2876propios datos, o las líneas de caché presentes en el caché de la CPU pueden2877simplemente ocultar el hecho de que la memoria RAM se haya actualizado,2878hasta el momento en que la caché se descarta de la memoria caché de la CPU2879y se vuelve a cargar. Para hacer frente a esto, la parte apropiada del2880kernel debe invalidar los bits superpuestos del caché en cada CPU.2881 2882Consulte Documentation/core-api/cachetlb.rst para obtener más información2883sobre administración de la memoria caché.2884 2885 2886COHERENCIA DE CACHÉ FRENTE A MMIO2887---------------------------------2888 2889La E/S mapeada en memoria generalmente se lleva a cabo a través de2890ubicaciones de memoria que forman parte de una ventana del espacio de2891memoria de la CPU, que tiene diferentes propiedades asignadas que la2892ventana habitual dirigida a RAM.2893 2894Entre dichas propiedades, suele existir el hecho de que tales accesos2895eluden el almacenamiento en caché por completo e ir directamente a los2896buses del dispositivo. Esto significa que los accesos MMIO pueden, en2897efecto, superar los accesos a la memoria caché que se emitieron2898anteriormente. Una barrera de memoria no es suficiente en tal caso, sino2899que el caché debe ser vaciado entre la escritura de la memoria caché, y el2900acceso MMIO, si los dos son de cualquier manera dependiente.2901 2902 2903=======================2904COSAS QUE HACEN LAS CPU2905=======================2906 2907Un programador podría dar por sentado que la CPU realizará las operaciones2908de memoria exactamente en el orden especificado, de modo que si a la CPU se2909entrega, por ejemplo, el siguiente fragmento de código a ejecutar:2910 2911	a = READ_ONCE(*A);2912	WRITE_ONCE(*B, b);2913	c = READ_ONCE(*C);2914	d = READ_ONCE(*D);2915	WRITE_ONCE(*E, e);2916 2917esperarían entonces que la CPU complete la operación de memoria para cada2918instrucción antes de pasar a la siguiente, lo que lleva a una definida2919secuencia de operaciones vistas por observadores externos en el sistema:2920 2921  	LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.2922 2923La realidad es, por supuesto, mucho más intrincada. Para muchas CPU y2924compiladores, la anterior suposición no se sostiene porque:2925 2926 (*) es más probable que las cargas deban completarse de inmediato para2927     permitir progreso en la ejecución, mientras que los stores a menudo se2928     pueden aplazar sin problema;2929 2930 (*) las cargas se pueden hacer especulativamente, y el resultado es2931     descartado si resulta innecesario;2932 2933 (*) las cargas se pueden hacer de forma especulativa, lo que lleva a que2934     se haya obtenido el resultado en el momento equivocado de la secuencia2935     de eventos esperada;2936 2937 (*) el orden de los accesos a memoria se puede reorganizar para promover2938     un mejor uso de los buses y cachés de la CPU;2939 2940 (*) las cargas y los stores se pueden combinar para mejorar el rendimiento2941     cuando se habla con memoria o hardware de E/S, que puede realizar2942     accesos por lotes a ubicaciones adyacentes, reduciendo así los costes2943     de configuración de transacciones (la memoria y los dispositivos PCI2944     pueden ambos pueden hacer esto); y2945 2946 (*) la caché de datos de la CPU puede afectar al orden, y mientras sus2947     mecanismos de coherencia pueden aliviar esto, una vez que el store2948     haya accedido al caché- no hay garantía de que la gestión de la2949     coherencia se propague en orden a otras CPU.2950 2951Entonces, digamos que lo que otra CPU podría observar en el fragmento de2952código anterior es:2953 2954	LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B2955 2956	(Donde "LOAD {*C,*D}" es una carga combinada)2957 2958 2959Sin embargo, se garantiza que una CPU es autoconsistente: verá que sus2960 _propios_ accesos parecen estar correctamente ordenados, sin necesidad de2961barrera de memoria. Por ejemplo con el siguiente código:2962 2963	U = READ_ONCE(*A);2964	WRITE_ONCE(*A, V);2965	WRITE_ONCE(*A, W);2966	X = READ_ONCE(*A);2967	WRITE_ONCE(*A, Y);2968	Z = READ_ONCE(*A);2969 2970y asumiendo que no hay intervención de una influencia externa, se puede2971suponer que el resultado final se parecerá a:2972 2973	U == el valor original de *A2974	X == W2975	Z == Y2976	*A == Y2977 2978El código anterior puede hacer que la CPU genere la secuencia completa de2979accesos de memoria:2980 2981	U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A2982 2983en ese orden, pero, sin intervención, la secuencia puede contener casi2984cualquier combinación de elementos combinados o descartados, siempre que la2985perspectiva del programa del mundo siga siendo consistente. Tenga en cuenta2986que READ_ONCE() y WRITE_ONCE() -no- son opcionales en el ejemplo anterior,2987ya que hay arquitecturas donde una CPU determinada podría reordenar cargas2988sucesivas en la misma ubicación. En tales arquitecturas, READ_ONCE() y2989WRITE_ONCE() hacen lo que sea necesario para evitar esto, por ejemplo, en2990Itanium los casts volátiles utilizados por READ_ONCE() y WRITE_ONCE() hacen2991que GCC emita las instrucciones especiales ld.acq y st.rel2992(respectivamente) que impiden dicha reordenación.2993 2994El compilador también puede combinar, descartar o diferir elementos de la2995secuencia antes incluso de que la CPU los vea.2996 2997Por ejemplo:2998 2999	*A = V;3000	*A = W;3001 3002puede reducirse a:3003 3004	*A = W;3005 3006ya que, sin una barrera de escritura o WRITE_ONCE(), puede que se asuma3007que el efecto del almacenamiento de V a *A se pierde. Similarmente:3008 3009  	*A = Y;3010  	Z = *A;3011 3012puede, sin una barrera de memoria o un READ_ONCE() y WRITE_ONCE(), esto3013sea reducido a:3014 3015  	*A = Y;3016  	Z = Y;3017 3018y la operación LOAD nunca aparezca fuera de la CPU.3019 3020 3021Y LUEGO ESTÁ EL ALFA3022--------------------3023 3024La CPU DEC Alpha es una de las CPU más relajadas que existen. No solo eso,3025algunas versiones de la CPU Alpha tienen un caché de datos dividido, lo que3026les permite tener dos líneas de caché relacionadas semánticamente,3027actualizadas en momentos separados. Aquí es donde la barrera de dependencia3028de dirección realmente se vuelve necesaria, ya que se sincronizan ambos3029cachés con el sistema de coherencia de memoria, lo que hace que parezca un3030cambio en el puntero, frente a que los nuevos datos se produzcan en el3031orden correcto.3032 3033Alpha define el modelo de memoria del kernel Linux, aunque a partir de3034v4.15, la adición al kernel de Linux de smp_mb() a READ_ONCE() en Alpha3035redujo en gran medida su impacto en el modelo de memoria.3036 3037 3038GUESTS DE MÁQUINAS VIRTUALES3039-----------------------------3040 3041Los "guests" (invitados) que se ejecutan en máquinas virtuales pueden verse3042afectados por los efectos de SMP incluso si el "host" (huésped) en sí se3043compila sin compatibilidad con SMP. Este es un efecto de la interacción con3044un host SMP mientras ejecuta un kernel UP. El uso obligatorio de barreras3045para este caso de uso sería posible, pero a menudo no son óptimas.3046 3047Para hacer frente a este caso de manera óptima, están disponibles macros de3048bajo nivel virt_mb() etc. Estas tienen el mismo efecto que smp_mb(), etc.3049cuando SMP está habilitado, pero generan código idéntico para sistemas SMP3050y no SMP. Por ejemplo, los invitados de máquinas virtuales debería usar3051virt_mb() en lugar de smp_mb() al sincronizar contra un (posiblemente SMP)3052anfitrión.3053 3054Estos son equivalentes a sus contrapartes smp_mb() etc. en todos los demás3055aspectos, en particular, no controlan los efectos MMIO: para controlar los3056efectos MMIO, utilice barreras obligatorias.3057 3058 3059================3060EJEMPLOS DE USOS3061================3062 3063BUFFERS CIRCULARES3064------------------3065 3066Las barreras de memoria se pueden utilizar para implementar almacenamiento3067en búfer circular, sin necesidad de un cerrojo para serializar al productor3068con el consumidor. Vea:3069 3070	Documentation/core-api/circular-buffers.rst3071 3072para más detalles.3073 3074 3075===========3076REFERENCIAS3077===========3078 3079Alpha AXP Architecture Reference Manual, Segunda Edición (por Sites & Witek,3080Digital Press)3081	Capítulo 5.2: Physical Address Space Characteristics3082	Capítulo 5.4: Caches and Write Buffers3083	Capítulo 5.5: Data Sharing3084	Capítulo 5.6: Read/Write Ordering3085 3086AMD64 Architecture Programmer's Manual Volumen 2: System Programming3087	Capítulo 7.1: Memory-Access Ordering3088	Capítulo 7.4: Buffering and Combining Memory Writes3089 3090ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)3091	Capítulo B2: The AArch64 Application Level Memory Model3092 3093IA-32 Intel Architecture Software Developer's Manual, Volumen 3:3094System Programming Guide3095	Capítulo 7.1: Locked Atomic Operations3096	Capítulo 7.2: Memory Ordering3097	Capítulo 7.4: Serializing Instructions3098 3099The SPARC Architecture Manual, Version 93100	Capítulo 8: Memory Models3101	Appendix D: Formal Specification of the Memory Models3102	Appendix J: Programming with the Memory Models3103 3104Storage in the PowerPC (por Stone and Fitzgerald)3105 3106UltraSPARC Programmer Reference Manual3107	Capítulo 5: Memory Accesses and Cacheability3108	Capítulo 15: Sparc-V9 Memory Models3109 3110UltraSPARC III Cu User's Manual3111	Capítulo 9: Memory Models3112 3113UltraSPARC IIIi Processor User's Manual3114	Capítulo 8: Memory Models3115 3116UltraSPARC Architecture 20053117	Capítulo 9: Memory3118	Appendix D: Formal Specifications of the Memory Models3119 3120UltraSPARC T1 Supplement to the UltraSPARC Architecture 20053121	Capítulo 8: Memory Models3122	Appendix F: Caches and Cache Coherency3123 3124Solaris Internals, Core Kernel Architecture, p63-68:3125	Capítulo 3.3: Hardware Considerations for Locks and3126			Synchronization3127 3128Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching3129for Kernel Programmers:3130	Capítulo 13: Other Memory Models3131 3132Intel Itanium Architecture Software Developer's Manual: Volumen 1:3133	Sección 2.6: Speculation3134	Sección 4.4: Memory Access3135