2010-04-01 16 views
17

Su una macchina SMP, è necessario utilizzare spin_lock_irqsave e non spin_lock_irq dal contesto di interruzione.spin_lock_irqsave vs spin_lock_irq

Perché dovremmo salvare i flag (che contengono l'IF)?

C'è un'altra routine di interrupt che potrebbe interromperci?

risposta

19

Sono nuovo al kernel ma da ciò che raccolgo dal libro di Robert Love "Kernel Development Linux", se gli interrupt sono già disabilitati sul processore prima che il codice inizi a bloccarsi, quando chiami spin_unlock_irq rilascerai il blocco in un modo errato. Se salvi i flag e li rilasci con i flag, la funzione spin_lock_irqsave restituirà l'interrupt al suo stato precedente.

Esempio 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 

Esempio con spin_lock_irq (senza 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

Questa risposta è errata. spin_lock_irq disabiliterà incondizionatamente gli interrupt, mentre le varianti irqsave salveranno lo stato di interruzione nei casi in cui non puoi sapere in quale stato ti trovi attualmente. –

+3

@NoahWatkins Questo è il punto dell'ultima porzione. Dice * Potrebbe causare un errore di sblocco * in un commento. 'Spin_lock_irq' mostra che l'IRQ è abilitato quando non dovrebbe essere. La risposta non è errata; solo non molto chiaro. –

+0

@artlessnoise Quando diciamo che gli irq sono disabilitati, tutti gli irq del sistema sono disabilitati? Questo non è molto chiaro per me. Puoi spiegare? –

4

lettura Why kernel code/thread executing in interrupt context cannot sleep? che collega a Robert Loves article, ho letto questo:

alcuni interrupt gestori (noto in Linux come gestori di interrupt veloci) eseguire con tutti gli interrupt sul processore locale disabilitato. Questo viene fatto a assicurandosi che il gestore di interrupt esegua senza interruzioni, con la stessa rapidità di possibile. Inoltre, tutti i gestori di interrupt vengono interrotti con la loro linea di interrupt attuale disattivata su tutti i processori . Ciò garantisce che due gestori di interrupt per la stessa riga di interrupt non eseguano contemporaneamente . Impedisce inoltre ai writer del dispositivo di dover gestire gli interrupt ricorsivi , che complicano la programmazione di .

+4

Questo non risponde alla domanda. – JagsVG

28

spin_lock_irqsave è fondamentalmente utilizzato per salvare lo stato di interruzione prima di prendere il blocco di selezione, questo è perché spin lock disabilita l'interrupt, quando la serratura è presa nel contesto di interrupt e riattiva quando, liberando. Lo stato di interruzione viene salvato in modo da ripristinare nuovamente gli interrupt.

Esempio:

  1. Diciamo interrupt x è stato disattivato prima di spin lock è stata acquisita
  2. spin_lock_irq consente di disattivare l'interrupt x e prendere la serratura
  3. spin_unlock_irq consentirà l'interrupt x.

Quindi nel terzo passaggio sopra dopo aver rilasciato il blocco avremo l'interrupt x abilitato che era stato disabilitato prima che il blocco fosse acquisito.

Pertanto, solo se si è certi che gli interrupt non sono disattivati, è necessario utilizzare spin_lock_irq altrimenti è necessario utilizzare sempre spin_lock_irqsave.

2

La necessità di spin_lock_irqsave oltre a spin_lock_irq è abbastanza simile al motivo local_irq_save(flags) è necessario oltre a local_irq_disable. Ecco una buona spiegazione di questo requisito tratto da Linux Kernel Development Second Edition di Robert Love.

La routine local_irq_disable() è pericolosa se gli interrupt sono stati già disattivati ​​prima del suo richiamo. La chiamata corrispondente a local_irq_enable() abilita in modo incondizionato gli interrupt, nonostante il fatto che si sia spento per iniziare. Invece, è necessario un meccanismo per ripristinare gli interrupt a uno stato precedente. Questa è una preoccupazione comune perché è possibile raggiungere un determinato percorso di codice nel kernel con e senza interruzioni abilitate, a seconda della catena di chiamate. Ad esempio, immagina che lo snippet di codice precedente faccia parte di una funzione più ampia. Immaginate che questa funzione sia chiamata da altre due funzioni, una delle quali disabilita gli interrupt e uno che non lo fa. Poiché sta diventando più difficile man mano che il kernel cresce in dimensioni e complessità per conoscere tutti i percorsi del codice che portano a una funzione, è molto più sicuro salvare lo stato di il sistema di interrupt prima di disabilitarlo. Poi, quando si è pronti a interrupt riattivare, è semplicemente di ripristinare lo stato originale:

unsigned long flags; 

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

Nota che questi metodi sono implementati almeno in parte come macro, in modo il parametro flags (che deve essere definito come non firmato lungo) è apparentemente passato per valore. Questo parametro contiene i dati specifici dell'architettura contenenti lo stato dei sistemi dell'interrupt. Poiché almeno un'architettura supportata incorpora le informazioni dello stack nel valore (ahem, SPARC), i flag non possono essere passati a in un'altra funzione (in particolare, deve rimanere sullo stesso stack frame). Per questo motivo, la chiamata da salvare e la chiamata per ripristinare gli interrupt devono essere eseguiti con la stessa funzione.

Tutte le funzioni precedenti possono essere richiamate sia dal contesto di interrupt sia dal contesto di processo .