2011-03-24 14 views
5

Me gustaría saber si es posible asegurar que line se ejecute atómicamente, dado que podría ser ejecutado tanto por el ISR como por el contexto principal. Estoy trabajando en un ARM9 (LPC313x) y usando RealView 4 (armcc).¿Se puede ejecutar esto atómicamente?

foo() { 
    .. 
    stack_var = ++volatile_var; // line 
    .. 
} 

Busco cualquier rutina como _atomic_ para C166, el código de montaje directo, etc. yo preferiría no tener que deshabilitar las interrupciones.

Muchas gracias.

Respuesta

6

De un vistazo rápido, la macro C166 _atomic_ parece utilizar una instrucción que enmascara eficazmente interrumpe durante la duración de un número especificado de instrucciones. No hay nada directamente relacionado con eso en la arquitectura ARM.

Por supuesto, puede utilizar la instrucción swp (o __swp intrínseco en la cadena de herramientas RealView) para implementar un bloqueo alrededor de la sección crítica. ldrex/strex mencionado en otra respuesta no existe en la arquitectura ARM versión 5, que incluye los procesadores ARM9. http://infocenter.arm.com/help/topic/com.arm.doc.dui0491c/CJAHDCHB.html y http://infocenter.arm.com/help/topic/com.arm.doc.dui0489c/Chdbbbai.html respectivamente.

Una aplicación simplista de bloqueo en torno a esta (usando la cadena de herramientas RealView) sería:

{ 
    /* Loop until lock acquired */ 
    while (__swp(LOCKED, &lockvar) == LOCKED); 
    .. 
    /* Critical section */ 
    .. 
    lockvar = UNLOCKED; 
} 

Sin embargo, esto hará conducen a la paralización en el contexto ISR cuando el hilo principal es la celebración de la cerradura.

Creo que las interrupciones de enmascaramiento alrededor de la operación probablemente sean la solución menos peluda, aunque si su contexto principal se está ejecutando en modo de usuario, requerirá una llamada al sistema para implementar.

+0

Gracias unixsmurf. – JoeSlav

+0

Puede mezclar 'swpb' con' swp' en ARM anteriores para patrones múltiples/únicos. Es decir, ** múltiples indicadores de bandera ** y ** bandera única clara **. Están disponibles hasta cuatro 'bytes' o ** estados **. –

8

No, no creo que alguna vez pueda esperar que ++volatile_var sea atómico, incluso si no tiene la asignación. Usa una primitiva atómica apropiada para eso. Si su compilador no proporciona dicha extensión, puede encontrar fácilmente un ensamblador en línea corto para eso en la web. Las instrucciones del ensamblador son llamadas ldrex y strex para intercambio atómico en el brazo, creo.

Editar: Parece que el tipo de procesador específico que se solicita en la pregunta no implementa estas instrucciones.

Editar: Lo siguiente debería funcionar con gcc, para otro compilador probablemente uno tenga que adaptar las partes __asm__.

inline 
size_t arm_ldrex(size_t volatile*ptr) { 
    size_t ret; 
    __asm__ volatile ("ldrex %0,[%1]\[email protected] load exclusive\n" 
        : "=&r" (ret) 
        : "r" (ptr) 
        : "cc", "memory" 
        ); 
    return ret; 
} 

inline 
_Bool arm_strex(size_t volatile*ptr, size_t val) { 
    size_t error; 
    __asm__ volatile ("strex %0,%1,[%2]\[email protected] store exclusive\n" 
        : "=&r" (error) 
        : "r" (val), "r" (ptr) 
        : "cc", "memory" 
        ); 
    return !error; 
} 

inline 
size_t atomic_add_fetch(size_t volatile *object, size_t operand) { 
    for (;;) { 
    size_t oldval = arm_ldrex(object); 
    size_t newval = oldval + operand; 
    if (arm_strex(object, newval)) return newval; 
    } 
} 
+0

Sería útil si alguien puede arrojar algo de luz, pero ¿no se consideraría que lo siguiente es atómico? ADD r0, r0, # 1 ¿Cómo se puede usar un ldrex/strex para incrementar un valor? Me estoy perdiendo algo. – TheLoneJoker

+0

@Jens, soy un poco nuevo en esto. ¿Podría indicarme algún recurso/documentación que proporcione más detalles sobre el código __asm__ volátil ("ldrex% 0, [% 1] \ t @ carga exclusiva \ n" : "= & r" (ret) : "r "(ptr) :" cc "," memoria " ); No tengo muy claro qué significan las cosas que están dentro. – TheLoneJoker

+0

@TheLoneJoker esto es lo que se conoce como "ensamblado en línea", las instrucciones del ensamblador que se insertan en su lugar, buscando ese término debería encontrar algo más de información. La variante que estoy usando aquí es para gcc, otros probablemente también soporten tales extensiones pero que pueden verse diferentes en su implementación. –

Cuestiones relacionadas