- Quelle est la différence entre la pile du noyau et la pile utilisateur?
En bref, rien - à part l'utilisation d'un emplacement différent dans la mémoire (et donc une valeur différente pour le registre de stackpointer), et généralement différentes protections d'accès à la mémoire. C'est-à-dire que lors de l'exécution en mode utilisateur, la mémoire du noyau (dont une partie est la pile du noyau) ne sera pas accessible même si elle est mappée. Vice versa, sans être explicitement demandée par le code du noyau (sous Linux, via des fonctions comme copy_from_user()
), la mémoire utilisateur (y compris la pile utilisateur) n'est généralement pas directement accessible.
- Pourquoi une pile de noyau [distincte] est-elle utilisée?
Séparation des privilèges et de la sécurité. D'une part, les programmes de l'espace utilisateur peuvent faire de leur pile (pointeur) tout ce qu'ils veulent, et il n'y a généralement aucune exigence architecturale pour même en avoir une valide. Le noyau ne peut donc pas faire confiance au pointeur de pile de l'espace utilisateur pour être valide ou utilisable, et par conséquent nécessitera un ensemble sous son propre contrôle. Différentes architectures de CPU implémentent cela de différentes manières; Les processeurs x86 commutent automatiquement de pointeur de pile lorsque des commutations de mode de privilège se produisent, et les valeurs à utiliser pour différents niveaux de privilège sont configurables - par code privilégié (c'est-à-dire uniquement le noyau).
- Si une variable locale est déclarée dans un ISR, où sera-t-elle stockée?
Sur la pile du noyau. Le noyau (noyau Linux, c'est-à-dire) n'accroche pas les ISR directement aux portes d'interruption de l'architecture x86, mais délègue à la place l'envoi d'interruption à un mécanisme commun d'entrée / sortie d'interruption du noyau qui enregistre l'état du registre de pré-interruption avant d'appeler le (s) gestionnaire (s) enregistré (s) . Le processeur lui-même lors de la distribution d'une interruption peut exécuter un privilège et / ou un commutateur de pile, et ceci est utilisé / configuré par le noyau de sorte que le code d'entrée d'interruption commun puisse déjà compter sur la présence d'une pile de noyau.
Cela dit, les interruptions qui se produisent lors de l'exécution du code du noyau utiliseront simplement (continueront) d'utiliser la pile du noyau en place à ce stade. Cela peut, si les gestionnaires d'interruption ont des chemins d'appels profondément imbriqués, entraîner des débordements de pile (si un chemin d'appel profond du noyau est interrompu et que le gestionnaire provoque un autre chemin profond; sous Linux, le code RAID du système de fichiers / logiciel est interrompu par le code réseau avec iptables actif est connu pour déclencher une telle situation dans les noyaux plus anciens non réglés ... la solution est d'augmenter la taille de la pile du noyau pour de telles charges de travail).
- Chaque processus a-t-il sa propre pile de noyau?
Pas seulement chaque processus - chaque thread a sa propre pile de noyau (et, en fait, sa propre pile d'utilisateurs également). N'oubliez pas que la seule différence entre les processus et les threads (sous Linux) est le fait que plusieurs threads peuvent partager un espace d'adressage (formant un processus).
- Comment le processus se coordonne-t-il entre ces deux piles?
Pas du tout - ce n'est pas nécessaire. La planification (comment / quand différents threads sont exécutés, comment leur état est enregistré et restauré) est la tâche du système d'exploitation et les processus n'ont pas besoin de se préoccuper de cela. Au fur et à mesure que les threads sont créés (et que chaque processus doit avoir au moins un thread), le noyau crée des piles de noyau pour eux, tandis que les piles de l'espace utilisateur sont soit explicitement créées / fournies par le mécanisme utilisé pour créer un thread (fonctions comme makecontext()
ou pthread_create()
permettent à l'appelant de spécifier une région mémoire à utiliser pour la pile du thread "enfant"), ou héritée (par clonage de mémoire à l'accès, généralement appelé "copie en écriture" / COW, lors de la création d'un nouveau processus).
Cela dit,(état, parmi lesquels se trouve le pointeur de pile du thread). Il y a plusieurs façons pour cela: signaux UNIX, setcontext()
, pthread_yield()
/ pthread_cancel()
... - mais cela est disgressing un peu de la question initiale.