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