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