Pregunta

En una máquina SMP debemos usar spin_lock_irqsave y no spin_lock_irq del contexto de interrupción.

¿Por qué queremos para salvar las banderas (que contienen el SI)?

¿Hay alguna otra rutina de interrupción que podrían interrumpir?

¿Fue útil?

Solución

Soy nuevo en el núcleo pero por lo que deduzco de libro de Robert Love "del núcleo Linux Desarrollo", si las interrupciones ya están deshabilitados en el procesador antes de su código comienza bloqueo, cuando se llama spin_unlock_irq va a liberar el bloqueo en una errónea manera. Si guarda las banderas y liberarlo con las banderas, la spin_lock_irqsave función se acaba de volver de la interrupción a su estado anterior.

Ejemplo con spin_lock_irqsave

spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;

spin_lock_irqsave(&mLock, flags); // save the state, if locked already it is saved in flags
// Critical section
spin_unlock_irqrestore(&mLock, flags); // return to the formally state specified in flags

Ejemplo con spin_lock_irq (sin irqsave):

spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;

spin_lock_irq(&mLock); // Does not know if already locked
// Critical section
spin_unlock_irq(&mLock); // Could result in an error unlock...

Otros consejos

spin_lock_irqsave se utiliza básicamente para guardar el estado de interrupción antes de tomar el bloqueo de giro, esto es debido a bloqueo de bucle desactiva la interrupción, cuando el bloqueo se toma en el contexto de interrupciones, y vuelve a habilitar cuando, mientras que el desbloqueo. El estado de las interrupciones se guarda de manera que debe restablecer las interrupciones de nuevo.

Ejemplo:

  1. Digamos que x interrupción se ha desactivado antes de adquirir bloqueo de bucle
  2. spin_lock_irq desactivará la x de interrupción y tomar el la cerradura
  3. spin_unlock_irq permitirá a la x de interrupción.

Así que en la tercera etapa anterior después de soltar el bloqueo tendremos x interrupción habilitada que era anteriormente desactivado antes de adquirir el bloqueo.

Por lo que sólo cuando esté seguro de que las interrupciones no se desactivan sólo entonces usted debe spin_lock_irq de lo contrario se debe utilizar siempre spin_lock_irqsave.

La necesidad de spin_lock_irqsave además spin_lock_irq es bastante similar a la razón se necesita local_irq_save(flags) además local_irq_disable. Aquí hay una buena explicación de este requisito tomado de Linux Kernel Desarrollo Segunda edición de Robert Love.

  

La rutina local_irq_disable () es peligroso si las interrupciones no eran   Ya desactivado antes de su invocación. La llamada correspondiente a   local_irq_enable () permite interrupciones incondicionalmente, a pesar de la   hecho de que se pusieron en marcha para empezar. En su lugar, se necesita un mecanismo   para restaurar las interrupciones a un estado anterior. Esta es una preocupación común   debido a que una ruta de código dado en el kernel se puede llegar con y   sin interrupciones permitido, dependiendo de la cadena de llamadas. Por ejemplo,   imaginar el fragmento de código anterior es parte de una función más grande.   Imagine que esta función es llamada por otras dos funciones, una que   deshabilita las interrupciones y uno que no lo hace. Porque se está convirtiendo   más duro que el núcleo crece en tamaño y complejidad a conocer todo el código   caminos que conducen a una función, es mucho más seguro para guardar el estado de   el sistema de interrupción antes de su desactivación. Entonces, cuando usted está listo para   interrupciones volver a activar, sólo tiene que devolverlos a su estado original:

unsigned long flags;

local_irq_save(flags);    /* interrupts are now disabled */ /* ... */
local_irq_restore(flags); /* interrupts are restored to their previous
state */
  

Tenga en cuenta que estos métodos se implementan al menos en parte como macros, por lo   el parámetro flags (que debe ser definido como un largo sin signo) es   aparentemente pasa por valor. Este parámetro contiene   datos arquitectura-específico que contiene el estado de la interrupción   Los sistemas. Debido a que al menos una arquitectura soportada incorpora   información de la pila en el valor (ejem, SPARC), las banderas no se puede pasar   a otra función (en concreto, debe permanecer en la misma pila   cuadro). Por esta razón, la llamada para guardar y restaurar la llamada a   interrupciones deben ocurrir en la misma función.

     

Todas las funciones anteriores puede ser llamado desde ambos interrupción y   proceso contexto.

Por qué código del núcleo / subproceso en ejecución en el contexto de interrupción no puede dormir? que une a Robert Amores artículo , leí esto:

  

algunos controladores de interrupción (conocido en   Linux como el manejador de interrupciones rápidas) de ejecución   con todas las interrupciones en el local de   procesador desactivado. Esto se hace para   garantizar que se ejecuta el gestor de interrupciones   sin interrupción, lo más rápidamente   posible. Más aún, toda interrupción   manejadores se ejecutan con su actual   línea de interrupción deshabilitado en todas   procesadores. Esto asegura que dos   controladores de interrupción para el mismo   línea de interrupción no se ejecutan   concurrentemente. También evita que el dispositivo   escritores conductor de tener que manejar   interrupciones recursivas, que complican   la programación.

A continuación se muestra parte del código en el kernel de Linux 4.15.18, lo que demuestra que spiin_lock_irq () llamará __raw_spin_lock_irq (). Sin embargo, no va a guardar ninguna bandera como se puede ver a continuación parte del código, pero desactivar la interrupción.

  static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
    {
        local_irq_disable();
        preempt_disable();
        spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
        LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
    }

A continuación código muestra spin_lock_irqsave () lo que ahorra la etapa actual de la bandera y luego desactivar Preferencia.

static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
    unsigned long flags;

    local_irq_save(flags);
    preempt_disable();
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    /*
     * On lockdep we dont want the hand-coded irq-enable of
     * do_raw_spin_lock_flags() code, because lockdep assumes
     * that interrupts are not re-enabled during lock-acquire:
     */
#ifdef CONFIG_LOCKDEP
    LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
#else
    do_raw_spin_lock_flags(lock, &flags);
#endif
    return flags;
}

Esta pregunta se inicia desde la falsa aseveración: On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.

Ninguno de estos deben utilizarse de interrupción contexto, el SMP o en UP. Dicho esto, spin_lock_irqsave() pueden usarse de contexto de interrupción, como siendo más universal (Que puede ser utilizado en ambos de interrupción y normales contextos), pero que se supone que usar spin_lock() del contexto de interrupción, y spin_lock_irq() o spin_lock_irqsave() a partir del contexto normal. El uso de spin_lock_irq() es casi siempre lo incorrecto que hacer en el contexto de interrupciones, siendo esta SMP o UP. Es posible que funcione porque la mayoría de controladores de interrupción IRQ correr con habilitadas a nivel local, pero no se debe tratar de eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top