Frage

Auf einer SMP-Maschine müssen wir spin_lock_irqsave und nicht spin_lock_irq von Interrupt-Kontext verwenden.

Warum sollten wir wollen die Flaggen speichern (die die IF enthalten)?

Gibt es eine andere Interrupt-Routine, die uns unterbrechen könnte?

War es hilfreich?

Lösung

Ich bin neu in den Kernel, sondern von dem, was ich von Robert Love Buch „Linux Kernel Development“ sammeln, wenn Interrupts bereits auf dem Prozessor deaktiviert, bevor Sie den Code Sperre beginnt, wenn Sie anrufen spin_unlock_irq Sie die Sperre in einem fehlerhaften freigeben werden Weise. Wenn Sie die Fahnen speichern und lassen Sie ihn mit den Flaggen, wird die Funktion spin_lock_irqsave zurückkehren nur den Interrupt in seinen vorherigen Zustand.

Beispiel mit 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

Beispiel mit spin_lock_irq (ohne 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...

Andere Tipps

spin_lock_irqsave ist im Grunde verwendet, um den Unterbrechungszustand zu speichern, bevor Sie den Spin-Lock nimmt, ist dies, weil Spin-Lock des Interrupt deaktiviert, wenn das Schloss in Interrupt-Kontext genommen und erneut aktiviert es, wenn während Entriegelung. Der Interrupt-Zustand wird so gespeichert, dass sie die Interrupts wieder wieder einstellen sollten.

Beispiel:

  1. Lassen Sie uns sagen Interrupt x deaktiviert wurde, bevor Spin-Lock erworben wurde
  2. spin_lock_irq wird die Interrupt-x deaktivieren und nehmen Sie die die Sperre
  3. spin_unlock_irq wird die Interrupt-x aktivieren.

So im dritten Schritt oben nach Lösen der Verriegelung werden wir Interrupt-x aktiviert, das war früher deaktiviert, bevor die Sperre übernommen wurde.

Also nur, wenn Sie sicher sind, dass Interrupts deaktiviert sind nicht nur dann sollten Sie spin_lock_irq sonst sollten Sie immer spin_lock_irqsave verwenden.

Die Notwendigkeit für spin_lock_irqsave neben spin_lock_irq ist ganz ähnlich wie der Grund local_irq_save(flags) neben local_irq_disable benötigt wird. Hier ist eine gute Erklärung für diese Anforderung genommen von Linux Kernel Entwicklung Second Edition von Robert Love.

  

Die local_irq_disable () Routine ist gefährlich, wenn Interrupts waren   bereits vor ihrem Aufruf gesperrt. Der entsprechende Aufruf   local_irq_enable () ermöglicht bedingungslos Interrupts, trotz der   Tatsache, dass sie mit zu beginnen, waren aus. Stattdessen wird ein Mechanismus benötigt   Unterbrechungen in einen früheren Zustand wiederherzustellen. Dies ist ein gemeinsames Anliegen   weil ein bestimmter Codepfad im Kernel mit den beiden erreicht werden kann und   ohne Unterbrechungen freigegeben, auf der Call-Kette abhängig. Beispielsweise,   vorstellen, den vorherigen Code-Schnipsel Teil einer größeren Funktion ist.   Stellen Sie sich vor, dass diese Funktion durch zwei weitere Funktionen aufgerufen wird, eine, die   sperrt Interrupts und eines, das nicht der Fall ist. Weil es immer   in Größe und Komplexität härter als der Kernel den gesamten Code zu wissen, wächst   Wege zu einer Funktion führt, ist es viel sicherer, den Zustand zu speichern   das Interrupt-System, bevor es deaktiviert wird. Dann, wenn Sie bereit sind,   reaktivieren Interrupts Sie einfach wieder in ihren ursprünglichen Zustand:

unsigned long flags;

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

Beachten Sie, dass diese Verfahren zumindest teilweise als Makros implementiert sind, so   Der Parameter flags (der als unsigned long definiert werden müssen) ist   scheinbar von Wert übergeben. Dieser Parameter enthält   architekturspezifischen Daten den Zustand der Interrupt-enthaltende   Systeme. Da mindestens eine unterstützte Architektur beinhaltet   Stapelinformation in den Wert (ähem, SPARC), Flags können nicht weitergegeben werden   an eine andere Funktion (es muss speziell bleiben, auf dem gleichen Stapel   Rahmen). Aus diesem Grund, um den Anruf zu speichern, und der Anruf wiederherstellen   Unterbrechungen in der gleichen Funktion auftreten müssen.

     

Alle bisherigen Funktionen können von beiden Interrupt aufgerufen werden und   Prozesskontext.

Beim Lesen Warum Kernel-Code / Thread in Interrupt-Kontext ausführen kann nicht schlafen? die Links zu Robert Liebt Artikel , las ich diese:

  

einig Interrupt-Handler (bekannt in   Linux als schnelle Interrupt-Handler) laufen   mit allen Unterbrechungen auf dem lokalen   Prozessor deaktiviert. Dies geschieht, um   sicherzustellen, dass die Interrupt-Handler läuft   ohne Unterbrechung, so schnell wie   möglich. Um so mehr, alle Interrupt   Handler laufen mit ihren aktuellen   Interrupt-Leitung auf alle deaktiviert   Prozessoren. Dadurch wird sichergestellt, dass zwei   Interrupt-Handler für den gleichen   Interrupt-Leitung läuft nicht   gleichzeitig. Es verhindert auch, Gerät   Treiber Autoren aus zu Griff   rekursiven Unterbrechungen, die erschweren   Programmierung.

Im Folgenden ist ein Teil des Codes in Linux-Kernel 4.15.18, die zeigt, dass spiin_lock_irq () rufen __raw_spin_lock_irq (). Es wird jedoch nicht speichern Sie alle Flaggen, wie Sie können unten Teil des Codes sehen, aber deaktivieren Sie die Unterbrechung.

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

Im Folgenden Code zeigt spin_lock_irqsave (), die den aktuellen Stand der Flagge speichert und dann Präemptionsverhinderungsfunktion.

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

Diese Frage geht von der falschen Behauptung: On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.

Auch diese sollten von der Unterbrechung verwendet werden Zusammenhang auf SMP oder auf UP. Das heißt, spin_lock_irqsave() können von Interrupt-Kontext verwendet werden, als universeller sein (Es kann in beiden Interrupt und normalen Kontexten verwendet werden), aber Sie sollen spin_lock() von Interrupt-Kontext verwenden, und spin_lock_irq() oder spin_lock_irqsave() aus dem normalen Rahmen. Die Verwendung von spin_lock_irq() ist fast immer die falsche Sache im Interrupt-Kontext, wobei dieses SMP oder UP zu tun. Es kann funktionieren weil die meisten Interrupt-Handler mit IRQs lokal ausführen aktiviert ist, aber Sie sollten nicht versuchen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top