4. Gestionnaire d'interruptions
Le gestionnaire d'interruptions sous Linux est tout à fait unique. Son gestionnaire d'interruptions est divisé en deux parties : la moitié supérieure et la moitié inférieure. La raison pour laquelle il existe des moitiés supérieure et inférieure est entièrement due à l'efficacité du traitement des interruptions.
La fonction de la moitié supérieure est "Interruption d'enregistrement". Lorsqu'une interruption se produit, la moitié inférieure de la routine d'interruption du pilote de périphérique est suspendue dans la moitié inférieure de la file d'attente d'exécution du périphérique, puis tout va bien - en attendant l'arrivée d'une nouvelle interruption. De cette façon, la moitié supérieure sera exécutée rapidement et il pourra accepter davantage d'interruptions générées par l'équipement dont elle est responsable. La raison pour laquelle la partie supérieure est plus rapide est qu'elle masque complètement les interruptions si son exécution ne termine pas, les autres interruptions ne peuvent pas être traitées à temps et ne peuvent qu'attendre que le gestionnaire d'interruption soit exécuté. Par conséquent, pour traiter et gérer autant d’interruptions générées par le périphérique que possible, le gestionnaire d’interruptions doit être rapide.
Cependant, le traitement de certains événements d'interruption est plus compliqué, le gestionnaire d'interruption doit donc passer un peu plus de temps pour terminer la chose. Mais comment résoudre la contradiction de réaliser un traitement complexe en peu de temps ? À cette époque, Linux a introduit le concept de moitié inférieure. La plus grande différence entre la moitié inférieure et la moitié supérieure est que la moitié inférieure est discontinue, tandis que la moitié supérieure est ininterruptible.
La moitié inférieure fait presque tout ce que fait le gestionnaire d'interruptions, car la moitié supérieure met simplement la moitié inférieure en file d'attente de traitement des interruptions du périphérique dont elle est responsable, puis ne se soucie de rien. La partie inférieure est généralement chargée d'observer l'appareil pour obtenir des informations sur les événements générant des interruptions, et d'effectuer le traitement correspondant basé sur ces informations (généralement obtenues en lisant les registres de l'appareil). S'il y a des moments où l'autre moitié ne sait pas quoi faire, elle utilise le fameux algorithme de l'autruche pour résoudre le problème - pour parler franchement, elle ignore l'événement.
Étant donné que la moitié inférieure est interruptible, si d'autres appareils sont interrompus pendant son fonctionnement, la moitié inférieure peut être temporairement interrompue jusqu'à ce que la moitié supérieure de cet appareil ait fini de fonctionner. Revenez en arrière et exécutez-le. Mais une chose doit être notée : si un gestionnaire d'interruption de périphérique est en cours d'exécution, qu'il exécute la moitié supérieure ou la moitié inférieure, tant que le gestionnaire d'interruption n'a pas terminé le traitement, de nouvelles interruptions générées par le périphérique pendant cette période sera ignorée. Les interruptions seront ignorées. Étant donné que les gestionnaires d'interruptions ne sont pas réentrants, le même gestionnaire d'interruptions ne peut pas être exécuté en parallèle.
Avant le noyau Linux 2.0, les interruptions étaient divisées en interruptions rapides et interruptions lentes (nous ne parlerons pas ici de pseudo-interruptions). La moitié inférieure de l'interruption rapide est également ininterruptible, ce qui peut garantir une exécution plus rapide). . Cependant, à mesure que le niveau matériel continue d'augmenter, il n'y a aucune différence dans la vitesse d'exécution des interruptions rapides et des interruptions lentes. Par conséquent, afin d'améliorer l'efficacité du traitement des transactions de routine d'interruption, à partir du noyau Linux 2.0, tous les gestionnaires d'interruptions sont intégrés. sous forme d'interruptions lentes --Leur moitié inférieure peut être interrompue.
Cependant, dans la seconde moitié, vous pouvez également masquer les interruptions - si un certain morceau de code ne peut pas être interrompu. Vous pouvez utiliser cti, sti ou save_flag, restaurer_flag pour réaliser votre idée. En ce qui concerne leur utilisation et leurs différences, veuillez vous référer à la section sur le traitement des interruptions de l'ouvrage de référence désigné dans cet article.
Pour plus de détails, veuillez vous référer à l'ouvrage de référence spécifié dans cet article. Je n'entrerai pas dans les détails ici. Mon objectif n'est pas d'introduire les détails en détail. Mon objectif est d'organiser les concepts.
5. Définissez le bit d'indicateur d'interruption
Lors du traitement d'une interruption, le contrôleur d'interruption bloquera le périphérique qui a initialement envoyé l'interruption jusqu'à ce que la dernière interruption qu'elle a envoyée ait été traitée. Par conséquent, si le périphérique qui a envoyé l'interruption envoie une autre interruption pendant le traitement de l'interruption, l'interruption sera perdue pour toujours.
La raison pour laquelle cela se produit est que le contrôleur d'interruption ne peut pas mettre en mémoire tampon les informations d'interruption, donc si une nouvelle interruption arrive avant que l'interruption en cours ne soit traitée, il perdra définitivement la nouvelle interruption. Cependant, ce défaut peut être résolu en définissant le « définir l'indicateur d'interruption » (sti) sur le processeur principal (CPU), car le processeur principal a pour fonction de mettre en mémoire tampon les interruptions. Si « définir le bit d'indicateur d'interruption » est utilisé, alors la fonction sti peut être utilisée pour traiter l'interruption précédemment masquée après le traitement de l'interruption.
Ce qui précède est une analyse approfondie des interruptions du pilote de périphérique Linux (1) (2). Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !