- Quelle est la différence entre la pile noyau et la pile utilisateur ?
En bref, rien - à part utiliser un emplacement différent en mémoire (et donc une valeur différente pour le registre du pointeur de pile), et généralement des protections d'accès à la mémoire différentes. C'est à dire. 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é 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 utilise-t-on [une pile de noyau distincte] ?
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 en avoir une valide. Le noyau ne peut donc pas faire confiance le pointeur de pile de l'espace utilisateur n'est ni valide ni utilisable, et nécessitera donc un ensemble sous son propre contrôle. Différentes architectures de processeur implémentent cela de différentes manières; Les processeurs x86 changent automatiquement les pointeurs de pile lorsque des changements 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 (le noyau Linux, c'est-à-dire) ne fait pas raccorder les ISR directement aux portes d'interruption de l'architecture x86 mais délègue à la place la répartition des interruptions à 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 ou les gestionnaires enregistrés. Le processeur lui-même lors de l'envoi d'une interruption peut exécuter un commutateur de privilèges et/ou de pile, et ceci est utilisé/configuré par le noyau afin 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 à) utiliser la pile du noyau en place à ce stade. Cela peut, si les gestionnaires d'interruption ont des chemins d'appel profondément imbriqués, conduire à 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 étant interrompu par le code réseau avec iptables actif est connu pour déclencher de tels noyaux anciens non réglés ... la solution consiste à 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 (pour 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 s'en préoccuper. Au fur et à mesure que les threads sont créés (et chaque processus doit avoir au moins un thread), le noyau crée des piles de noyau pour eux, tandis que les piles d'espace utilisateur sont 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é (par clonage de mémoire sur accès, généralement appelé "copie sur écriture" / COW, lors de la création d'un nouveau processus).
Cela dit, le processus peut influencer la planification de ses threads et/ou influencer le contexte (é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 s'écarte un peu de la question initiale.
Ma réponse est collectée à partir d'autres questions SO avec mes affaires.
What's the difference between kernel stack and user stack?
En tant que programmeur du noyau, vous savez que le noyau doit être protégé contre les programmes utilisateur erronés. Supposons que vous gardiez la même pile pour le noyau et l'espace utilisateur, puis une simple erreur de segmentation dans l'application utilisateur plante le noyau et nécessite un redémarrage.
Il y a une "pile de noyau" par CPU comme ISR Stack et une "pile de noyau" par processus. Il existe une "pile utilisateur" pour chaque processus, bien que chaque thread ait sa propre pile, y compris les threads utilisateur et noyau.
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Why kernel stack is used?
Ainsi, lorsque nous sommes en mode noyau, un mécanisme de type pile est nécessaire pour traiter les appels de fonction, les variables locales similaires à l'espace utilisateur.
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
If a local variable is declared in an ISR, where it will be stored?
Il sera stocké dans la pile ISR (IRQSTACKSIZE). L'ISR s'exécute sur une pile d'interruptions distincte uniquement si le matériel le prend en charge. Sinon, les trames de pile ISR sont poussées sur la pile du thread interrompu.
L'espace utilisateur ne sait pas et franchement ne se soucie pas de savoir si l'interruption est servie dans la pile du noyau du processus actuel ou dans une pile ISR séparée. Comme les interruptions arrivent par processeur, la pile ISR doit donc être par processeur.
Does each process has its own kernel stack ?
Oui. Chaque processus a sa propre pile de noyau.
Then how the process coordinates between both these stacks?
La réponse de @FrankH me semble géniale.