Domanda

Su una macchina SMP dobbiamo usare spin_lock_irqsave e non spin_lock_irq dall'interruzione contesto.

Perché vogliamo salvare il flag (che contengono il SE)?

C'è un'altra routine di interrupt che interrompono noi?

È stato utile?

Soluzione

Sono nuovo al kernel, ma da quanto ho capito dal libro di Robert Love "Linux Kernel Development", se gli interrupt sono già disabilitati sul processore prima che il codice di inizio di blocco, quando si chiama spin_unlock_irq si rilasciare il blocco in un'erronea maniera. Se si salvano le bandiere e rilasciarlo con le bandiere, la funzione spin_lock_irqsave sarà solo tornare 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...

Altri suggerimenti

spin_lock_irqsave è fondamentalmente utilizzato per salvare l'interrupt è stato prima di prendere il blocco di rotazione, questo perché spin lock disabilita gli interrupt, quando il blocco viene preso in interrupt contesto, e ri-attivato quando mentre lo sblocco.L'interrupt è stato salvato, in modo che dovrebbe ripristinare la interrompe di nuovo.

Esempio:

  1. Diciamo interrupt x è stato disattivato prima di spin lock è stata acquisita
  2. spin_lock_irq disabilita gli interrupt x e prendere il blocco
  3. spin_unlock_irq abilita l'interrupt x.

Così nel 3 ° gradino al di sopra dopo il rilascio del blocco avremo interrupt x abilitato che è stato precedentemente disattivato prima che il blocco è stato acquisito.

Quindi, solo quando si è sicuri che gli interrupt non vengono disattivati solo allora si dovrebbe spin_lock_irq altrimenti si dovrebbe usare sempre spin_lock_irqsave.

La necessità di spin_lock_irqsave oltre spin_lock_irq è molto simile alla ragione local_irq_save(flags) è necessaria oltre local_irq_disable. Ecco una buona spiegazione di questo requisito preso da Linux Kernel Development Seconda edizione da Robert Love.

  

Il local_irq_disable () di routine è pericoloso se fossero gli interrupt   già disattivato prima della sua invocazione. La corrispondente chiamata a   local_irq_enable () consente incondizionatamente interrupt, nonostante la   fatto che erano fuori per cominciare. Invece, è necessario un meccanismo   per ripristinare interrupt a uno stato precedente. Questa è una preoccupazione comune   perché un determinato percorso di codice nel kernel può essere raggiunto sia con che   senza interruzioni attivato, a seconda della catena di chiamate. Per esempio,   immaginare il codice precedente è parte di una funzione più ampia.   Immaginare che questa funzione è chiamato da altre due funzioni, una che   disabilita interrupt e uno che non lo fa. Perché sta diventando   più difficile come il kernel cresce in dimensioni e complessità di conoscere tutto il codice   sentieri che portano fino a una funzione, è molto più sicuro per salvare lo stato di   il sistema di interruzione prima di disabilitarlo. Poi, quando si è pronti per   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 */
  

Si noti che questi metodi sono implementati almeno in parte come macro, in modo   il parametro flags (che deve essere definito come un unsigned long) è   apparentemente passato per valore. Questo parametro contiene   dati Architettura-specifici contenenti lo stato di interruzione   sistemi. Poiché almeno un'architettura supportata incorpora   informazioni di stack nel valore (ahem, SPARC), le bandiere non può essere passato   ad un'altra funzione (in particolare, deve rimanere sulla stessa pila   telaio). Per questo motivo, la chiamata per salvare e la chiamata per ripristinare   interrupt devono avvenire nella stessa funzione.

     

Tutte le funzioni precedenti può essere chiamato da entrambi interruzione e   processo di contesto.

Perché il codice del kernel / thread in esecuzione nel contesto di interrupt non riesce a dormire? che collega Robert Loves articolo , ho letto questo:

  

alcuni gestori di interrupt (noto in   Linux come gestori di interrupt veloci) run   con tutti gli interrupt sul locale   processore disabilitata. Questo viene fatto per   garantire che le piste gestore di interrupt   senza interruzione, nel più breve tempo   possibile. Più così, tutti interrupt   gestori di correre con loro attuale   linea di interrupt disattivato su tutti   processori. Questo assicura che due   gestori di interrupt per la stessa   linea di interrupt non vengono eseguiti   simultaneamente. Inoltre impedisce dispositivo   scrittori del driver da dover manico   interrupt ricorsive che complicano   programmazione.

Di seguito è parte del codice del kernel Linux 4.15.18, il che dimostra che spiin_lock_irq () chiameranno __raw_spin_lock_irq (). Tuttavia, non sarà salvare tutti i flag, come si può vedere di seguito parte del codice, ma disattivare l'interrupt.

  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);
    }

Sotto codice spettacoli spin_lock_irqsave () che salva l'attuale fase di bandiera e quindi disattivare preempt.

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;
}

Questa domanda parte dalla falsa asserzione: On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.

Nessuno di questi dovrebbe essere usato da interrupt contesto, lo SMP o UP. Detto questo, spin_lock_irqsave() possono essere utilizzato dal contesto di interrupt, come più universale (Può essere utilizzato sia in ambito interrupt e normali), ma si suppone di utilizzare spin_lock() dal contesto di interrupt, e spin_lock_irq() o spin_lock_irqsave() dal contesto normale. L'uso di spin_lock_irq() è quasi sempre la cosa sbagliata fare in contesto di interrupt, essendo questo SMP o UP. Si può lavorare perché la maggior parte gestori di interrupt correre con IRQ localmente abilitati, ma non si deve provare che.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top