serrure de rotation irqsave vs serrure de rotation irq
Sur une machine SMP, nous devons utiliser spin_lock_irqsave
et non spin_lock_irq
du contexte d'interruption.
Pourquoi voudrions-nous enregistrer les drapeaux (qui contiennent le si)?
Y a-t-il une autre routine d'interruption qui pourrait nous interrompre?
5 réponses
Je suis nouveau dans le noyau mais d'après ce que j'ai compris du livre de Robert Love "Linux Kernel Development", si les interruptions sont déjà désactivées sur le processeur avant que votre code ne commence à se verrouiller, lorsque vous appelez spin_unlock_irq vous relâchez le verrou d'une manière erronée. Si vous enregistrez les drapeaux et les relâchez avec les drapeaux, la fonction spin_lock_irqsave renverra simplement l'interruption à son état précédent.
Exemple avec 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
Exemple avec spin_lock_irq
( sans 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...
spin_lock_irqsave
est essentiellement utilisé pour enregistrer l'interruption de l'etat avant de prendre le verrou de rotation, c'est parce que le verrou de rotation désactive l'interruption, lorsque le verrou est pris en interruption contexte, et ré-active quand lors du déverrouillage. L'état d'interruption est enregistré afin qu'il rétablisse les interruptions à nouveau.
Exemple:
- disons que l'interruption X a été désactivée avant l'acquisition du verrouillage de rotation
- {[1] } désactivera l'interruption x et prendra le verrou
-
spin_unlock_irq
volonté activer l'interruption X.
Donc, dans la 3ème étape ci-dessus après avoir relâché le verrou, nous aurons activé l'interruption x qui était précédemment désactivée avant l'acquisition du verrou.
Donc seulement lorsque vous êtes sûr que les interruptions ne sont pas désactivées seulement alors vous devriez spin_lock_irq
sinon vous devriez toujours utiliser spin_lock_irqsave
.
Lecture Pourquoi le code/thread du noyau s'exécutant dans un contexte d'interruption ne peut pas dormir? qui renvoie à Robert Aime article, j'ai lu ceci :
Certains gestionnaires d'interruption (connus dans Linux comme gestionnaires d'interruption rapide) exécuter avec toutes les interruptions sur le local processeur désactivé. C'est fait pour s'assurer que le gestionnaire d'interruption s'exécute sans interruption, aussi rapidement que possible. Plus encore, tous interrompre les gestionnaires fonctionnent avec leur courant ligne d'interruption désactivée sur tout processeur. Cela garantit que deux gestionnaires d'interruption pour le même ligne d'interruption ne pas exécuter simultanément. Il empêche également dispositif pilotes écrivains d'avoir à gérer interruptions récursives, qui compliquent programmation.
La nécessité de spin_lock_irqsave
en plus de spin_lock_irq
est assez similaire à la raison local_irq_save(flags)
est nécessaire en plus d' local_irq_disable
. Voici une bonne explication de cette exigence tirée de Linux Kernel Development Second Edition Par Robert Love.
La routine local_irq_disable() est dangereuse si les interruptions déjà désactivé avant son invocation. L'appel correspondant à local_irq_enable() active inconditionnellement les interruptions, malgré fait qu'ils étaient en route pour commencer avec. Au lieu de cela, un un mécanisme est nécessaire pour restaurer les interruptions à un état précédent. C'est une préoccupation commune parce qu'un chemin de code donné dans le noyau peut être atteint à la fois avec et sans interruption activée, en fonction de la chaîne d'appels. Exemple, imaginez que l'extrait de code précédent fait partie d'une fonction plus grande. Imaginez que cette fonction est appelée par deux autres fonctions, qui désactive les interruptions et celle qui ne le fait pas. Parce qu'il est en train de devenir plus difficile à mesure que le noyau grandit en taille et en complexité connaître tout le code les chemins menant à une fonction, il est beaucoup plus sûr d'enregistrer l'état de le système d'interruption avant de le désactiver. Ensuite, lorsque vous êtes prêt à réactivez les interruptions, vous les restaurez simplement à leur état d'origine:
unsigned long flags;
local_irq_save(flags); /* interrupts are now disabled */ /* ... */
local_irq_restore(flags); /* interrupts are restored to their previous
state */
Notez que ces méthodes sont implémentées au moins en partie sous forme de macros, donc le paramètre flags (qui doit être défini comme un long non signé) est apparemment passé par valeur. Ce paramètre contient données spécifiques à l'architecture contenant l'état de l'interruption système. Parce qu'au moins une architecture prise en charge intègre les informations de pile dans la valeur (ahem, SPARC), les drapeaux ne peuvent pas être passés à une autre fonction (plus précisément, elle doit rester sur la même pile cadre). Pour cette raison, l'appel à enregistrer et l'appel à la restauration les interruptions doivent se produire dans la même fonction.
Toutes les fonctions précédentes peuvent être appelées à la fois contexte de processus.
Cette question commence à partir de la fausse assertion:
On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.
Aucun de ceux-ci ne doit être utilisé à partir de l'interruption
Contexte, sur SMP ou sur UP. Cela dit, spin_lock_irqsave()
Peut être utilisé à partir du contexte d'interruption, comme étant plus universel
(il peut être utilisé à la fois dans des contextes d'interruption et normaux), mais
vous êtes censé utiliser spin_lock()
du contexte d'interruption,
et spin_lock_irq()
ou spin_lock_irqsave()
du contexte normal.
L'utilisation de spin_lock_irq()
est presque toujours la mauvaise chose
à faire dans le contexte d'interruption, étant ce SMP ou UP. Il peut travail
parce que la plupart des gestionnaires d'interruption s'exécutent avec IRQs activé localement,
mais tu ne devrais pas essayer ça.