Compréhension approfondie du sous-système de planification Linux - Partie 1

CPU

En tant que ressource informatique, le processeur a toujours été au cœur de la compétitivité des fournisseurs de cloud computing. Notre objectif est d'organiser les tâches informatiques de manière raisonnable, d'améliorer pleinement l'utilisation du processeur, de réserver plus d'espace pour la tolérance aux pannes, d'améliorer la stabilité du système et de permettre aux tâches d'être exécutées plus rapidement. réduire la consommation d'énergie inefficace, réduire les coûts, améliorant ainsi la compétitivité du marché.

Schéma logique abstrait de l'implémentation du processeur

  1. Tout d'abord, nous avons un compteur automatique. Ce compteur automatique augmentera continuellement avec la fréquence principale de l'horloge comme notre registre PC ;

  2. Derrière ce compteur automatique, on connecte un décodeur. Le décodeur est également connecté à la mémoire que nous avons constituée à travers un grand nombre de bascules D.

  3. Le compteur automatique augmentera en continu avec la fréquence principale de l'horloge. À partir du décodeur, recherchez l'adresse mémoire représentée par le compteur correspondant, puis lisez les instructions du processeur à l'intérieur.

  4. L'instruction CPU de lecture sera contrôlée par l'horloge CPU et écrite dans un registre composé de bascules D, c'est-à-dire le registre d'instructions.

  5. Après le registre d'instructions, on peut suivre un autre décodeur. La fonction de ce décodeur n'est plus utilisée pour l'adressage, mais pour analyser les instructions obtenues en opcode et opérandes correspondants.

  6. Lorsque nous obtenons l'opcode et l'opérande correspondants, la ligne de sortie correspondante sera connectée à l'ALU, et diverses opérations arithmétiques et logiques commenceront. Les résultats de calcul correspondants seront réécrits dans le registre ou la mémoire composée de bascules D.

L'ensemble du processus ici est probablement le processus d'exécution d'une instruction du CPU. Afin d'accélérer la vitesse d'exécution des instructions du processeur, le processeur a effectué de nombreuses optimisations dans le processus de développement, telles que le pipeline, la prédiction de branche, le superscalaire, l'hyper-threading, le SIMD, le cache à plusieurs niveaux, l'architecture NUMA, etc. Ici nous nous concentrons principalement sur le système de planification Linux.

de la planète des geeks

Contexte CPU

Linux est un système d'exploitation multitâche, qui prend en charge l'exécution simultanée de tâches bien supérieures au nombre de processeurs. Bien sûr, ces tâches ne s'exécutent pas réellement en même temps, mais parce que le système leur alloue le CPU à tour de rôle dans un court laps de temps, créant l'illusion que plusieurs tâches s'exécutent en même temps.

Avant l'exécution de chaque tâche, le processeur doit savoir où la tâche est chargée et a commencé à s'exécuter, c'est-à-dire que le système doit définir à l'avance les registres du processeur et le compteur de programme (compteur de programme, PC).

Le registre CPU est une mémoire de petite capacité mais extrêmement rapide intégrée au CPU. Le compteur de programme est utilisé pour stocker la position de l'instruction en cours d'exécution par la CPU, ou la position de la prochaine instruction à exécuter. Ce sont tous des environnements dépendants du CPU avant d'exécuter des tâches, ils sont donc également appelés contexte CPU (environnement d'exécution) :

                             

Ces contextes sauvegardés seront stockés dans le noyau du système (pile) et chargés à nouveau lorsque la tâche sera replanifiée pour exécution. De cette manière, l'état d'origine de la tâche ne sera pas affecté et la tâche semblera s'exécuter en continu.

Sous Linux, l'espace noyau et l'espace utilisateur sont deux modes de fonctionnement. Le système d'exploitation s'exécute dans l'espace noyau, tandis que les applications en mode utilisateur s'exécutent dans l'espace utilisateur. Ils représentent différents niveaux et ont des droits d'accès différents aux ressources système.

De cette manière, il existe différents contextes CPU pour l'exécution du code (instruction), et lors de la planification, le changement de contexte CPU correspondant est requis. Il existe différentes piles dans le système Linux pour enregistrer le contexte CPU. Chaque processus du système aura son propre pile de noyau, et chaque CPU du système préparera deux piles d'interruptions indépendantes pour le traitement des interruptions, à savoir la pile hardirq et la pile softirq :

Structure de la pile de changement de contexte CPU de l'appel système Linux :

        

  • Contexte d'interruption : le code d'interruption s'exécute dans l'espace du noyau. Le contexte d'interruption est l'environnement de contexte CPU requis pour exécuter le code d'interruption. Ces paramètres doivent être passés par le matériel et certains autres environnements dont le noyau a besoin pour enregistrer (principalement le processus actuellement interrompu ou autre environnement d'interruption), ceux-ci sont généralement stockés dans la pile d'interruption (x86 est indépendant, d'autres peuvent être partagés avec la pile du noyau, qui est étroitement liée à l'architecture de traitement spécifique), après la fin de l'interruption, le le processus peut toujours reprendre à partir de l'état d'origine.

  • Contexte de processus : les processus sont gérés et planifiés par le noyau. La commutation de processus se produit dans l'état du noyau. Le contexte d'un processus inclut non seulement les ressources de l'espace utilisateur telles que la mémoire virtuelle, les piles et les variables globales, mais également l'espace du noyau, comme les piles du noyau. et registres.

  • Contexte d'appel système : un processus peut s'exécuter dans l'espace noyau et l'espace utilisateur, appelés respectivement état utilisateur du processus et état noyau du processus. La transition de l'état utilisateur à l'état noyau doit être effectuée via un appel système. , ce qui nécessite un changement de contexte CPU. Lorsque le système appelle, il est nécessaire de sauvegarder le contexte CPU du mode utilisateur (pile du mode utilisateur) dans la pile du noyau, puis de charger le contexte CPU du mode noyau.

  • Le processeur CPU est toujours dans l'un des états suivants :
    1. État du noyau, s'exécutant dans le contexte du processus, le noyau représente le processus s'exécutant dans l'espace du noyau ;
    2, État du noyau, s'exécutant dans le contexte de l'interruption, le noyau représente le matériel s'exécutant dans l'espace noyau
    3. Mode utilisateur, s'exécutant dans l'espace utilisateur.

interrompre

Les interruptions sont générées par des périphériques matériels, et ce sont des signaux physiquement électriques. Après cela, elles sont envoyées au CPU via le contrôleur d'interruption, puis le CPU détermine de quel périphérique matériel provient l'interruption reçue (ceci est défini dans le noyau), et enfin , envoyé par le CPU au noyau, et le noyau gère l'interruption.

Flux de traitement simple de l'interruption matérielle :

Implémentation d'interruption matérielle : contrôleur d'interruption + routine de service d'interruption

Conception du framework d'interruption (x86) :

Le CPU de l'ordinateur X86 ne fournit que deux broches externes pour les interruptions : NMI et INTR. Parmi eux, NMI est une interruption non masquable, qui est généralement utilisée pour les pannes de courant et la parité de la mémoire physique ; INTR est une interruption masquable, qui peut être masquée en définissant le bit de masque d'interruption. Il est principalement utilisé pour accepter des signaux d'interruption provenant de sources externes. Le signal est transmis au CPU par le contrôleur d'interruption. Le courant dominant de l'architecture SMP x86 actuelle consiste à utiliser le système d'interruption APIC (Advanced Programmable Interrupt Controller) d'E / S à plusieurs niveaux.

  • APIC local : principalement responsable de la transmission des signaux d'interruption au processeur spécifié ;

  • I/O APIC : collecte principalement les signaux d'interruption des périphériques d'E/S et envoie des signaux à l'APIC local lorsque ces périphériques doivent être interrompus ;

 

Classement des interruptions :

Les interruptions peuvent être divisées en interruptions synchrones ( synchronous ) et en interruptions asynchrones ( asynchronous ) :

  • Une interruption synchrone est activement générée par l'unité de contrôle de la CPU lorsqu'une instruction est exécutée. Elle est appelée synchrone car la CPU n'émet une interruption qu'après l'exécution d'une instruction, plutôt que pendant l'exécution d'une instruction de code, telle qu'un appel système. Selon Intel Selon les informations officielles, l'interruption synchrone est appelée exception , et les exceptions peuvent être divisées en trois catégories : fault , trap et abort .

  • Les interruptions asynchrones sont générées de manière aléatoire par d'autres périphériques matériels en fonction du signal d'horloge du processeur, ce qui signifie que des interruptions peuvent se produire entre des instructions, telles que des interruptions de clavier. Les interruptions asynchrones sont appelées interruptions et les interruptions peuvent être divisées en interruptions masquables. ) et non masquable interruption ( interruption nomasquable ).

  1. Interruptions non masquables (NMI) : Tout comme la signification littérale de ce type d'interruption, ce type d'interruption ne peut pas être ignoré ou annulé par le CPU. NMI est envoyé sur une ligne d'interruption séparée, qui est généralement utilisée pour les erreurs matérielles critiques, telles que les erreurs de mémoire, les pannes de ventilateur, les pannes de capteur de température, etc.

  2. Interruptions masquables (Maskable interrupts) : Ces interruptions peuvent être ignorées ou retardées par le CPU. Ce type d'interruption sera généré lorsque la broche externe du contrôleur de cache est déclenchée, et le registre de masque d'interruption masquera une telle interruption. Nous pouvons mettre un bit à 0 pour désactiver les interruptions déclenchées sur cette broche.

Flux de traitement :

la différence:

Même remarque :

1. Au final, il est envoyé au noyau par le CPU et traité par le noyau ;

2. La conception de flux du programme de traitement est similaire.

différence:

1. Les sources de génération sont différentes : les interruptions et les exceptions sont générées par le CPU, tandis que les interruptions sont générées par les périphériques matériels ;

2. Le noyau doit appeler différents gestionnaires selon qu'il s'agit d'une exception, d'un piège ou d'une interruption ;

3. Les interruptions ne sont pas synchrones avec l'horloge, ce qui signifie que les interruptions peuvent survenir à tout moment, les interruptions et les exceptions sont générées par le processeur, elles sont donc synchrones avec l'horloge.

4. Lors du traitement des interruptions, il se trouve dans le contexte de l'interruption, lors du traitement des interruptions et des exceptions, il se trouve dans le contexte du processus.

Interrompre l'affinité :

  • Dans l'architecture SMP, nous pouvons définir l'affinité CPU (affinité CPU) via des appels système et un ensemble de macros associées, et lier un ou plusieurs processus pour qu'ils s'exécutent sur un ou plusieurs processeurs. Les interruptions ne montrent aucune faiblesse à cet égard non plus et partagent les mêmes propriétés. L'affinité d'interruption fait référence à la liaison d'une ou plusieurs sources d'interruption pour qu'elles s'exécutent sur un processeur spécifique ;

  • Dans le répertoire /proc/irq, pour les périphériques matériels qui ont enregistré des gestionnaires d'interruptions, il y aura un répertoire IRQ# nommé d'après le numéro d'interruption sous ce répertoire, et il y aura un fichier smp_affinity sous le répertoire IRQ# (uniquement pour l'architecture SMP )), il s'agit d'un masque de bits CPU, qui peut être utilisé pour définir l'affinité de l'interruption, et la valeur par défaut est 0xffffffff, indiquant que l'interruption est envoyée à tous les CPU pour traitement. Si le contrôleur d'interruption ne prend pas en charge l'affinité IRQ, cette valeur par défaut ne peut pas être modifiée et tous les masques de bits CPU ne peuvent pas être désactivés, c'est-à-dire qu'ils ne peuvent pas être définis sur 0x0 ;

  • L'avantage de l'affinité d'interruption est que dans un grand nombre de scénarios d'interruption matérielle, pour des applications telles que les serveurs de fichiers et les serveurs Web à fort trafic, la liaison de différentes IRQ de carte réseau à différents processeurs de manière équilibrée réduira la charge sur un certain processeur et améliorer plusieurs La capacité de chaque CPU à gérer les interruptions dans leur ensemble ; pour les applications telles que les serveurs de base de données, la liaison du contrôleur de disque à un CPU et de la carte réseau à un autre CPU améliorera le temps de réponse de la base de données et optimisera les performances. Équilibrer raisonnablement les interruptions IRQ en fonction des caractéristiques de votre propre environnement de production et de vos applications peut aider à améliorer le débit global et les performances du système ;

  Informations via le train : Itinéraire d'apprentissage de la technologie du code source du noyau Linux + didacticiel vidéo sur le code source du noyau

Apprentissage par le train : code source du noyau Linux réglage de la mémoire gestion des processus du système de fichiers pilote de périphérique/pile de protocole réseau

Classification des interruptions courantes dans le système Linux

Interruption d'horloge :

La puce d'horloge est générée et sa tâche principale consiste à traiter toutes les informations liées au temps, à décider d'exécuter ou non le planificateur et à traiter la seconde moitié. Toutes les informations relatives au temps incluent l'heure système, la tranche de temps du processus, le retard, le temps CPU et divers temporisateurs. La tranche de temps mise à jour du processus fournit la base de la planification du processus, puis décide s'il faut s'exécuter lorsque l'interruption de l'horloge renvoie le planificateur. Un gestionnaire de seconde moitié est un mécanisme fourni par Linux pour différer l'exécution d'une partie du travail. L'interruption de l'horloge doit absolument garantir l'exactitude de l'heure système. "L'interruption de l'horloge" est le pouls de l'ensemble du système d'exploitation.

Interruption NMI :

Le matériel externe se déclenche via la broche NMI de la CPU (déclencheur matériel), ou le logiciel délivre une interruption de type NMI au bus système de la CPU (déclencheur logiciel). Il existe deux utilisations principales de l'interruption NMI :

  • Il est utilisé pour informer le système d'exploitation d'une défaillance matérielle (défaillance matérielle), telle qu'une erreur de mémoire, une défaillance du ventilateur, une défaillance du capteur de température, etc. ;

  • Utilisé comme minuteur de surveillance pour détecter les blocages du processeur, etc. ;

Interruption E/S matérielle :

La plupart des interruptions d'E/S des périphériques matériels, telles que les cartes réseau, les claviers, les disques durs, les souris, les ports USB, les ports série, etc. ;

Interruption virtuelle :

Certaines sorties d'interruption et injection d'interruption dans KVM, interruption de simulation logicielle ;

Méthode d'affichage : cat /proc/interrupts

Gestion des interruptions du système Linux

Étant donné que l'interruption interrompra l'opération de planification normale du processus dans le noyau, le programme de service d'interruption doit être aussi court et concis que possible ; mais dans le système réel, lorsque l'interruption arrive, cela prend souvent beaucoup de temps. traitement fastidieux pour achever le travail. Par conséquent, on s'attend à ce que le gestionnaire d'interruptions s'exécute plus rapidement et qu'il accomplisse plus de travail.Ces deux objectifs se limitent mutuellement et le mécanisme de la moitié supérieure/inférieure est né.

Interrompre la moitié supérieure :

Le gestionnaire d'interruption est la moitié supérieure - acceptez l'interruption, il commence à s'exécuter immédiatement, mais ne fait que des travaux urgents. Le travail qui peut être autorisé à être effectué plus tard est reporté à la moitié inférieure, après quoi, au bon moment, la moitié inférieure est ouverte pour exécution. La moitié supérieure est simple et rapide, et certaines ou toutes les interruptions sont désactivées pendant l'exécution.

Interrompre la moitié inférieure :

La moitié inférieure est exécutée plus tard et toutes les interruptions peuvent être traitées pendant l'exécution. Cette conception peut rendre le temps pendant lequel le système est dans l'état de protection contre les interruptions aussi court que possible, de manière à améliorer la réactivité du système. La moitié supérieure n'a qu'un mécanisme de gestionnaire d'interruptions, tandis que la moitié inférieure implémente des interruptions logicielles, des tasklets et des files d'attente de travail ;

interruption douce

Softirq, en tant que représentant du mécanisme de la moitié inférieure, a vu le jour avec l'émergence du SMP (processeur de mémoire partagée), et c'est aussi la base de l'implémentation des tasklets (les tasklets ne font en fait qu'ajouter un certain mécanisme sur la base de softirq). Les interruptions logicielles sont généralement le terme général pour les "fonctions retardables", et parfois les tasklets sont également inclus (les lecteurs sont invités à déduire si les tasklets sont inclus en fonction du contexte lorsqu'ils les rencontrent). Il apparaît parce qu'il doit répondre à la différence entre la moitié supérieure et la moitié inférieure proposée ci-dessus, de sorte que l'exécution des tâches insensibles au temps est retardée, et il peut être exécuté en parallèle sur plusieurs processeurs, de sorte que l'efficacité globale du système peut être plus élevé. Ses caractéristiques incluent : il ne peut pas être exécuté immédiatement après sa génération et il doit attendre l'ordonnancement du noyau pour s'exécuter.

Les interruptions logicielles ne peuvent pas être interrompues par elles-mêmes (c'est-à-dire que les interruptions logicielles sur un seul processeur ne peuvent pas être imbriquées) et ne peuvent être interrompues que par des interruptions matérielles (la partie supérieure) et peuvent s'exécuter simultanément sur plusieurs processeurs (même du même type). Par conséquent, l'interruption logicielle doit être conçue comme une fonction réentrante (permettant à plusieurs processeurs de fonctionner en même temps), il est donc également nécessaire d'utiliser un verrou tournant pour protéger sa structure de données.


Planification de la synchronisation des interruptions logicielles :

  1. irq_exit est appelé lorsque do_irq termine l'interruption d'E/S.

  2. Le système utilise l'API d'E/S lors du traitement de l'interruption de l'horloge locale.

  3. local_bh_enable, c'est-à-dire lorsque l'interruption logicielle locale est activée.

  4. Dans le système SMP, lorsque le processeur termine le traitement de la fonction déclenchée par l'interruption interprocesseur CALL_FUNCTION_VECTOR.

  5. Lorsque le thread ksoftirqd/n est réveillé.

fil du noyau softirq

Sous Linux, les interruptions ont la priorité la plus élevée. Peu importe à tout moment, tant qu'un événement d'interruption se produit, le noyau exécute immédiatement le gestionnaire d'interruption correspondant et attend que toutes les interruptions en attente et les interruptions logicielles soient traitées avant d'effectuer des tâches normales, de sorte que les tâches en temps réel ne peuvent pas être traitées dans temps. Une fois l'interruption enfilée, l'interruption s'exécutera en tant que thread du noyau et recevra une priorité en temps réel différente. La tâche en temps réel peut avoir une priorité plus élevée que le thread d'interruption. De cette façon, les tâches en temps réel avec la priorité la plus élevée peuvent être traitées en premier, et les performances en temps réel sont garanties même en cas de charge importante. Cependant, toutes les interruptions ne peuvent pas être threadées, comme les interruptions d'horloge, qui sont principalement utilisées pour maintenir l'heure système et les minuteries, etc. La minuterie est l'impulsion du système d'exploitation. Une fois threadée, elle peut être suspendue, et les conséquences seraient impensable, donc ne devrait pas être fileté.

L'interruption logicielle est d'abord exécutée dans irq_exit(), et si la condition dépasse le temps, elle sera exécutée dans le thread softirqd. Les softirqs sont exécutés dans le thread softirqd si l'une des conditions suivantes est remplie :

  • L'exécution dans irq_exit()->__do_softirq() prend plus de 2 ms.

  • S'exécute dans irq_exit()->__do_softirq(), interrogeant softirq plus de 10 fois.

  • S'exécutant dans irq_exit()->__do_softirq(), ce thread doit être planifié.

Remarque : lors de l'appel de raise_softirq() pour réveiller l'interruption logicielle, celle-ci n'est pas dans l'environnement d'interruption.

TÂCHE

Étant donné que les interruptions logicielles doivent utiliser des fonctions réentrantes, cela conduit à une complexité de conception plus élevée, ce qui augmente la charge des développeurs de pilotes de périphériques. Et si une application n'a pas besoin d'être exécutée en parallèle sur plusieurs processeurs, les interruptions logicielles sont en fait inutiles. Par conséquent, une tasklet est née pour compenser les deux exigences ci-dessus. Il a les propriétés suivantes :

a) Un type spécifique de tasklet ne peut s'exécuter que sur un processeur, non pas en parallèle, mais en série.

b) Plusieurs tasklets de différents types peuvent s'exécuter en parallèle sur plusieurs processeurs.

c) Les interruptions logicielles sont allouées statiquement et ne peuvent pas être modifiées après la compilation du noyau. Mais les tasklets sont beaucoup plus flexibles et peuvent être modifiés au moment de l'exécution (comme lors de l'ajout de modules).

Tasklet est implémenté sur la base de deux types de softirq, donc si la fonctionnalité parallèle de softirq n'est pas requise, tasklet est le meilleur choix. C'est-à-dire que la tasklet est une utilisation spéciale de l'interruption logicielle, c'est-à-dire l'exécution en série sous délai.

Il existe deux types de tasklets, tasklet et hi-tasklet :

  • la tasklet   correspond à softirq_vec[TASKLET_SOFTIRQ] ;

  • hi-tasklet  correspond à softirq_vec[HI_SOFTIRQ]. C'est juste que ce dernier est classé premier dans softirq_vec[], donc il est exécuté plus tôt ;

/proc/softirqs fournit l'état d'exécution de softirqs

# cat /proc/softirqs
CPU0      
HI:    1   //高优先级TASKLET软中断
TIMER:   12571001  //定时器软中断
NET_TX:     826165  //网卡发送软中断
NET_RX:    6263015  //网卡接收软中断
BLOCK:    1403226  //块设备处理软中断
BLOCK_IOPOLL:   0  //块设备处理软中断
TASKLET:   3752   //普通TASKLET软中断
SCHED:     0  //调度软中断
HRTIMER:   0  //当前已经没有使用
RCU:    9729155  //RCU处理软中断,主要是callback函数处理

file d'attente de travail

La file d'attente de travail (work queue) est un mécanisme du noyau Linux permettant de différer l'exécution d'un travail. Les interruptions logicielles s'exécutent dans le contexte d'interruption, de sorte qu'elles ne peuvent pas bloquer et dormir, et les tasklets sont implémentées à l'aide d'interruptions logicielles, et bien sûr, elles ne peuvent pas bloquer et dormir. La file d'attente de travail peut reporter le travail et le transmettre à un thread du noyau pour exécution— cette partie inférieure sera toujours exécutée dans le cadre du processus, donc l'avantage de la file d'attente de travail est qu'elle permet la replanification et même la mise en veille.

Plusieurs relations de rôle dans la file d'attente :

  • travail  : travail/tâche.

  • workqueue  : Une collection de travaux. workqueue et work est une relation un-à-plusieurs.

  • ouvrier  : ouvrier. Dans le code, worker correspond à un thread noyau work_thread().

  • worker_pool : Une collection de travailleurs. La relation entre worker_pool et worker est un-à-plusieurs.

  • pwq (pool_workqueue) : middleman/intermédiaire, chargé d'établir la relation entre workqueue et worker_pool. La relation entre workqueue et pwq est un-à-plusieurs, et celle entre pwq et worker_pool est un-à-un.

En général, pour choisir entre les files d'attente de travail et les softirqs/tasklets, les règles suivantes peuvent être utilisées :

  • Si la tâche reportée doit être mise en veille, seule la file d'attente de travail peut être sélectionnée.

  • Si la tâche de post-exécution doit être retardée pendant une durée spécifiée avant d'être déclenchée, utilisez la file d'attente de travail car elle peut utiliser le délai du minuteur (implémentation du minuteur du noyau).

  • Si la tâche de post-exécution doit être traitée en un tick, utilisez une interruption logicielle ou une tasklet, car elle peut préempter les processus ordinaires et les threads du noyau et ne peut pas dormir en même temps.

  • Si la tâche reportée n'a aucune exigence pour le temps de retard, la file d'attente de travail est utilisée, ce qui est généralement une tâche insignifiante à ce moment.

En fait, l'essence de la file d'attente de travail est de remettre le travail au thread du noyau, afin qu'il puisse être remplacé par le thread du noyau. Cependant, la création et la destruction des threads du noyau ont des exigences élevées pour les programmeurs, et la file d'attente de travail réalise l'encapsulation des threads du noyau, ce qui n'est pas facile de faire des erreurs.Il est recommandé d'utiliser des files d'attente de travail.

contexte d'interruption

Le code d'interruption s'exécute dans l'espace du noyau. Le contexte d'interruption est l'environnement de contexte CPU requis pour exécuter le code d'interruption. Ces paramètres doivent être transmis par le matériel et certains autres environnements que le noyau doit enregistrer (principalement le processus actuellement interrompu ou d'autres environnements d'interruption), Ceux-ci sont généralement stockés dans la pile d'interruption (x86 est indépendant, et d'autres peuvent être partagés avec la pile du noyau, qui est étroitement liée à l'architecture de traitement spécifique). Une fois l'interruption terminée, le processus peut toujours reprendre de l'état d'origine.

Qu'il soit interrompu ou non est jugé par preempt_count sous Linux, comme suit :

#define in_irq() (hardirq_count()) //dans le traitement des interruptions dures

#define in_softirq() (softirq_count()) //dans le traitement de softirq

#define in_interrupt() (irq_count()) //dans le traitement des interruptions matérielles ou logicielles

#define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0) //Inclure tous les cas ci-dessus

  

Résumé et points à noter :

1. Le concepteur du noyau Linux a établi les règles :

  • Le contexte d'interruption n'est pas une entité de planification , la tâche est [processus (thread principal) ou thread] ;

  • Ordre de priorité : contexte d'interruption matérielle > contexte d'interruption logicielle > contexte de processus ;

Le contexte d'interruption (contexte hardirq et softirq) ne participe pas à l'ordonnancement (le threading d'interruption n'est pas envisagé pour le moment), il s'agit d'un mécanisme de traitement des événements asynchrones, et le but est de terminer le traitement dès que possible et de revenir à la scène. Par conséquent, la priorité de tous les contextes d'interruption est supérieure à celle des contextes de processus. C'est-à-dire que pour les processus utilisateur (que ce soit en mode noyau ou en mode utilisateur) ou les threads du noyau, à moins que l'interruption locale du CPU ne soit désactivée, une fois qu'une interruption se produit, ils n'ont pas la capacité d'empêcher le contexte d'interruption de préempter l'exécution du courant. contexte du processus.

2.Linux divise le processus de traitement des interruptions en deux étapes, à savoir la moitié supérieure et la moitié inférieure :

  • La partie supérieure est utilisée pour traiter rapidement les interruptions. Elle fonctionne en mode interruption désactivée et traite principalement des tâches liées au matériel ou sensibles au temps qui doivent être exécutées rapidement ;

  • La partie inférieure est utilisée pour retarder le traitement du travail inachevé de la partie supérieure et s'exécute généralement en mode d'interruption logicielle, ce qui peut retarder l'exécution.

3. Les interruptions matérielles et les interruptions logicielles (tant qu'elles sont des contextes d'interruption) ne peuvent pas être préemptées par le noyau (la préemption du noyau sera abordée dans les chapitres suivants de cet article). Parce que dans le contexte d'interruption, le seul qui peut interrompre le gestionnaire d'interruption actuel est une interruption de priorité plus élevée, qui ne sera pas interrompue par le processus (c'est la même chose pour softirq et tasklet, donc ces moitiés inférieures ne peuvent pas dormir); si dans Dormir dans le contexte d'interruption, il n'y a aucun moyen de le réveiller, car tous les wake_up_xxx sont pour un certain processus, mais dans le contexte d'interruption, il n'y a pas de concept de processus, pas de task_struct correspondant (c'est la même chose pour softirq et tasklet) , donc Vraiment dormir, comme appeler une routine qui provoquera un blocage, le noyau se bloquera presque.

4. Une interruption matérielle peut être "interrompue" par une autre interruption matérielle avec une priorité plus élevée qu'elle-même, mais ne peut pas être "interrompue" par une interruption matérielle de même niveau (le même type d'interruption matérielle) ou une interruption matérielle de bas niveau , sans parler d'une interruption douce. Une interruption logicielle peut être « interrompue » par une interruption matérielle, mais pas « interrompue » par une autre interruption logicielle. Sur un CPU, les softirqs sont toujours exécutés en série. Ainsi, sur un monoprocesseur, l'accès à la structure de données de l'interruption logicielle ne nécessite aucune primitive de synchronisation.

5. La désactivation des interruptions ne perdra pas d'interruptions, mais plusieurs interruptions identiques arrivant pendant la période seront fusionnées en une seule, c'est-à-dire traitées une seule fois ; la valeur de comptage jieffis doit être mise à jour dans l'interruption d'horloge. Si plusieurs interruptions sont combinées en une seule un, afin de réduire l'impact sur la précision de la valeur jieffis, besoin d'une autre horloge matérielle pour corriger.

 

Je suppose que tu aimes

Origine blog.csdn.net/youzhangjing_/article/details/131577331
conseillé
Classement