Comment les interruptions sont-elles gérées sur SMP?

Comment les interruptions sont-elles gérées sur les machines SMP (Symmeteric multiprocessor / multicore)? Y a-t-il une seule unité de gestion de mémoire ou plus?

Supposons que deux threads, A et B s’exécutant sur des cœurs différents, touchent une page de mémoire (en même temps) qui n’est pas présente dans la table des pages. Dans ce cas, une erreur de page est générée.

Quelle est la séquence des événements qui va se passer? S’il existe une unité de gestion de la mémoire, à quel cœur la faute de page est-elle transmise? Comment le kernel le gère-t-il? Existe-t-il plusieurs instances du kernel, chacune exécutant un kernel différent? Si oui, comment se synchronisent-ils sur des événements tels que la gestion des fautes de page?

Sur les architectures multicœur / multiprocesseur, un APIC est utilisé pour acheminer les interruptions vers les cœurs / processeurs. Comme leur nom l’indique, les APIC peuvent être programmés pour effectuer le routage comme souhaité.

En ce qui concerne la synchronisation du kernel: Cela dépend du kernel / du système d’exploitation. Vous pouvez soit utiliser un schéma avec locking (bien que les IPI puissent être nécessaires sur des architectures non-cachecherentes) ou vous pouvez également utiliser l’approche suggérée consistant à exécuter un kernel sur chaque cœur et utiliser une sorte de communication inter-kernel explicite.

Barrelfish est un exemple de système d’exploitation exécutant plusieurs kernelx. Si vous êtes intéressé par ce type d’architecture, vous pouvez lire l’article ” Le Multikernel: une nouvelle architecture de système d’exploitation pour les systèmes multicœurs évolutifs “.

Eh bien, cela dépend de l’architecture spécifique, mais de ce que je peux me souvenir des documents Intel …

Il existe deux sources principales d’interruption:

  • Interne: ceux-ci sont générés par le processeur lui-même. Comprend les défauts, les interruptions, les interruptions de logiciel, etc.
  • Externe: Ce sont des interruptions matérielles générées par les périphériques.

Les interruptions internes sont toujours fournies à la CPU qui les a générées. Les externes sont envoyés à un kernel arbitraire.

Dans les modèles modernes, les interruptions peuvent également être délivrées à l’aide d’un système de type bus au lieu de l’ancien géré par interruption, mais j’ignore si ce modèle est utilisé dans un système d’exploitation actuel.

À propos de la MMU, chaque cœur a bien sûr sa propre version, mais les systèmes d’exploitation lui imposent généralement les mêmes segments, de sorte qu’ils peuvent être utilisés de manière symésortingque. Notez que la plupart des correspondances entre la mémoire physique et la mémoire virtuelle sont réellement en mémoire, et que celles-ci sont toujours partagées.

A propos de la séquence dans votre exemple:

  • Le défaut de page est transmis au cœur qui l’a généré.
  • Le kernel met à jour ses tables MMU, protégées par un verrou partagé ou similaire.
  • Non, il n’y a généralement qu’un kernel, sauf si vous appliquez un modèle de virtualisation.
  • Ils se synchronisent en utilisant un verrou partagé ou une structure similaire. Si les deux kernelx sont en panne à la même page au même moment … eh bien, ce n’est pas grave, en fait.

Chaque processeur possède sa propre unité de gestion de la mémoire avec un tampon de traduction. Cela est nécessaire car chaque cœur peut exécuter un processus différent qui possède un espace d’adressage différent.

Les cœurs multiples peuvent gérer indépendamment les interruptions / exceptions en même temps. Il peut donc y avoir plusieurs contextes d’interruption simultanés s’exécutant dans un kernel en même temps.

Une exception telle qu’une erreur de page ou une division par zéro sera toujours traitée sur le même processeur que celui sur lequel elle s’est produite, car elle se rapporte à ce que fait ce processeur.

Les interruptions externes passent généralement par une sorte de masortingce de commutation qui leur permet d’être mappées d’une manière ou d’une autre sur des processeurs, de manière statique ou dynamic. Par exemple, le “APIC” sur le matériel de type PC.

Si le tissu est suffisamment sophistiqué, les interruptions peuvent être reprogrammées en ciblant un cœur différent à la volée.

Cela dépend de l’architecture. Une architecture simpliste pourrait, par exemple, lier toutes les interruptions externes à un cœur. Ce ne serait pas très symésortingque cependant; cela ne permettrait pas d’équilibrer la charge IRQ.

(Notez également qu’il est utile que certaines interruptions externes se produisent sur tous les processeurs. Un exemple est l’interruption du minuteur. Si chaque cœur dispose de son propre minuteur, la gestion du temps dans le planificateur est symésortingque: pas de traitement de cas particulier pour un kernel principal par rapport aux autres: une interruption se déclenche, le kernel exécute le code du planificateur et, si le quantum de la tâche en cours est en hausse, il choisit une autre tâche à exécuter sur ce kernel.

Chaque CPU logique (c.-à-d. Le cœur du processeur) possède son propre registre cr3 , gérant le pointeur vers les structures de pagination. Les deux défauts de page peuvent se produire soit:

  • dans les fils du même processus
  • dans les fils de différents processus

Si ce sont des threads de processus différents, alors ce n’est pas un problème. Je ne sais pas quelle est l’implémentation spécifique de Linux (oui, je sais qu’il est étiqueté comme “linux”), mais il existe deux algorithmes généraux pour gérer la mémoire virtuelle dans un environnement SMP:

  • chaque kernel contient sa propre liste de pages physiques libres et en demande davantage lorsque toutes les pages de sa propre liste sont allouées
  • tous les cœurs utilisent la même liste de pages gratuites, protégées par une sorte de verrou (en général, le locking est suffisant), ce qui est bien sûr une solution plus lente

Le même code (gestionnaire #PF) peut s’exécuter simultanément sur deux cœurs différents, ce qui n’est pas un problème. Si les threads utilisent deux VAS différents 1 , leurs défauts de page sont simplement traités de manière symésortingque. Si les erreurs de page se produisent dans un seul VAS, cela ne pose toujours aucun problème jusqu’à ce que les #PF soient provoqués par l’access à la même page. Dans ce cas, chaque page de VAS doit être protégée par un spinlock (ou simplement #PF dans un VAS donné peut être protégé par un seul verrou – cette méthode réduit la surcharge de la mémoire, mais supprime la possibilité d’exécuter simultanément deux gestionnaires #PF).

Selon cette réponse , dans les systèmes NUMA uniquement, chaque cœur de processeur possède sa propre MMU; dans d’autres systèmes, chaque processeur physique possède son propre MMU, ainsi que TLB pour gérer différentes structures de pagination référencées par différentes valeurs du registre cr3 .


1. VAS = Espace d’adressage virtuel

Je n’ai pas eu les “multiples instances du kernel”, généralement le kernel règle toutes les règles. c’est-à-dire qu’il n’y a pas d’instance, il faut plutôt penser au kernel comme à un système réactif global, qui fournit des services aux applications.

Pour autant que je sache, la gestion de la mémoire est une unité (bien que chaque cœur ait son propre vecteur d’interruption), les pages sont verrouillées à l’aide de page_table_lock .

** EDIT: Après avoir vu les autres commentaires, ma réponse pourrait être dépassée: de toute façon, vous devriez vérifier: http://www.xml.com/ldd/chapter/book/ch13.html