arm barrier

Casos de uso de la vida real de barreras(DSB, DMB, ISB) en ARM



barrier (3)

Entiendo que DSB, DMB e ISB son barreras para evitar que se vuelvan a ordenar las instrucciones. También puedo encontrar muchas explicaciones muy buenas para cada uno de ellos, pero es bastante difícil imaginar el caso en el que tengo que usarlos.

Además, desde los códigos de código abierto, veo esas barreras de vez en cuando, pero es bastante difícil entender por qué se usan. Solo para un ejemplo, en la función tcp_rcv_synsent_state_process del kernel 3.7 de Linux, hay una línea como la siguiente:

if (unlikely(po->origdev)) sll->sll_ifindex = orig_dev->ifindex; else sll->sll_ifindex = dev->ifindex; smp_mb(); if (po->tp_version <= TPACKET_V2) __packet_set_status(po, h.raw, status);

donde smp_mb () es básicamente DMB. ¿Podría darme algunos de sus ejemplos de la vida real? Ayudaría a entender más sobre las barreras.


Lo siento, no le voy a dar un ejemplo directo como lo está pidiendo, porque como ya está mirando a través del código fuente de Linux, tiene muchos de ellos y no parece que le ayuden. No es vergonzoso, ya que todas las personas sanas están al menos inicialmente confundidas por los problemas de orden de acceso a la memoria :)

Si usted es principalmente un desarrollador de aplicaciones, entonces hay muchas posibilidades de que no tenga que preocuparse demasiado por eso, independientemente de los marcos de concurrencia que utilice lo resolverán por usted.

Si usted es principalmente un desarrollador de controladores de dispositivo, entonces los ejemplos son bastante sencillos de encontrar, siempre que haya una dependencia en su código de un acceso anterior que haya tenido un efecto (borró una fuente de interrupción, escribió un descriptor DMA) antes de que se realice algún otro acceso (Re-habilitando interrupciones, iniciando la transacción DMA).

Si está en el proceso de desarrollar un marco de concurrencia (o depurar uno), probablemente necesite leer un poco más sobre el tema, ¿pero su pregunta sugiere una curiosidad superficial en lugar de una necesidad inmediata? Si está desarrollando su propio método para pasar datos entre subprocesos, no se basa en primitivas proporcionadas por un marco de concurrencia, es decir, para todos los propósitos y propósitos un marco de concurrencia.

Paul McKenney escribió un excelente artículo sobre la necesidad de barreras de memoria y los efectos que realmente tienen en el procesador: Barreras de memoria: una vista de hardware para hackers de software

Si eso es un poco demasiado duro, escribí una serie de blogs en tres partes que es un poco más liviana y termina con una vista específica de ARM. La primera parte es el orden de acceso a la memoria - una introducción .

Pero si se trata específicamente de listas de ejemplos que está buscando, especialmente para la arquitectura ARM, podría hacerlo mucho peor que Barrier Litmus Tests and Cookbook .

La vista del programador extra extra liviano y la versión no completamente correcta desde el punto de vista arquitectónico es:

  • DMB: siempre que un acceso a la memoria requiera ordenarse con respecto a otro acceso a la memoria.
  • DSB: siempre que se deba completar un acceso a la memoria antes de que avance la ejecución del programa.
  • ISB: siempre que la obtención de instrucciones tenga lugar explícitamente después de un cierto punto en el programa, por ejemplo, después de actualizar el mapa de memoria o después de escribir el código que se ejecutará. (En la práctica, esto significa "desechar cualquier instrucción precargada en este punto").

Por lo general, debe usar una barrera de memoria en los casos en que tenga que ASEGURARSE de que el acceso a la memoria se produce en un orden específico. Esto puede ser necesario por varios motivos, generalmente es necesario cuando dos o más procesos / subprocesos o un componente de hardware acceden a la misma estructura de memoria, que debe mantenerse de manera consistente.

Se usa muy a menudo en transferencias DMA. Un simple DMA estructuras de control podría tener este aspecto:

struct dma_control { u32 owner; void * data; u32 len; };

El propietario generalmente se configurará en algo como OWNER_CPU o OWNER_HARDWARE, para indicar quién de los dos participantes tiene permitido trabajar con la estructura.

Código que cambia esto usualmente le gusta como este

dma->data = data; dma->len = length; smp_mb(); dma->owner = OWNER_HARDWARE;

Por lo tanto, los datos y un len siempre se configuran antes de que la propiedad se transfiera al hardware DMA. De lo contrario, el motor podría obtener datos obsoletos, como un puntero o una longitud que no se actualizó, porque la CPU reordenó el acceso a la memoria.

Lo mismo ocurre con los procesos o hilos que se ejecutan en diferentes núcleos. Podrían comunicarse de manera similar.


Un ejemplo simple de un requisito de barrera es un spinlock. Si implementa un spinlock usando la comparación y el intercambio (o LDREX / STREX en ARM) y sin una barrera, el procesador puede cargar especulativamente los valores de la memoria y almacenar perezosamente los valores computados en la memoria, y ninguno de los dos debe ocurrir. en el orden de las cargas / tiendas en el flujo de instrucciones.

El DMB, en particular, evita el acceso a la memoria reordenado alrededor del DMB. Sin DMB, el procesador podría reordenar una tienda en memoria protegida por el spinlock después de que se libere el spinlock. O el procesador podría leer la memoria protegida por el spinlock antes de que el spinlock estuviera realmente bloqueado, o mientras estaba bloqueado por un contexto diferente.

unixsmurf ya lo señaló, pero también lo dirigiré hacia Barrier Litmus Tests and Cookbook . Tiene algunos ejemplos bastante buenos de dónde y por qué debería usar barreras.