web-dev-qa-db-fra.com

spin_lock_irqsave vs spin_lock_irq

Sur une machine SMP, nous devons utiliser spin_lock_irqsave et non spin_lock_irq à partir du contexte d'interruption. 

Pourquoi voudrions-nous sauvegarder les drapeaux (qui contiennent le SI)?

Y a-t-il une autre routine d'interruption qui pourrait nous interrompre?

22
cojocar

Je suis nouveau dans le noyau, mais d'après ce que je tire du livre "Développement du noyau Linux" de Robert Love, si les interruptions sont déjà désactivées sur le processeur avant le verrouillage de votre code, lorsque vous appelez spin_unlock_irq, vous lâchez le verrou de manière erronée. Si vous enregistrez les drapeaux et les relâchez, la fonction spin_lock_irqsave ramènera 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...
20
Hagai

spin_lock_irqsave est essentiellement utilisé pour sauvegarder l'état d'interruption avant de prendre le verrou tournant. Cela est dû au fait que le verrou tournant désactive l'interruption, lorsque le verrou est utilisé dans un contexte d'interruption et le réactive au déverrouillage. L'état d'interruption est sauvegardé de manière à rétablir les interruptions. 

Exemple:

  1. Disons que l'interruption x a été désactivée avant l'acquisition du blocage de spin
  2. spin_lock_irq désactive l'interruption x et prend le verrou
  3. spin_unlock_irq activera l'interruption x.

Ainsi, à la troisième étape ci-dessus, après avoir relâché le verrou, l'interruption x sera activée, ce qui a été désactivé avant l'acquisition du verrou.

Donc, seulement lorsque vous êtes sûr que les interruptions ne sont pas désactivées, alors vous devriez spin_lock_irq sinon vous devriez toujours utiliser spin_lock_irqsave.

35
pastum

La nécessité de spin_lock_irqsave en plus de spin_lock_irq est assez similaire à la raison pour laquelle local_irq_save(flags) est nécessaire en plus de local_irq_disable. Voici une bonne explication de cette exigence tirée de Linux Kernel Development Second Edition de Robert Love.

La routine local_irq_disable () est dangereuse si les interruptions étaient déjà désactivé avant son invocation. L’appel correspondant à local_irq_enable () active inconditionnellement les interruptions, malgré le fait qu’ils étaient partis pour commencer. Au lieu de cela, un mécanisme est nécessaire pour restaurer les interruptions à un état antérieur. C'est une préoccupation commune car un chemin de code donné dans le noyau peut être atteint avec et sans interruptions activées, en fonction de la chaîne d'appels. Par exemple, Imaginez que l'extrait de code précédent fasse partie d'une fonction plus grande . Imaginons que cette fonction soit appelée par deux autres fonctions, une qui désactive les interruptions et un qui ne le fait pas. Parce que ça devient plus difficile à mesure que le noyau grandit en taille et en complexité pour connaître tout le code chemins menant à une fonction, il est beaucoup plus sûr de sauvegarder l’état de le système d’interruption avant de le désactiver. Ensuite, lorsque vous êtes prêt à Pour réactiver les interruptions, il vous suffit de les restaurer dans 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 unsigned long) est apparemment passé par valeur. Ce paramètre contient données spécifiques à l'architecture contenant l'état de l'interruption systèmes. Car au moins une architecture prise en charge intègre informations de pile dans la valeur (ahem, SPARC), les indicateurs ne peuvent pas être transmis à une autre fonction (en particulier, il doit rester sur la même pile frame). Pour cette raison, l’appel à sauvegarder et l’appel à restaurer les interruptions doivent se produire dans la même fonction.

Toutes les fonctions précédentes peuvent être appelées à la fois par interruption et par contexte de processus.

4
4pie0

Lecture Pourquoi le code de noyau/thread s'exécutant dans un contexte d'interruption ne peut pas dormir? qui renvoie à Robert Loves article , je lis ceci:

certains gestionnaires d'interruptions (connus dans Linux en tant que gestionnaires d'interruptions rapides) s'exécutent avec toutes les interruptions sur le local processeur désactivé. Ceci est fait pour assurez-vous que le gestionnaire d'interruptions s'exécute sans interruption, aussi rapidement que possible. Plus encore, tous interrompent les gestionnaires courent avec leur courant ligne d'interruption désactivée sur tous processeurs. Cela garantit que deux interrompre les gestionnaires pour le même la ligne d'interruption ne fonctionne pas en même temps. Il empêche également le périphérique les rédacteurs de pilotes d'avoir à gérer interruptions récursives, qui compliquent la programmation.

2
Ian Vaughan

Cette question part de la fausse affirmation: On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.

Aucune de celles-ci ne doit être utilisée à partir de interruption Context, sur SMP ou sur UP. Cela dit, spin_lock_irqsave() peut être utilisé dans un contexte d'interruption, étant plus universel (Il peut être utilisé à la fois dans des contextes d'interruption et normaux), maisvous êtes supposé use spin_lock() depuis un contexte d'interruption, et spin_lock_irq() ou spin_lock_irqsave() depuis un contexte normal .. L'utilisation de spin_lock_irq() est presque toujours la mauvaise chose to faire dans le contexte d'interruption, étant ce SMP ou UP. Cela peut fonctionner Parce que la plupart des gestionnaires d’interruptions fonctionnent avec des IRQ activées localement, Mais vous ne devriez pas essayer.

0
stsp