2010-04-01 10 views
17

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

¿Por qué querríamos guardar las banderas (que contienen el IF)?

¿Hay alguna otra rutina de interrupción que pueda interrumpirnos?

Respuesta

19

Soy nuevo en el kernel pero por lo que recojo del libro de Robert Love "Linux Kernel Development", si las interrupciones ya están deshabilitadas en el procesador antes de que el código comience a bloquearse, cuando llame a spin_unlock_irq liberará el bloqueo en un manera errónea. Si guarda los indicadores y los suelta con los indicadores, la función spin_lock_irqsave devolverá 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... 
+2

Esta respuesta es incorrecta. spin_lock_irq deshabilitará las interrupciones por un segundo, mientras que las variantes irqsave guardarán el estado de interrupción en casos en que no se puede saber en qué estado se encuentra actualmente. –

+3

@NoahWatkins Ese es el punto de la última parte. Dice * Podría dar lugar a un desbloqueo de error * en un comentario. El 'spin_lock_irq' es para mostrar que el IRQ está habilitado cuando no debería ser. La respuesta no es incorrecta; simplemente no muy claro. –

+0

@artlessnoise Cuando decimos que los irq están deshabilitados, ¿están inhabilitados todos los irq del sistema? Esto no es muy claro para mí. ¿Puedes explicar? –

4

lectura Why kernel code/thread executing in interrupt context cannot sleep? que enlaza con Robert ama article, leí esto:

algunos de interrupción manipuladores (conocidos en)Linux como controladores de interrupción rápidos) ejecute con todas las interrupciones en el procesador local deshabilitado. Esto se hace a , asegúrese de que el manejador de interrupciones ejecute sin interrupción, tan rápido como posible. Más aún, todos los controladores de interrupción se ejecutan con su actual línea de interrupción deshabilitada en todos los procesadores . Esto garantiza que dos controladores de interrupción para la misma línea de interrupción no se ejecuten al mismo tiempo. También evita que los escritores de controladores del dispositivo tengan que manejar interrupciones recursivas, lo que complica la programación de .

+4

Esto no responde la pregunta. – JagsVG

28

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 desbloquear. El estado de interrupción se guarda para que vuelva a restablecer las interrupciones.

Ejemplo:

  1. permite decir interrupción x fue desactivado antes de bloqueo de bucle fue adquirida
  2. spin_lock_irq deshabilitará la interrupción x y tomar la cerradura de la
  3. spin_unlock_irq permitirá la interrupción x.

Por lo tanto, en el 3er paso anterior después de liberar el bloqueo, se activará la interrupción x que se deshabilitó anteriormente antes de que se adquiriera el bloqueo.

Entonces, solo cuando esté seguro de que las interrupciones no están deshabilitadas, entonces debe spin_lock_irq, de lo contrario, siempre debe usar spin_lock_irqsave.

2

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

La rutina local_irq_disable() es peligrosa si las interrupciones fueron ya desactivadas antes de su invocación. La llamada correspondiente al local_irq_enable() habilita incondicionalmente las interrupciones, a pesar del hecho de que estaban desactivadas para empezar. En su lugar, se necesita un mecanismo para restablecer las interrupciones a un estado anterior. Esta es una preocupación común porque se puede llegar a una ruta de código dada en el kernel con y sin interrupciones habilitadas, dependiendo de la cadena de llamadas. Por ejemplo, imagine que el fragmento de código anterior es parte de una función más grande. Imagine que otras dos funciones invocan esta función, una que deshabilita las interrupciones y otra que no. Debido a que se está convirtiendo en más difícil a medida que el kernel crece en tamaño y complejidad para conocer todos los caminos del código que conducen a una función, es mucho más seguro guardar el estado de el sistema de interrupción antes de deshabilitarlo. 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 definirse como un largo sin signo) es aparentemente pasado por valor. Este parámetro contiene datos específicos de arquitectura que contienen el estado de los sistemas de interrupción . Como al menos una arquitectura admitida incorpora información de la pila en el valor (ejem, SPARC), las banderas no se pueden pasar a otra función (específicamente, debe permanecer en la misma pila marco). Por esta razón, la llamada para guardar y la llamada para restaurar interrupciones deben ocurrir en la misma función.

Todas las funciones anteriores se pueden invocar desde el contexto de proceso de interrupción y .

Cuestiones relacionadas