- Apprendre
- Informatique et numérique
- Informatique
- Systèmes d’exploitation : processus, mémoire et fichiers
- Processus et appels système
Processus et appels système
IntermédiaireUnité 1 sur 9 de la formation Formation : Systèmes d’exploitation : processus, mémoire et fichiers
Ce que tu vas apprendre
- Décris les principales fonctions du système d’exploitation ainsi que les étapes historiques et les idées de conception qui expliquent sa façon de partager et de protéger la machine.
- Décris les principales fonctions d’un système d’exploitationExplique comment le système d’exploitation transforme le matériel brut en ressources plus faciles à utiliser, partagées et protégées pour les programmes.
- Explique comment la multiprogrammation et le partage du temps ont façonné les systèmes d’exploitationSuis les étapes du traitement par lots à la multiprogrammation et au partage du temps, découvre pourquoi chacune a nécessité de nouvelles protections et compare les principales organisations possibles d’un noyau.
- Décris les principales fonctions d’un système d’exploitation
- Explique ce qu’est un processus, ce que le système d’exploitation enregistre sur chacun et comment les processus passent entre les états en cours d’exécution, prêt et bloqué.
- Explique ce qu’est un processus et quelles informations le système d’exploitation conserve à son sujetDistingue un programme d’un processus, décris l’état de la machine et l’espace d’adressage d’un processus, puis explique comment le système d’exploitation crée un processus et en assure le suivi.
- Suis les transitions d’état d’un processusUtilise les états en cours d’exécution, prêt et bloqué et leurs transitions pour suivre le partage d’un processeur entre processus, et reconnais les états supplémentaires signalés par les systèmes existants.
- Explique ce qu’est un processus et quelles informations le système d’exploitation conserve à son sujet
- Utilise l’API des processus Unix en C pour créer des processus fils, y exécuter de nouveaux programmes, récupérer leurs résultats, les terminer et combiner ces appels dans un interpréteur de commandes simple.
- Crée un processus fils avec forkAppelle fork, distingue le père du fils grâce à sa valeur de retour et prédis ce que chaque processus voit et affiche.
- Exécute un autre programme avec execRemplace le programme d’un processus avec exec, transmets correctement les arguments et explique pourquoi Unix sépare la création d’un processus du chargement d’un programme.
- Attends la fin des processus fils, lis leur code de sortie et termine des processusTermine des processus avec exit et des signaux, récupère le résultat d’un fils avec wait et waitpid, décode son état et évite que les processus zombies et orphelins posent problème.
- Construis un interpréteur de commandes simple avec fork, exec, wait et la redirectionCombine les appels de gestion des processus dans une boucle d’interpréteur qui exécute des commandes, redirige les entrées et les sorties, relie des commandes par des tubes et exécute des tâches en arrière-plan.
- Crée un processus fils avec fork
- Explique comment le matériel sépare le code noyau privilégié des programmes utilisateur et comment les programmes franchissent cette frontière de façon contrôlée grâce aux appels système, aux exceptions et aux interruptions.
- Distingue le mode utilisateur du mode noyauExplique ce que permet chaque mode du processeur, quelles opérations sont privilégiées et ce qui se produit lorsqu’un programme dépasse les droits de son mode.
- Explique le déroulement d’un appel système, étape par étapeSuis un appel système depuis la fonction d’enveloppe de bibliothèque jusqu’au noyau par le déroutement, puis au retour, et interprète sa valeur de retour et ses erreurs.
- Distingue les déroutements, les exceptions et les interruptionsClasse les événements qui font passer le processeur dans le noyau, explique le fonctionnement de la table des gestionnaires du noyau et prédis ce qui se produit après chaque type d’événement.
- Distingue le mode utilisateur du mode noyau
- 5Explique comment le système d’exploitation partage le processeur grâce à l’exécution directe limitéeExplique comment le système d’exploitation exécute les programmes directement sur le processeur à pleine vitesse tout en gardant le contrôle, et comment il attribue le processeur successivement aux processus.
- Explique l’exécution directe limitéeExplique les deux problèmes posés par l’exécution directe des programmes sur le processeur et comment le mode utilisateur, les déroutements et l’interruption d’horloge les résolvent, étape par étape, du démarrage à la terminaison du processus.
- Suis une commutation de contexte et estime son coûtSuis chaque étape du passage du processeur d’un processus à un autre, distingue une commutation de contexte d’un changement de mode et estime le temps processeur consommé par les commutations.
- Explique l’exécution directe limitée
Processus et appels système : cours
1Explique le rôle d’un système d’exploitation
Le système d’exploitation donne aux programmes ordinaires des moyens utiles de calculer, de stocker des données et d’utiliser des périphériques tout en partageant la machine en toute sécurité. Ses responsabilités expliquent pourquoi une application de bureau n’a pas besoin de son propre pilote de disque et pourquoi un programme défaillant ne devrait pas tout arrêter. Suis le passage des ordinateurs exécutant une seule tâche aux systèmes interactifs, puis compare la façon dont les différentes architectures de noyau répartissent le travail privilégié.
1.1 Décris les principales fonctions d’un système d’exploitation
Un navigateur, un compilateur et un lecteur de musique peuvent tous progresser sur un même ordinateur. Chacun a besoin de temps processeur, de mémoire et d’un accès aux périphériques. Le système d’exploitation fournit ces ressources par des services que les programmes peuvent utiliser sans contrôler toute la machine.
Fournir des ressources utiles aux programmes
La virtualisation transforme une ressource physique en une ressource virtuelle pratique. La virtualisation du processeur permet à de nombreux processus de se comporter comme si chacun avait son propre processeur. Le système d’exploitation exécute chacun pendant un certain temps et conserve son état entre ses tours. La virtualisation de la mémoire donne à chaque processus son propre espace d’adressage : les adresses que ses instructions peuvent utiliser.
Une abstraction masque des détails derrière une interface utile. Un fichier est une abstraction pour des octets stockés. Un programme peut appeler write sans savoir si ces octets vont vers un SSD ou un lecteur réseau. Un appel système fournit un moyen contrôlé de demander un service au noyau. Le travail propre au périphérique reste masqué derrière l’interface.
Partager les ressources et protéger les programmes
En tant que gestionnaire de ressources, le système d’exploitation décide qui obtient du temps processeur, de la mémoire et des services des périphériques. Il cherche à utiliser efficacement le matériel tout en donnant aux programmes un accès raisonnable. Le partage exige aussi une protection : un programme ne doit pas écraser la mémoire privée d’un autre ni désactiver l’horloge pour garder le processeur.
Le matériel aide à faire respecter cette frontière. Les instructions des applications s’exécutent en mode utilisateur avec des droits limités. Le code noyau s’exécute avec les privilèges nécessaires pour gérer la machine. Une horloge peut interrompre un programme même si celui-ci ne demande jamais rien au système d’exploitation.
Pour un ordinateur portable qui télécharge un fichier tout en compilant du code, suis trois tâches distinctes :
- Le périphérique réseau signale l’arrivée de données. Le noyau les met à la disposition du processus de téléchargement.
- Le système d’exploitation partage le temps processeur entre le navigateur, le compilateur et les autres processus prêts.
- Le compilateur demande des opérations sur des fichiers pour stocker sa sortie. Son code ne pilote pas directement le contrôleur de stockage.
Séparer le noyau de l’interface
Le noyau est le cœur privilégié. L’interpréteur de commandes, l’environnement graphique et la plupart des bibliothèques système s’exécutent comme des programmes ordinaires, même lorsqu’ils sont distribués avec le système d’exploitation. Fermer une fenêtre du bureau ne supprime pas le noyau. Un serveur sans interface graphique a toujours besoin de gestion des processus, de protection mémoire et de services pour les périphériques.
Sur un processeur logique, le code utilisateur et le code noyau s’exécutent à tour de rôle. Pendant que le compilateur exécute des instructions utilisateur ordinaires, le noyau ne s’exécute pas en même temps sur ce processeur. Les appels système, les exceptions et les interruptions matérielles lui rendent le contrôle.
Choisir comment faire, puis à qui attribuer
Un mécanisme fournit une opération ; une politique choisit comment l’utiliser. Sauvegarder les registres d’un processus et restaurer ceux d’un autre est un mécanisme. Choisir quel processus prêt obtient le prochain tour relève d’une politique. Cette séparation permet au système d’exploitation de changer ses choix d’ordonnancement sans remplacer le mécanisme de commutation.
La conception d’un système d’exploitation concilie des abstractions utiles, les performances, la protection, la fiabilité, la sécurité et la consommation d’énergie. Le temps processeur et la mémoire supplémentaires consacrés à la gestion constituent un surcoût. Dans tout le domaine, trois thèmes reviennent : la virtualisation, la concurrence (des activités en cours pendant une même période) et la persistance, qui conserve les données stockées au-delà de la durée de vie d’un programme ou d’une coupure de courant.
Points clés
- La virtualisation donne aux programmes des vues pratiques du matériel partagé.
- Les abstractions comme les fichiers masquent les détails des périphériques derrière des opérations utiles.
- Le noyau est privilégié ; l’interpréteur de commandes et l’environnement graphique sont des programmes ordinaires.
- Un mécanisme fournit une opération ; une politique choisit quand ou pour qui l’utiliser.
- La protection et un faible surcoût sont deux objectifs de la conception d’un système d’exploitation.
1.2 Explique comment la multiprogrammation et le partage du temps ont façonné les systèmes d’exploitation
Les systèmes d’exploitation ont évolué lorsque les ordinateurs sont passés de l’exécution de tâches isolées à la prise en charge de nombreuses activités à la fois. Chaque changement a résolu un problème pratique : matériel inactif, interaction lente ou propagation des défaillances entre programmes.
Des lots au recouvrement des tâches
Dans le traitement par lots, les tâches soumises s’exécutent les unes après les autres sans interaction avec la personne qui les a soumises. Les premiers logiciels d’assistance aidaient surtout à charger les tâches et à effectuer les opérations courantes d’entrée-sortie. Si la tâche en cours devait attendre un périphérique, le processeur pouvait rester inactif.
La multiprogrammation maintient plusieurs tâches en mémoire. Lorsque l’une se bloque en attendant une entrée-sortie, une autre peut effectuer des calculs. Supposons qu’une tâche calcule de façon répétée pendant 20 ms puis attende une entrée-sortie disque pendant 80 ms. Seule, son taux d’utilisation du processeur est de 20 / 100 = 20 %. Avec deux tâches de ce type et un recouvrement adapté, les calculs utiles peuvent occuper 40 % du temps écoulé. L’attente du périphérique n’a pas raccourci ; les calculs occupent du temps processeur qui aurait autrement été perdu.
Le gain dépend de la présence de tâches prêtes. Ajouter des tâches ne peut pas porter le taux d’utilisation du processeur au-delà de 100 %, et les tâches qui attendent le même périphérique peuvent toujours se heurter à un goulet d’étranglement. Plusieurs tâches en mémoire nécessitent aussi une protection : l’une ne doit pas écraser une autre ni endommager les données propres au système d’exploitation.
Rendre l’interaction réactive
Le partage du temps donne aux processus de courts tours sur le processeur. Un terminal ou un environnement graphique peut répondre pendant que d’autres programmes continuent leur travail. Attendre la fin d’une tâche par lots avant de traiter la frappe d’un autre utilisateur donnerait une impression très différente.
| Méthode de partage | Ce qui est divisé | Exemple |
|---|---|---|
| Partage du temps | Utilisation d’une ressource pendant des intervalles successifs | Tours sur le processeur |
| Partage spatial | Capacité détenue simultanément par différents utilisateurs | Zones de mémoire ou espace disque |
La concurrence signifie que plusieurs activités sont en cours pendant une même période. Leurs instructions peuvent être entrelacées sur un processeur logique. Le parallélisme signifie que des instructions s’exécutent réellement en même temps sur différentes ressources de traitement. La multiprogrammation ne nécessite pas de matériel parallèle.
Placer les services dans le noyau ou à l’extérieur
| Architecture | Où s’exécutent la plupart des services | Principal compromis |
|---|---|---|
| Noyau monolithique | Les systèmes de fichiers, les pilotes et les fonctions réseau s’exécutent en mode noyau | Les appels directs sont efficaces ; un bogue dans un pilote peut endommager le noyau |
| Micronoyau | Un petit cœur privilégié prend en charge des processus de service en mode utilisateur | L’isolation des services aide à contenir les défaillances ; la communication ajoute du travail |
| Noyau hybride | Combine des éléments des deux approches | La frontière exacte des services dépend de l’architecture |
Linux est monolithique et peut charger des modules noyau. MINIX 3, QNX et seL4 illustrent les architectures à micronoyau. Windows NT et XNU d’Apple sont généralement décrits comme des architectures hybrides. Un pilote en mode utilisateur peut souvent être redémarré après une panne, tandis qu’un pilote privilégié dispose d’un accès tel que sa défaillance peut toucher tout le système.
Les premiers systèmes pour ordinateurs personnels, comme MS-DOS et le Mac OS classique, ne disposaient pas de la protection de la mémoire des processus attendue aujourd’hui. Les systèmes modernes combinent les règles du système d’exploitation et leur application par le matériel. De courts tours sur le processeur ne suffiraient pas à empêcher un programme de modifier la mémoire d’un autre ; le partage et la protection résolvent des aspects différents du problème.
Points clés
- La multiprogrammation occupe le temps d’attente des entrées-sorties avec les calculs d’une autre tâche.
- Le partage du temps permet une utilisation interactive grâce à de courts tours sur le processeur.
- Des travaux concurrents peuvent être entrelacés sur un processeur ; des travaux parallèles s’exécutent simultanément.
- Le partage du temps divise les tours ; le partage spatial divise la capacité.
- L’organisation du noyau établit un compromis entre appels directs des services et isolation renforcée des services.
- Plusieurs tâches résidentes nécessitent une protection de la mémoire et des privilèges.
2Décris les processus et les états par lesquels ils passent
Un fichier programme n’est que le point de départ. Pour l’exécuter, le système d’exploitation construit et suit un processus actif doté d’une mémoire, de registres, de descripteurs ouverts et d’une place dans la liste des processus. Apprends à lire cet état, puis suis deux processus pendant que les calculs sur le processeur recouvrent les attentes des périphériques. La différence entre attendre un processeur et attendre un événement explique quel processus l’ordonnanceur peut choisir.
2.1 Explique ce qu’est un processus et quelles informations le système d’exploitation conserve à son sujet
Un exécutable sur disque peut être lancé plusieurs fois. Chaque lancement a besoin de son propre état évolutif pour qu’une instance puisse être suspendue, reprendre ou échouer indépendamment des autres. Cette instance active est un processus.
Identifier l’instance en cours d’exécution
Un programme est constitué d’instructions et de données statiques stockées. Un processus combine un programme avec sa mémoire courante, ses registres du processeur et son état d’entrée-sortie. Trois interpréteurs de commandes peuvent exécuter le même fichier tout en gardant des variables, des répertoires courants et des historiques différents.
Le compteur ordinal (PC) indique la prochaine instruction. Le pointeur de pile indique l’emplacement de la pile active. Les registres généraux contiennent des valeurs intermédiaires. Lorsqu’un processus cesse de s’exécuter, une partie suffisante de son état doit être conservée pour qu’il puisse continuer à la bonne instruction avec les bonnes valeurs.
Lire le schéma de l’espace d’adressage
L’espace d’adressage d’un processus est la mémoire que ses instructions peuvent adresser. Dans une organisation pédagogique courante, le code et les données statiques se trouvent vers les adresses basses, le tas au-dessus et la pile vers les adresses hautes. Le tas accueille les objets alloués dynamiquement ; la pile prend en charge les appels de fonctions et l’état local. Dans cette organisation, le tas grandit vers les adresses hautes et la pile vers les adresses basses. Les organisations réelles dépendent du système et les implémentations de malloc peuvent obtenir de la mémoire de plusieurs façons.
Deux processus peuvent afficher la même adresse virtuelle pour une variable tout en y conservant des valeurs différentes. Les adresses virtuelles appartiennent à la vue qu’un processus a de la mémoire. Des numéros d’adresse identiques ne prouvent pas que le stockage accessible en écriture est partagé.
Démarrer un programme
Pour démarrer une nouvelle image de programme, le système d’exploitation met en place les éléments suivants :
- Son code exécutable et ses données, dont certaines parties sont chargées au besoin sur les systèmes modernes.
- Une pile utilisateur initiale et des informations de démarrage, notamment les chaînes d’arguments et le vecteur d’arguments utilisés par l’environnement d’exécution pour appeler
main. - De la mémoire pour l’allocation dynamique et l’état initial des registres.
- Un environnement d’entrée-sortie, notamment les descripteurs de fichier hérités.
- Un point d’entrée où commence le code de démarrage du programme.
Sous Unix, les descripteurs de fichier sont de petits entiers qui désignent des ressources d’entrée-sortie ouvertes. Par convention dans l’interpréteur de commandes, 0 est l’entrée standard, 1 la sortie standard et 2 l’erreur standard. Ils sont souvent reliés à un terminal. Un processus peut hériter de descripteurs supplémentaires ; les trois numéros habituels ne constituent ni une limite ni une garantie qu’ils sont toujours ouverts dans chaque processus.
Examiner l’enregistrement du noyau
Le bloc de contrôle de processus (PCB) enregistre les informations dont le noyau a besoin pour gérer un processus : PID, état, contexte d’exécution sauvegardé, informations mémoire, descripteurs ouverts, père, propriétaire, répertoire courant et données de comptabilisation. Linux utilise task_struct ; xv6 utilise struct proc. Une table ou une liste des processus organise ces enregistrements.
Pendant qu’un processus s’exécute, ses registres courants sont dans le processeur. À l’entrée dans le noyau, ses registres utilisateur sont sauvegardés sur sa pile noyau ; une commutation de contexte conserve aussi le contexte d’exécution du noyau. Le PCB n’est pas un miroir constamment à jour de chaque registre utilisateur.
Par exemple, une sortie de ps sous Linux peut contenir 8240 8200 S bash et 8291 8240 R ps. Le second processus a le PID 8291 et le PID de son père est 8240 : il est donc le fils de l’interpréteur de commandes. R couvre les processus en cours d’exécution et les processus prêts. Un PID identifie un processus actif dans son espace de noms PID, mais après le nettoyage, ce numéro peut être réutilisé.
Points clés
- Un processus est une instance de programme avec un état de mémoire, de registres et d’entrée-sortie.
- Des adresses virtuelles identiques dans différents processus peuvent désigner des données différentes.
- Le PCB contient l’enregistrement de gestion du noyau, pas les registres courants du processeur mis à jour en permanence.
- Les descripteurs de fichier sont hérités ; 0, 1 et 2 ont des rôles définis par convention.
- Les PID peuvent être réutilisés après la terminaison d’un processus et le nettoyage de ses ressources.
2.2 Suis les transitions d’état d’un processus
Un processus peut exister sans exécuter d’instruction à un instant donné. Son état indique au système d’exploitation s’il peut utiliser un processeur ou s’il doit d’abord attendre autre chose. Cette distinction explique pourquoi un ordinateur occupé peut avoir de nombreux processus, mais seulement quelques-uns en cours d’exécution à un instant donné.
Déterminer ce dont le processus a besoin
| État | Signification | Exemple |
|---|---|---|
| En cours d’exécution | Exécute des instructions sur un processeur | Un compilateur qui génère des instructions |
| Prêt | Peut s’exécuter, attend du temps processeur | Un calcul dont le tour vient de se terminer |
| Bloqué | Attend un événement avant de pouvoir continuer | Une lecture sur le terminal qui attend une saisie |
Un processus bloqué ne consomme aucun temps processeur tant qu’il est bloqué. Son périphérique ou l’événement attendu peut néanmoins progresser. Un processus prêt possède déjà tout ce dont il a besoin, sauf un processeur.
Les transitions de base sont prêt → en cours d’exécution lorsqu’il est sélectionné, en cours d’exécution → prêt lorsqu’il est retiré du processeur, en cours d’exécution → bloqué lorsqu’il doit attendre, et bloqué → prêt lorsque l’événement attendu se produit. La fin de l’événement rend un processus admissible à l’exécution ; elle ne lui donne pas immédiatement le processeur. Choisir parmi les processus admissibles est le rôle de l’ordonnanceur.
Suivre le recouvrement des tâches
Utilise un processeur logique et néglige le surcoût des commutations de contexte. Le processus A calcule pendant 2 ms, attend une entrée-sortie disque pendant 3 ms, puis calcule pendant 1 ms. Le processus B a besoin de 4 ms de temps processeur. A commence en premier.
| Intervalle | Processeur | État de A | État de B |
|---|---|---|---|
| 0–2 ms | A | En cours d’exécution | Prêt |
| 2–5 ms | B | Bloqué | En cours d’exécution |
| 5–6 ms | B | Prêt | En cours d’exécution |
| 6–7 ms | A | En cours d’exécution | Terminé |
À 2 ms, A lance l’entrée-sortie et se bloque. B calcule pendant que le disque travaille. À 5 ms, l’entrée-sortie de A se termine, mais le système d’exploitation laisse B terminer sa quatrième milliseconde de temps processeur avant d’exécuter A. C’est un choix de politique, pas une transition supplémentaire directement de l’état bloqué à l’état en cours d’exécution.
Le travail total du processeur est de 2 + 1 + 4 = 7 ms, et les deux processus terminent après 7 ms. Si A s’exécutait jusqu’à sa fin avant que B commence, le temps écoulé serait de 2 + 3 + 1 + 4 = 10 ms. Le taux d’utilisation du processeur serait de 7 / 10 = 70 %, car aucun autre travail n’occuperait le temps d’attente de l’entrée-sortie.
Lire les états sur un système réel
Sous Linux, ps regroupe les états en cours d’exécution et prêt sous R. Il affiche le sommeil interruptible sous S, le sommeil non interruptible, souvent lié aux entrées-sorties, sous D, un processus arrêté sous T et un processus terminé mais non récupéré sous Z. Un processus arrêté n’attend pas simplement la fin d’une entrée-sortie ordinaire. Un zombie a terminé son exécution et ne conserve que l’enregistrement nécessaire pour communiquer son résultat.
Un nouveau processus passe aussi par une phase de création avant d’être prêt. Sur un système doté de quatre processeurs logiques, au plus quatre processus à un seul fil d’exécution peuvent s’exécuter simultanément. Les files des processus prêts organisent les tâches admissibles ; les listes des processus bloqués suivent les événements qu’ils attendent. Une commutation de contexte conserve l’état d’exécution d’un processus et restaure celui d’un autre lorsque le système d’exploitation change le processus en cours d’exécution.
Points clés
- Prêt signifie attendre un processeur ; bloqué signifie attendre un événement.
- La fin d’une entrée-sortie fait passer un processus bloqué à l’état prêt.
- Recouvrir les attentes des périphériques par un travail utile du processeur peut raccourcir le temps total écoulé.
- Linux signale les états prêt et en cours d’exécution avec le même code,
R. - Un zombie est terminé mais n’a pas encore été récupéré.
- Le nombre de processeurs logiques limite l’exécution simultanée des processus à un seul fil d’exécution.
3Crée et contrôle des processus avec fork, exec et wait
L’interface des processus Unix sépare la création d’un fils, le remplacement de son programme et la récupération de son résultat. Suis ce que chaque appel modifie et ce qu’il conserve, notamment les variables privées et l’état partagé des fichiers ouverts. Assemble ensuite les appels pour obtenir le comportement d’un interpréteur de commandes : commandes au premier plan, redirection, enchaînements par tubes et tâches en arrière-plan. Chaque étape dépend de l’identification du processus qui l’exécute.
3.1 Crée un processus fils avec fork
fork() crée un processus fils à partir du père appelant. Les deux poursuivent leur exécution immédiatement après l’appel : un chemin du code source donne donc lieu à deux exécutions. La valeur de retour indique à chaque processus quel est son rôle.
Traiter les trois résultats
pid_t rc = fork();
if (rc < 0) {
perror("fork");
exit(1);
} else if (rc == 0) {
printf("child %ld\n", (long) getpid());
} else {
printf("parent of %ld\n", (long) rc);
}
Utilise <unistd.h> pour fork et getpid, <stdio.h> pour l’affichage et <stdlib.h> pour exit. En cas de succès, le père reçoit le PID positif du fils ; le fils reçoit 0. En cas d’échec, l’appelant reçoit -1, errno indique l’erreur et aucun fils n’est créé.
Si le père a le PID 5000 et le fils le PID 5001, le père affiche « parent of 5001 » et le fils affiche « child 5001 ». Rien ne garantit lequel des deux s’exécute en premier. getpid() renvoie le PID de l’appelant ; getppid() renvoie le PID de son père. Le fils ne redémarre pas main et ne répète pas les instructions précédant le fork.
Suivre la mémoire privée et les entrées-sorties partagées
Le père et le fils commencent avec des contenus de mémoire ordinaire identiques dans des espaces d’adressage distincts. Si x vaut 10 avant l’appel et que le fils donne la valeur 20 à sa copie, celle du père reste à 10. Même l’adresse affichée de x peut être identique : ces adresses virtuelles égales appartiennent aux espaces d’adressage de processus différents.
La copie sur écriture évite de copier immédiatement chaque page mémoire. Le père et le fils partagent initialement les pages physiques, protégées en écriture. Lorsque l’un écrit dans une page privée, le noyau crée une copie privée avant d’autoriser l’écriture. Cela conserve le comportement de mémoires distinctes tout en réduisant le coût lorsqu’un fils appelle rapidement exec.
Les descripteurs de fichier se comportent différemment. Leurs entrées copiées renvoient à la même description de fichier ouvert sous-jacente, qui comprend le déplacement courant dans le fichier. Les lectures séquentielles effectuées au moyen d’un descripteur hérité font avancer ce déplacement partagé. La table des descripteurs est copiée, mais l’état sous-jacent du fichier ouvert dans le noyau peut rester partagé.
Ne compter que les forks atteints par un processus
Si tous les appels réussissent, fork(); fork(); laisse quatre processus : les deux processus issus du premier appel exécutent le second. Une boucle de trois itérations atteinte par tous les processus laisse processus, dont l’original. Un fork situé dans une branche réservée au père est atteint par moins de processus : des doublements répétés ne décrivent alors plus l’ensemble du programme.
Vider volontairement le texte mis en tampon
printf peut laisser du texte dans un tampon de l’espace utilisateur. fork copie ce tampon avec le reste de la mémoire. Si la sortie est redirigée vers un flux entièrement mis en tampon, le texte affiché avant le fork peut être vidé par les deux processus lors de leur terminaison normale.
Avec printf("start\n"); fork();, le terminal habituel, dont la sortie est mise en tampon par ligne, vide la ligne avant le fork grâce au saut de ligne. Un fichier vers lequel la sortie est redirigée peut la conserver et en recevoir deux copies. fflush(stdout) avant fork() envoie une seule fois le texte en attente. Le doublon provient des données mises en tampon qui ont été copiées, et non d’une double exécution du printf précédent.
Points clés
fork()renvoie le PID du fils dans le père, 0 dans le fils ou -1 en cas d’échec.- En cas de succès, les deux processus poursuivent leur exécution juste après
fork(). - Les modifications de la mémoire privée ordinaire du fils ne changent pas les valeurs du père.
- Les descripteurs hérités peuvent partager une même description de fichier ouvert et un même déplacement.
- Le nombre de processus dépend de ceux qui atteignent chaque fork.
- Vide la sortie en attente avant un fork lorsque son affichage en double serait indésirable.
3.2 Exécute un autre programme avec exec
Un processus peut garder son identité tout en changeant le programme qu’il exécute. La famille exec effectue ce remplacement. La combiner avec fork permet à un père de continuer son travail pendant qu’un fils devient un autre programme.
Remplacer l’image, conserver le processus
Un exec réussi remplace l’ancien code, les données statiques, le tas et la pile. Le noyau prépare les arguments et l’état initial du nouveau programme, puis démarre son code de démarrage. Le point où l’ancien appel a été effectué n’existe plus : un exec réussi n’y revient donc jamais.
Le PID, le lien avec le père et le répertoire courant sont conservés. Les descripteurs ouverts le sont aussi, sauf ceux marqués pour la fermeture à l’exécution. Les signaux interceptés retrouvent leur comportement par défaut ; ceux qui sont ignorés restent généralement ignorés. Les identifiants restent habituellement les mêmes, mais les permissions set-user-ID ou set-group-ID d’un exécutable peuvent modifier les identifiants effectifs lorsque le système l’autorise.
| Opération | Nouveau processus ? | Effet principal |
|---|---|---|
fork() | Oui | Crée un fils avec un état d’exécution copié |
| Exec réussi | Non | Remplace l’image du programme du processus appelant |
Construire un vecteur d’arguments valide
Pour exécuter wc -l notes.txt, le fils peut utiliser :
char *args[] = {"wc", "-l", "notes.txt", NULL};
execvp(args[0], args);
perror("execvp");
_exit(127);
Les chaînes sont des arguments distincts, pas une seule ligne de commande combinée. Par convention, args[0] désigne le programme. Le NULL final est un pointeur qui marque la fin du tableau ; ce n’est pas la chaîne « NULL ». Sans marqueur de fin valide, l’appel peut lire au-delà du tableau.
Les lignes qui suivent execvp traitent l’échec. Si le programme est introuvable, exec renvoie -1 et définit errno, par exemple à ENOENT. _exit termine alors le fils sans vider les tampons de sortie C hérités. Revenir dans la boucle de l’interpréteur après un échec créerait accidentellement un second chemin d’exécution de l’interpréteur.
Lire le nom de la variante
Le v de execv signifie que les arguments arrivent sous forme de vecteur ; les variantes l reçoivent une liste. Une variante p cherche un nom de programme dans PATH. Une variante e fournit un environnement explicite. L’appel système sous-jacent de Linux est execve ; la bibliothèque fournit les variantes pratiques.
execvp("wc", args) cherche dans PATH. execv("wc", args) traite « wc » comme un chemin relatif dans le répertoire courant. Un chemin absolu comme /usr/bin/wc peut être utilisé là où cet exécutable est installé. Exec n’analyse pas la syntaxe de l’interpréteur de commandes : une chaîne > dans args est un simple argument, sauf si un programme l’interprète lui-même.
Utiliser le temps avant le remplacement
Dans l’exemple où le père a le PID 6000 et le fils le PID 6001, le fils devient wc mais conserve le PID 6001. Son père peut attendre ce PID. Avant exec, le fils peut rediriger des descripteurs, connecter un tube ou changer de répertoire ; le programme de remplacement hérite de l’environnement ainsi préparé.
Cette séparation est essentielle à l’interpréteur de commandes Unix. Sous Windows, CreateProcess combine la création et le chargement du programme, avec des paramètres qui configurent le nouveau processus. POSIX propose aussi posix_spawn pour combiner ces opérations.
Points clés
- Exec remplace une image de programme sans créer de processus ni changer son PID.
- En cas de succès, exec ne revient jamais ; les instructions suivantes traitent l’échec.
- Termine les vecteurs d’arguments par un pointeur
NULL. - Les variantes
pcherchent dansPATH; une variante qui n’accepte qu’un chemin ne le fait pas. - La configuration des descripteurs avant exec permet à un programme inchangé de participer à des redirections et à des tubes.
3.3 Attends la fin des processus fils, lis leur code de sortie et termine des processus
Un père doit savoir si un fils a terminé et comment il s’est terminé. La terminaison du processus et la récupération du résultat sont deux étapes distinctes : le fils se termine, puis son père récupère l’enregistrement restant dans le noyau.
Terminer un processus
Revenir de main ou appeler exit(status) met fin à l’exécution normale. exit vide les tampons de sortie C et exécute les fonctions de fin enregistrées. _exit(status) termine le processus sans ce nettoyage de bibliothèque, ce qui est utile après un exec échoué dans un fils créé par fork. Par convention, 0 indique une réussite et une valeur non nulle un échec.
Un signal peut aussi terminer un processus. SIGTERM demande sa terminaison et peut être traité ; SIGKILL ne peut être ni intercepté ni ignoré. SIGSTOP arrête l’exécution et ne peut pas non plus être intercepté ou ignoré ; SIGCONT reprend un processus arrêté. Un terminal envoie normalement SIGINT pour Ctrl-C et SIGTSTP pour Ctrl-Z à la tâche au premier plan. Un signal est une notification logicielle adressée à un processus, et non une interruption matérielle.
Attendre un résultat
wait(&status) attend un fils et renvoie son PID. waitpid(pid, &status, 0) sélectionne un PID positif correspondant à un fils particulier. Un fils terminé et non récupéré peut être récupéré immédiatement. Sinon, une attente bloquante ordinaire suspend le père jusqu’à ce qu’un résultat correspondant soit disponible.
Avec WNOHANG, waitpid renvoie 0 lorsque des fils correspondants existent mais qu’aucun résultat n’est prêt. Un résultat positif identifie le fils récupéré. Un résultat de -1 indique une erreur : ECHILD signifie qu’il ne reste aucun fils correspondant ; EINTR signifie qu’un gestionnaire de signal a interrompu l’attente.
Décoder l’état avant de l’utiliser
int status;
pid_t r;
do {
r = waitpid(child, &status, 0);
} while (r == -1 && errno == EINTR);
if (r == -1) {
perror("waitpid");
} else if (WIFEXITED(status)) {
printf("exit %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("signal %d\n", WTERMSIG(status));
}
Ce code utilise <sys/wait.h>, <errno.h> et <stdio.h>. L’état stocké encode la manière dont le processus s’est terminé ainsi qu’un résultat. WEXITSTATUS a un sens après un résultat vrai de WIFEXITED ; WTERMSIG s’utilise après WIFSIGNALED.
Seuls les huit bits de poids faible d’une valeur de sortie normale sont disponibles. exit(300) donne donc 44, tandis que exit(-1) donne 255. Sous Linux, exit(3) produit généralement l’état retourné par wait brut 768 ; afficher cet entier brut ne revient pas à décoder le code de sortie.
Récupérer les zombies et reconnaître les orphelins
Un processus zombie s’est terminé mais conserve son PID et son résultat jusqu’à ce qu’une attente les récupère. Il n’exécute aucun code : lui envoyer SIGKILL ne peut donc pas le supprimer. Un père qui s’exécute longtemps doit récupérer chacun de ses fils. Pour tous les récupérer, continue d’attendre après chaque PID positif, réessaie en cas de EINTR et arrête-toi sur ECHILD ; signale les autres erreurs.
Un processus orphelin a perdu son père et peut encore s’exécuter. Linux lui attribue comme nouveau père un processus récupérateur approprié ou le processus init de l’espace de noms, qui pourra récupérer son résultat plus tard. Les permissions ordinaires d’envoi de signaux dépendent des identités utilisateur et des privilèges. S’exécuter en tant que root accorde des permissions, mais pas une exécution en mode noyau.
Points clés
- Chaque attente réussie récupère le résultat d’un fils.
- Décode la terminaison normale et la terminaison par signal avec les macros d’état correspondantes.
WNOHANGrenvoie 0 lorsqu’un fils correspondant existe mais n’a pas de résultat prêt.- Réessaie une attente interrompue en cas de
EINTR;ECHILDsignifie qu’il ne reste aucun fils correspondant. - Un zombie s’est terminé ; un orphelin a perdu son père et peut encore s’exécuter.
SIGKILLetSIGSTOPne peuvent être ni interceptés ni ignorés.exitvide les tampons C ;_exitne le fait pas.
3.4 Construis un interpréteur de commandes simple avec fork, exec, wait et la redirection
Un interpréteur de commandes transforme le texte des commandes en création de processus, configuration de descripteurs et récupération de résultats. C’est un programme utilisateur ordinaire qui utilise les mêmes services protégés du système d’exploitation que les autres programmes.
Lancer une commande externe
Pour wc -l notes.txt, l’interpréteur construit le vecteur d’arguments et lance la commande. Les mots analysés forment un vecteur d’arguments args terminé par un pointeur nul :
pid_t child = fork();
if (child == -1) {
perror("fork");
} else if (child == 0) {
execvp(args[0], args);
perror("execvp");
_exit(127);
} else {
int status;
pid_t result;
do {
result = waitpid(child, &status, 0);
} while (result == -1 && errno == EINTR);
if (result == -1) perror("waitpid");
else if (WIFEXITED(status)) {
printf("exit %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("signal %d\n", WTERMSIG(status));
}
}
Ce code utilise <unistd.h>, <sys/wait.h>, <errno.h> et <stdio.h>. L’interpréteur qui l’entoure lit et analyse chaque commande, exécute cette procédure de lancement, puis affiche l’invite suivante.
Seul le fils remplace son programme ; l’interpréteur peut récupérer le plantage d’une commande comme résultat de terminaison. Les commandes internes comme cd doivent modifier l’état propre de l’interpréteur : changer le répertoire d’un fils laisserait celui de l’interpréteur père inchangé.
Rediriger un descripteur avant exec
Pour ls -l > out.txt, le fils ouvre la destination en écriture, en la créant ou en la tronquant. Il fait ensuite en sorte que la sortie standard désigne ce fichier :
int fd = open("out.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) { perror("open"); _exit(1); }
if (dup2(fd, STDOUT_FILENO) == -1) {
perror("dup2"); _exit(1);
}
if (fd != STDOUT_FILENO && close(fd) == -1) {
perror("close"); _exit(1);
}
open nécessite <fcntl.h> ; les appels sur les descripteurs et _exit utilisent <unistd.h>. Le mode de création est filtré par le masque de création de fichiers du processus. La vérification fd != STDOUT_FILENO garde le descripteur 1 ouvert même si open lui-même a renvoyé 1. Après une configuration réussie, exec conserve le descripteur 1 et ls écrit normalement sans connaître la redirection.
Une approche plus ancienne ferme le descripteur 1 avant d’ouvrir le fichier : open renvoie le plus petit descripteur inutilisé. dup2 indique explicitement la destination. La redirection de l’entrée relie de la même façon un fichier lisible au descripteur 0.
Relier deux commandes
Pour ls | wc -l, pipe(fds) crée une extrémité de lecture fds[0] et une extrémité d’écriture fds[1]. Le fils producteur relie l’extrémité d’écriture au descripteur 1. Le fils consommateur relie l’extrémité de lecture au descripteur 0. Après la duplication, chacun ferme les descripteurs d’origine du tube dont il n’a pas besoin. Le père ferme ses copies et attend les deux fils.
Crée les deux fils avant d’attendre l’un d’eux. Un producteur peut remplir le tube et se bloquer ; le lecteur doit exister pour le vider. Le lecteur n’atteint la fin de fichier que lorsque tous les descripteurs d’écriture sont fermés et que les données du tube mises en tampon ont été consommées. Une extrémité d’écriture inutilisée que le père garde ouverte peut faire attendre wc indéfiniment.
Garder l’invite disponible
Pour sleep 60 &, l’interpréteur lance le fils et présente l’invite suivante sans attendre immédiatement. Il utilise ensuite des attentes non bloquantes ou réagit à SIGCHLD pour récupérer les fils terminés.
Le code de sortie contrôle aussi les combinaisons de commandes. make && ./app ne lance la seconde commande qu’en cas de réussite ; make || echo failed ne lance la seconde qu’en cas d’échec. Ces décisions utilisent le résultat décodé, et non l’état retourné par wait brut et encodé.
Points clés
- Une commande externe s’exécute dans un fils ; une commande interne qui modifie l’état s’exécute dans l’interpréteur.
- La redirection modifie les descripteurs dans le fils avant exec.
- Un tube relie la sortie standard d’un producteur à l’entrée standard d’un consommateur.
- Lance les deux côtés avant d’attendre et ferme les extrémités inutilisées du tube.
- La fin de fichier nécessite que toutes les extrémités d’écriture du tube soient fermées et que les données mises en tampon soient consommées.
- L’exécution en arrière-plan reporte l’attente ; l’interpréteur doit quand même récupérer le fils plus tard.
4Explique le mode utilisateur, le mode noyau et les appels système
Les programmes utilisateur ont besoin des services du système d’exploitation sans prendre le contrôle de la machine. Les modes de privilège matériels créent cette frontière, et des voies d’entrée contrôlées permettent au noyau de répondre aux requêtes et aux événements. Suis un appel système à travers sa fonction d’enveloppe de bibliothèque et son gestionnaire dans le noyau, puis distingue les déroutements volontaires, les fautes d’instruction et les interruptions de périphériques par leurs causes et leurs conséquences possibles.
4.1 Distingue le mode utilisateur du mode noyau
Le noyau doit laisser les programmes calculer rapidement tout en bloquant les opérations qui pourraient prendre le contrôle de la machine. Le mode de privilège du processeur est la frontière matérielle qui rend les deux possibles.
Séparer les calculs du contrôle privilégié
En mode utilisateur, les instructions peuvent accéder à la mémoire autorisée du processus et effectuer des calculs ordinaires. Elles ne peuvent pas modifier librement la configuration matérielle qui protège les autres programmes. En mode noyau, aussi appelé mode superviseur ou privilégié, le système d’exploitation peut effectuer les opérations protégées nécessaires à la gestion de la machine.
Les opérations privilégiées comprennent la programmation de l’horloge, la désactivation des interruptions, l’installation de gestionnaires d’interruption, la modification des registres de contrôle de la traduction des adresses mémoire, le contrôle direct de périphériques protégés et l’arrêt du processeur. Si n’importe quelle application pouvait désactiver l’horloge, les courts tours sur le processeur dépendraient de sa coopération.
| Plateforme | Mode application | Mode noyau |
|---|---|---|
| x86-64 sous Linux ou Windows | Anneau 3 | Anneau 0 |
| AArch64 | EL0 | EL1 |
AArch64 fournit aussi EL2 pour les hyperviseurs et EL3 pour le micrologiciel sécurisé. Ces noms désignent des niveaux de privilège matériels, et non différents types de comptes utilisateur.
Entrer à une adresse contrôlée
Le code utilisateur ne peut pas augmenter ses propres privilèges ni choisir une adresse quelconque du noyau à exécuter. L’entrée se fait par un appel système, une exception provoquée par une instruction ou une interruption matérielle. Le processeur transfère le contrôle à un point d’entrée configuré par le système d’exploitation. Le code de retour du noyau restaure l’état utilisateur sauvegardé et abaisse le niveau de privilège pour reprendre le code de l’application.
Le noyau protège aussi ses données par des permissions mémoire. Un processus peut avoir des adresses du noyau dans son espace virtuel sans pour autant avoir la permission d’y accéder en mode utilisateur. Connaître une adresse ne donne pas accès aux octets qui s’y trouvent.
Considère une application Linux sur x86-64 qui exécute hlt, une instruction destinée à arrêter un processeur jusqu’à un événement. En mode utilisateur, l’instruction provoque une exception. Linux envoie normalement SIGSEGV, dont l’action par défaut termine ce processus. L’application n’arrête pas tout l’ordinateur ; la frontière de protection transforme la tentative d’opération privilégiée en un événement traité par le noyau.
Distinguer l’identité du mode
Un processus root ou administrateur reste un programme en mode utilisateur pendant l’exécution de ses propres instructions. Son identité utilisateur lui donne des permissions plus larges pour demander des services. Il entre toujours dans le noyau par des voies contrôlées et le noyau vérifie la requête.
Par exemple, un utilitaire de maintenance privilégié peut être autorisé à ouvrir un fichier protégé. L’utilitaire le demande par un appel système ; il ne devient pas du code noyau simplement parce que la requête est autorisée. À l’inverse, lorsque le code noyau traite un read d’un utilisateur ordinaire, il s’exécute en mode noyau même si l’appelant n’a pas d’identité administrative.
Sur un processeur logique, il s’agit d’une séquence : instructions utilisateur, entrée dans le noyau, travail du noyau, retour aux instructions utilisateur. Il ne s’agit pas de l’exécution simultanée d’un programme et d’une seconde tâche du système d’exploitation sur ce même processeur. Des processeurs logiques distincts peuvent exécuter du code dans différents modes au même instant.
Points clés
- Le mode utilisateur permet les calculs ordinaires tout en restreignant les opérations de contrôle de la machine.
- L’entrée dans le noyau utilise des points d’entrée configurés par le système d’exploitation.
- Root est une identité utilisateur ; le mode noyau est un état de privilège du processeur.
- Une instruction interdite en mode utilisateur déclenche une exception pour que le noyau puisse réagir.
4.2 Explique le déroulement d’un appel système, étape par étape
Un programme C semble souvent appeler une fonction ordinaire lorsqu’il a besoin d’un service du système d’exploitation. Sous la fonction d’enveloppe d’un appel système, une transition contrôlée du processeur permet au code noyau de vérifier et d’exécuter cette requête.
Distinguer un appel de bibliothèque d’une requête au noyau
La bibliothèque C implémente strlen dans l’espace utilisateur sans appel système. printf met les données en forme et peut les placer en tampon ; un write ultérieur transfère les octets par l’intermédiaire du noyau. Une fine fonction d’enveloppe read prépare les arguments selon la convention d’appel système de la plateforme et exécute l’instruction d’entrée.
POSIX décrit des interfaces pour les systèmes de type Unix. Linux implémente de nombreux services regroupés de façon générale en contrôle des processus, opérations sur les fichiers et les périphériques, information, communication et protection. Un numéro d’appel système sélectionne un service dans la table de répartition du noyau. Les numéros dépendent de la plateforme : Linux sur x86-64 utilise 1 pour write et 39 pour getpid ; sur AArch64, il utilise 64 pour write.
Suivre une requête d’écriture
Pour write(1, "hi\n", 3) sous Linux sur x86-64, suis la requête dans l’ordre :
- La fonction d’enveloppe place le numéro de service 1 dans
rax, le descripteur 1 dansrdi, l’adresse du tampon dansrsiet le nombre 3 dansrdx. syscallconserve l’adresse de retour et les indicateurs dans des registres, passe en mode noyau et saute au point d’entrée configuré. L’instruction ne change pas automatiquement de pile.- Le code d’entrée du noyau met en place la pile noyau du processus et sauvegarde le reste de l’état utilisateur.
- La répartition dans le noyau sélectionne
write; son implémentation vérifie le descripteur, l’accès au tampon utilisateur et la requête avant de transmettre les octets vers la ressource de sortie. - Si l’écriture réussit complètement, le résultat est de 3 octets. Le code de retour du noyau restaure l’état utilisateur et reprend la fonction d’enveloppe, qui revient à l’appelant.
Le descripteur 1 peut désigner un terminal, un fichier ou un tube. Le numéro seul n’identifie pas le périphérique de sortie. Une écriture réussie peut aussi renvoyer un nombre d’octets inférieur ; les appelants qui doivent transférer chaque octet suivent la quantité effectivement écrite.
Vérifier les erreurs à l’interface
Le noyau considère que les pointeurs utilisateur et les autres arguments ne sont pas fiables. Une demande de copie depuis un tampon inaccessible peut échouer avec EFAULT ; la copie contrôlée évite d’accorder à l’appelant un accès à la mémoire du noyau.
Sous Linux, une erreur du noyau est un code d’erreur négatif. La fonction d’enveloppe C habituelle renvoie -1 et définit errno. Par exemple, si open("missing.txt", O_RDONLY) échoue parce que le fichier n’existe pas, errno vaut ENOENT. perror("missing.txt") peut afficher « missing.txt: No such file or directory ». Examine errno après un échec signalé, et non comme test principal de réussite : un appel réussi n’est pas tenu d’effacer une erreur précédente.
Tenir compte du temps passé dans le noyau
Un appel qui peut se terminer immédiatement peut revenir au même processus. Une lecture bloquante sur le terminal peut au contraire faire passer ce processus à l’état bloqué et en laisser un autre s’exécuter. L’événement de saisie rend le lecteur prêt ; une fois ordonnancé, il termine la procédure de retour.
L’entrée dans le noyau ajoute du travail par rapport à un appel de fonction normal : sauvegarder l’état, changer de privilège, vérifier les arguments et restaurer l’exécution. La mise en tampon par la bibliothèque peut regrouper de petites sorties en moins d’écritures. Sous Linux, strace ls exécute ls tout en affichant ses appels système, leurs arguments et leurs résultats.
Points clés
- Une fonction de bibliothèque peut effectuer tout son travail dans l’espace utilisateur ou invoquer des appels système.
- Un numéro de service sélectionne une opération du noyau ; l’appelant ne choisit pas une adresse arbitraire du noyau.
- Le code noyau vérifie les descripteurs, les pointeurs et les autres arguments.
- Utilise la valeur de retour pour détecter un échec, puis examine
errno. - Un appel système bloquant peut provoquer une commutation de contexte ; l’entrée dans le noyau seule ne l’impose pas.
- Les numéros d’appel système et les conventions d’utilisation des registres dépendent du système d’exploitation et de l’architecture.
4.3 Distingue les déroutements, les exceptions et les interruptions
Une entrée dans le noyau peut correspondre à une demande de service, à un problème d’instruction ou à un événement de périphérique. Classer la cause t’aide à prévoir ce que fera le système d’exploitation et si la même instruction doit être exécutée de nouveau.
Déterminer la cause de l’événement
| Événement | Cause | Moment par rapport à l’instruction courante |
|---|---|---|
| Déroutement d’appel système | Le programme demande volontairement un service | Synchrone |
| Exception ou faute | L’instruction courante nécessite un traitement particulier | Synchrone |
| Interruption matérielle | Une horloge ou un périphérique signale un événement au processeur | Asynchrone |
Synchrone signifie lié à l’instruction en cours d’exécution. Cela ne signifie pas que les mêmes données provoquent exactement les mêmes fautes à chaque exécution. Un chargement peut provoquer une faute lorsque sa page est absente, puis réussir plus tard lorsque cette page est présente en mémoire. Asynchrone signifie que la cause de l’événement est indépendante de l’instruction courante, par exemple lorsqu’un disque termine un travail antérieur.
Les manuels des processeurs utilisent ces termes de différentes façons. Suis la cause : demande volontaire de service, événement provoqué par une instruction ou notification matérielle.
Transmettre au bon gestionnaire
Au démarrage, le système d’exploitation installe des adresses de gestionnaires protégées. Une table de déroutement ou d’interruption associe les types d’événements à des routines du noyau. Sur x86-64, la table des descripteurs d’interruption (IDT) sert aux interruptions et aux exceptions ; syscall utilise une adresse d’entrée dans un registre spécial du processeur. Seul le code privilégié peut configurer ces destinations.
Lors d’une interruption depuis le mode utilisateur, le matériel x86-64 sauvegarde un cadre de retour sur une pile noyau. Le code d’entrée sauvegarde des registres supplémentaires avant d’effectuer le travail. La voie syscall conserve son état de retour initial dans des registres et s’appuie sur le code d’entrée pour mettre en place la pile noyau. Considérer toutes les voies d’entrée comme des actions matérielles identiques masque une différence importante d’implémentation.
Choisir l’issue
Une page valide absente de la mémoire peut être chargée, après quoi l’instruction ayant provoqué la faute est exécutée de nouveau. Un accès à une mémoire que le processus ne peut pas utiliser conduit normalement Linux à envoyer SIGSEGV. Une exception n’est donc pas toujours fatale et ne demande pas toujours de sauter l’instruction courante.
Pour une véritable instruction entière idiv sur x86-64 avec un diviseur nul, le processeur déclenche une exception de division. Linux transmet normalement SIGFPE ; le message habituel mentionne les nombres à virgule flottante même pour cette instruction entière. La division entière sur AArch64 donne au contraire zéro pour un diviseur nul. En C, la division par zéro produit un comportement indéfini : un code C portable ne peut donc compter sur aucun de ces résultats matériels.
Lorsqu’une lecture sur disque se termine, le gestionnaire d’interruption enregistre sa fin et rend prêt le processus qui attendait. Ce processus peut s’exécuter plus tard. Une interruption d’horloge donne au système d’exploitation l’occasion de réexaminer quel processus utilise le processeur, mais le gestionnaire peut aussi revenir au même processus.
Distinguer un signal d’une interruption
Une interruption matérielle informe le processeur ; un signal informe un processus par l’intermédiaire du système d’exploitation. Une exception peut conduire le noyau à envoyer un signal, et un processus peut demander l’envoi d’un signal à un autre par kill. La fin normale d’une opération de périphérique donne lieu à une interruption sans impliquer d’erreur de programme.
Le code noyau doit aussi protéger les données partagées lorsque des événements se produisent. Il peut désactiver brièvement les interruptions sur un processeur et utiliser des verrous si nécessaire. De longues périodes pendant lesquelles les interruptions sont désactivées retardent le traitement des périphériques ; désactiver les seules interruptions locales n’empêche pas un autre processeur d’accéder aux données partagées.
Points clés
- Les déroutements et les exceptions proviennent de l’instruction courante ; les interruptions matérielles ont une cause externe.
- Une faute récupérable peut être corrigée et son instruction exécutée de nouveau.
- Les tables d’entrée protégées empêchent les programmes utilisateur de remplacer les gestionnaires du noyau.
- Un signal vise un processus ; une interruption matérielle est destinée à être traitée par le processeur.
- La fin d’une opération de périphérique rend prêt un processus bloqué, et une interruption d’horloge n’impose pas de changer de processus.
5Explique comment le système d’exploitation partage le processeur grâce à l’exécution directe limitée
La rapidité d’exécution et le contrôle du système d’exploitation doivent aller de pair. L’exécution directe limitée permet aux instructions ordinaires de s’exécuter sur le matériel pendant que les modes, les points d’entrée protégés et une horloge laissent le noyau aux commandes. Suis ce qui se produit lorsque le système d’exploitation revient au même processus et lorsqu’il en reprend un autre. L’état sauvegardé et les coûts de commutation expliquent comment de courts tours sur le processeur peuvent favoriser le travail interactif.
5.1 Explique l’exécution directe limitée
Exécuter chaque instruction d’une application dans un simulateur logiciel rendrait le partage du processeur coûteux. Laisser une application contrôler la machine sans limite rendrait le partage dangereux. L’exécution directe limitée utilise l’exécution matérielle ordinaire avec une voie protégée de retour vers le système d’exploitation.
Résoudre deux problèmes de contrôle différents
L’exécution directe signifie que les instructions ordinaires d’un processus s’exécutent sur le processeur lui-même. Le système d’exploitation n’examine et n’approuve pas chaque instruction arithmétique. Deux problèmes subsistent : restreindre les opérations qui pourraient endommager la machine et reprendre le contrôle lorsqu’un programme ne s’arrête pas volontairement.
Le mode utilisateur résout le problème des restrictions. Les déroutements d’appel système permettent à un programme de demander des services sans choisir un code privilégié arbitraire. Une horloge matérielle résout le problème du contrôle : elle peut interrompre une application qui n’effectue aucun appel. Ensemble, ces mécanismes permettent de virtualiser le processeur avec un faible surcoût.
Préparer le système avant l’exécution des applications
Au démarrage, le noyau configure les gestionnaires d’événements et initialise l’horloge. Ces opérations de configuration sont privilégiées. Les programmes utilisateur exécutés ensuite ne peuvent pas rediriger les gestionnaires ni désactiver l’horloge pour éviter de perdre leur tour.
Pour démarrer un processus, le système d’exploitation crée son enregistrement de gestion et son image mémoire, prépare les arguments de démarrage et une pile utilisateur, et établit les valeurs initiales des registres. Il prépare un contexte sauvegardé initial afin que le chemin normal de retour du noyau vers le mode utilisateur puisse démarrer le programme. Conceptuellement, le processus commence par revenir d’un déroutement qu’il n’a jamais effectué.
L’organisation détaillée du cadre sauvegardé dépend du processeur et du système d’exploitation. L’idée de conception utile est la réutilisation : le même mécanisme de restauration peut reprendre un processus suspendu ou en démarrer un nouvellement préparé.
Revenir volontairement dans le noyau
Pendant un appel système, le matériel conserve l’état de retour initial et transfère le contrôle. Le code d’entrée du noyau sauvegarde les registres supplémentaires sur la pile noyau du processus. Après avoir exécuté une requête non bloquante, le noyau restaure le processus et revient en mode utilisateur. Si la requête bloque, un autre processus prêt peut s’exécuter en premier.
Lorsque main revient, le traitement de fin de l’environnement d’exécution demande finalement au noyau de terminer le processus. Sa mémoire peut être libérée tandis que son enregistrement de terminaison reste présent jusqu’à ce qu’un père le récupère.
Revenir sans coopération
Un système coopératif dépend des programmes pour effectuer des appels, céder le processeur ou provoquer des exceptions. Une boucle infinie qui ne fait rien de tout cela peut monopoliser un processeur. Le Mac OS classique illustre cette faiblesse.
Une architecture non coopérative utilise une interruption d’horloge pour forcer l’entrée dans le noyau. Considère un modèle pédagogique avec un processeur logique et une horloge périodique réglée sur 4 ms. L’horloge produit 1 000 / 4 = 250 impulsions par seconde. Un processus utilisateur coincé dans while (1) { } est interrompu à la prochaine impulsion. Le noyau peut alors exécuter un autre processus prêt ; la boucle n’a pas besoin d’atteindre d’abord un appel système.
L’impulsion est une occasion d’agir, pas une obligation de changer de processus. L’ordonnanceur peut laisser le processus interrompu continuer. Le traitement de l’horloge et la restauration de l’état sauvegardé sont des mécanismes ; le choix de l’ordonnanceur relève d’une politique. Le temps de réponse réel dépend aussi du travail du noyau et du moment où les interruptions peuvent être traitées : la période de l’horloge ne garantit donc pas à elle seule le temps de réponse d’une application.
Points clés
- L’exécution directe limitée exécute directement les instructions utilisateur ordinaires avec des restrictions imposées par le matériel.
- Le mode utilisateur restreint les opérations ; les appels système fournissent des services privilégiés contrôlés.
- Une horloge permet au système d’exploitation de reprendre le contrôle sans coopération du code utilisateur.
- La configuration au démarrage protège les adresses des gestionnaires et les paramètres de l’horloge.
- Une impulsion d’horloge donne un choix à l’ordonnanceur ; elle n’impose pas de changer de processus.
5.2 Suis une commutation de contexte et estime son coût
L’entrée en mode noyau ne change pas nécessairement le processus en cours d’exécution. Une commutation de contexte se produit lorsque le noyau conserve l’état d’exécution d’un processus et reprend celui d’un autre. Cela exige à la fois la conservation de l’état utilisateur et un changement du contexte d’exécution propre au noyau.
Suivre la sortie de A et l’entrée de B
Pour une commutation déclenchée par l’horloge sur x86-64, suis les étapes :
- A exécute des instructions utilisateur. L’horloge l’interrompt.
- Le matériel passe en mode noyau et sauvegarde le cadre de retour d’interruption de A sur sa pile noyau. Le code d’entrée y sauvegarde les autres registres utilisateur de A.
- L’ordonnanceur choisit B. La routine de commutation sauvegarde le contexte d’exécution noyau de A et restaure le contexte noyau sauvegardé de B, y compris son pointeur de pile noyau.
- Le noyau passe au contexte d’espace d’adressage de B si nécessaire. Il s’exécute alors pour le compte de B en utilisant sa pile noyau.
- Le code de sortie du noyau restaure les registres utilisateur de B. L’instruction de retour restaure l’état de retour de B et passe en mode utilisateur. B reprend là où il s’était arrêté.
La première sauvegarde conserve l’exécution utilisateur interrompue de A. La seconde conserve le point où en était le noyau pendant le traitement de A. Il ne s’agit pas de deux copies complètes identiques du même ensemble de registres. Un PCB ou une structure de contexte associée et la pile noyau propre au processus fonctionnent ensemble pour conserver l’état.
Identifier l’événement et la décision
Un appel bloquant, la terminaison d’un processus ou une décision prise à la suite d’une interruption d’horloge peuvent entraîner une commutation. Une interruption de périphérique peut rendre prêt un autre processus, que l’ordonnancement peut alors sélectionner. Tout le mécanisme de commutation s’exécute dans le noyau ; une application ne sauvegarde pas ses propres registres pour se porter volontaire à l’interruption.
| Situation | Transition de mode ? | Changement de processus ? |
|---|---|---|
| Un service non bloquant revient à son appelant | Utilisateur → noyau → utilisateur | Non |
| L’horloge est traitée, le même processus reprend | Utilisateur → noyau → utilisateur | Non |
| A se bloque et B reprend | Entrée dans le noyau, puis chemin de retour de B | Oui |
Une commutation de contexte conserve l’état d’exécution nécessaire pour continuer. Le temps passe et le monde extérieur peut changer : les déplacements partagés dans les fichiers et les entrées externes ne sont pas figés pendant qu’un processus est suspendu.
Tenir compte des coûts directs et indirects
Le travail direct comprend l’exécution de l’ordonnanceur, la sauvegarde et la restauration des registres et la sélection d’un espace d’adressage. Les caches de traduction peuvent nécessiter une adaptation ; des traductions associées à un identifiant peuvent éviter de supprimer toutes les anciennes entrées. Des coûts indirects suivent lorsque B doit remplir à nouveau les caches du processeur ou les traductions d’adresses mises en cache que A a évincées. Le coût dépend du matériel et de la charge de travail : utilise donc des valeurs mesurées ou indiquées pour calculer le surcoût.
Supposons qu’une commutation, avec ses effets pertinents, coûte 5 µs et que les tours de calcul utile durent 10 ms. Convertis 10 ms en 10 000 µs. La part consacrée aux commutations est de 5 / (10 000 + 5), soit environ 0,05 %. Pour des tours utiles de 1 ms, elle est de 5 / 1 005, soit environ 0,50 % ; à 0,1 ms, elle est de 5 / 105, soit environ 4,8 %.
Le dénominateur comprend le travail utile et le temps de commutation pour un cycle répété. Un tour plus court peut multiplier les occasions d’effectuer du travail interactif, mais consacre une plus grande part aux commutations répétées. L’horloge et le code de commutation rendent possibles les tours courts ; la politique d’ordonnancement doit mettre ce coût en balance avec la réactivité.
Points clés
- L’entrée dans le noyau peut revenir au même processus sans commutation de contexte.
- La sauvegarde de l’état utilisateur à l’entrée et celle du contexte noyau pendant une commutation ont des rôles différents.
- La reprise de B nécessite sa pile noyau, ses registres sauvegardés et son contexte d’espace d’adressage.
- Les coûts de commutation comprennent les opérations directes de gestion et le remplissage ultérieur des caches ou des caches de traduction.
- La part du surcoût est le coût de commutation divisé par la somme de la durée du tour utile et du coût de commutation.
- Des tours plus courts augmentent la part consacrée aux commutations pour un coût fixe par commutation.
Processus et appels système : exemples
1Observe ce qu’apporte le système d’exploitation
12 étapes
- 1IntroductionCommence avec plusieurs programmes
Imagine un ordinateur portable qui compile un projet tout en jouant de la musique et en recevant des données réseau. Chaque application a besoin de temps processeur, de mémoire et d’entrées-sorties, mais aucune ne contrôle toute la machine.
Suis qui fournit ces ressources, comment plusieurs tâches progressent et où s’exécutent les services privilégiés. La question qui revient est concrète : quel travail l’application demande-t-elle et quel travail le système d’exploitation doit-il gérer ?
- 2ExplicationMasque les détails du périphérique
Le système d’exploitation fournit des abstractions : des interfaces utiles qui masquent les mécanismes de plus bas niveau. Un programme ouvre un fichier et lit des octets sans implémenter les commandes de chaque périphérique de stockage.
Un appel système demande un service au noyau par une interface contrôlée. Le noyau vérifie et effectue le travail protégé. L’application décide toujours des données qu’elle souhaite ; elle n’obtient pas la permission de piloter directement le périphérique.
- 3ExempleSuis le fichier de sortie d’un compilateur
Un compilateur produit les octets d’un exécutable et demande une écriture. Le noyau vérifie la ressource de sortie et prend en charge le stockage derrière l’interface de fichier.
En même temps, le système d’exploitation gère la mémoire du compilateur et partage le temps processeur avec le lecteur de musique. Une action, l’enregistrement d’un fichier, mobilise donc plusieurs responsabilités du système d’exploitation : l’abstraction, la gestion des ressources et la protection des autres programmes.
- 4Point cléDonne à chaque processus une machine utilisable
La virtualisation présente une ressource physique à travers une vue privée utile. Un processus peut progresser comme s’il avait son propre processeur, même si ses instructions s’exécutent à tour de rôle avec celles d’autres processus.
Sa vue de la mémoire est aussi privée : l’adresse qu’il utilise ne désigne pas nécessairement les mêmes octets physiques dans un autre processus. La virtualisation du processeur et de la mémoire donne aux programmes des modèles pratiques pendant que le système d’exploitation gère le matériel réellement partagé.
- 5DéfiLocalise la partie privilégiée
Un ordinateur n’a pas d’environnement graphique installé, mais il exécute des services, stocke des fichiers et partage le temps processeur. A-t-il perdu le cœur essentiel du système d’exploitation ? Explique.
---reveal---
Non. Le noyau gère toujours les processus, la mémoire et les services des périphériques. Un environnement graphique est un programme utilisateur construit au-dessus de ces services. Son absence change l’interface que voit une personne, mais ne supprime pas la nécessité du travail de gestion des ressources effectué par le noyau.
- 6ExplicationSépare l’opération du choix
Un mécanisme rend une action possible. Sauvegarder les registres d’un processus et restaurer ceux d’un autre fournit le mécanisme nécessaire à la commutation.
Une politique choisit comment l’utiliser, par exemple en décidant quel processus prêt obtient le prochain tour sur le processeur. La distinction compte lorsque l’architecture change : une nouvelle règle de choix peut réutiliser le même code de commutation fiable. Des mécanismes efficaces ne décident pas à eux seuls de ce qui est équitable.
- 7ExplicationOccupe un temps d’attente autrement inutilisé
Un système de traitement par lots peut laisser le processeur inactif pendant que sa tâche courante attend une entrée-sortie. La multiprogrammation garde d’autres tâches disponibles et en exécute une pendant cette attente.
La tâche en attente ne calcule pas et le périphérique n’est pas devenu plus rapide. Le gain vient du recouvrement de travaux indépendants : un processus attend pendant qu’un autre utilise le processeur. Plusieurs programmes résidents nécessitent aussi une protection pour que l’un ne puisse pas écraser la mémoire d’un autre.
- 8ExempleCalcule le gain d’utilisation
Une tâche calcule pendant 20 ms, puis attend une entrée-sortie pendant 80 ms. Seule, elle n’effectue que 20 ms de travail sur le processeur par cycle de 100 ms : le taux d’utilisation est de 20 %.
Avec une seconde tâche de ce type et un recouvrement adapté, 20 ms de calcul supplémentaires peuvent occuper un temps autrement inutilisé, ce qui donne jusqu’à 40 % dans cet exemple. L’amélioration utilise le temps d’attente de façon productive ; ajouter des tâches ne peut pas porter le taux d’utilisation du processeur au-delà de 100 %.
- 9LienDonne de courts tours au travail interactif
Le partage du temps donne aux processus de courts tours sur le processeur afin que le travail interactif n’ait pas à attendre la fin d’une tâche par lots entière. C’est de la concurrence même sur un processeur logique : plusieurs activités progressent par entrelacement.
Le parallélisme nécessite une exécution réellement simultanée sur des ressources de traitement distinctes. La capacité de la mémoire et celle du disque illustrent un autre partage, le partage spatial, dans lequel différents utilisateurs détiennent simultanément des portions distinctes.
- 10ExplicationChoisis la frontière des services
Un noyau monolithique, comme Linux, exécute la plupart des services ensemble avec des privilèges. Les appels directs sont efficaces, mais un pilote défaillant peut endommager l’état du noyau.
Un micronoyau, comme seL4, laisse davantage de services dans des processus utilisateur distincts. L’isolation peut contenir la défaillance d’un service, au prix de communications et de changements de mode. Windows NT et XNU mélangent les approches. La frontière détermine quelles défaillances peuvent se propager et quels services peuvent être redémarrés.
- 11DéfiRelie partage et protection
Un système à un processeur exécute plusieurs tâches et passe à une autre dès que l’une attend une entrée-sortie disque. Une proposition permettrait à chaque tâche d’écrire à n’importe quelle adresse mémoire. Explique le gain d’utilisation et le défaut de cette proposition.
---reveal---
La multiprogrammation occupe les attentes d’entrées-sorties avec les calculs d’une autre tâche. Des écritures sans restriction permettraient à une tâche d’en endommager une autre ou d’endommager le système d’exploitation. Le recouvrement des travaux améliore l’utilisation des ressources, mais le partage nécessite toujours une protection effective de la mémoire et des privilèges.
- 12RécapitulatifExamine une architecture en trois questions
Pour une architecture de système d’exploitation, demande-toi quelle ressource est partagée, quelle interface voit un programme et quelle frontière protège les autres travaux.
Ces questions relient la virtualisation du processeur aux tours des processus, les fichiers aux détails masqués des périphériques et l’organisation du noyau à l’isolation des défaillances. Les mécanismes effectuent les opérations protégées ; les politiques décident comment en répartir l’utilisation. La concurrence peut provenir de l’entrelacement sur un processeur.
2Suis un processus dans ses calculs et ses entrées-sorties
13 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionSuis une instance active
- 2ExplicationTransforme un fichier en processus
- 3ExplicationConserve la prochaine instruction
- 4ExempleLis une liste de processus
- 5DéfiInterprète des adresses égales
- 6ConseilConsidère les descripteurs comme des ressources héritées
- 7ExplicationDemande-toi ce qui manque
- 8ExempleCommence la chronologie
- 9ExempleTermine la chronologie
- 10DéfiChange le choix du processus prêt
- 11LienReconnais les noms d’états réels
- 12DéfiRelie les enregistrements à la capacité des processeurs
- 13RécapitulatifLis l’état comme une indication de possibilité d’exécution
3Construis une commande à partir d’appels de gestion des processus
23 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionDonne un rôle à chaque appel
- 2ExplicationDivise une exécution en deux
- 3ExempleSuis une valeur privée
- 4ExempleCompte selon la branche, pas les appels dans le code source
- 5DéfiCompte les chemins qui affichent du texte
- 6ConseilVérifie ce qui a été copié
- 7ExplicationRemplace le programme du fils
- 8ExempleTransmets des chaînes d’arguments distinctes
- 9DéfiPrédis le résultat d’un remplacement réussi
- 10Point cléUtilise l’intervalle avant exec
- 11ExplicationRécupère le résultat d’un fils
- 12ExempleDécode une terminaison normale
- 13ExplicationNe laisse aucun résultat non récupéré
- 14DéfiGère correctement une interruption
- 15ConseilChoisis une demande de terminaison
- 16ExplicationReviens à une invite au premier plan
- 17ExempleRedirige la sortie avant le remplacement
- 18DéfiConserve la destination de sortie
- 19ExempleRelie les deux extrémités du tube
- 20Point cléLance les processus avant d’attendre
- 21LienAssure le suivi des tâches en arrière-plan
- 22DéfiSuis un enchaînement par tube vide
- 23RécapitulatifSuis l’identité, l’image et le résultat
4Suis une requête à travers la frontière de privilège
15 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionDemande-toi pourquoi le noyau a été sollicité
- 2ExplicationLimite ce que les applications peuvent contrôler
- 3ExempleDistingue l’identité du privilège
- 4DéfiPrédis l’effet d’une instruction interdite
- 5ExplicationTrouve le véritable appel système
- 6ExemplePrépare une écriture
- 7ExempleEntre dans le noyau et vérifie
- 8ExempleInterprète le retour
- 9DéfiSuis une lecture bloquée
- 10ExplicationClasse selon la cause
- 11ExempleCorrige ou termine
- 12ConseilSitue les signaux au niveau des processus
- 13DéfiClasse la fin d’une opération de périphérique
- 14DéfiDistingue deux types d’entrée
- 15RécapitulatifSuis la cause, les vérifications et le résultat
5Garde le contrôle pendant l’exécution directe des programmes
15 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionConcilie vitesse et contrôle
- 2ExplicationRésous deux problèmes de contrôle
- 3ExemplePrépare la machine et le processus
- 4LienObserve la faiblesse de l’approche coopérative
- 5ExempleInterromps une boucle infinie
- 6DéfiIdentifie le mécanisme manquant
- 7ExplicationSauvegarde l’exécution utilisateur interrompue
- 8ExempleSauvegarde aussi l’exécution dans le noyau
- 9ExempleReviens par l’état sauvegardé de B
- 10DéfiRepère une transition de mode seule
- 11ExplicationCompte les coûts après une commutation
- 12ExempleConstruis le dénominateur du cycle complet
- 13DéfiEstime l’effet d’un changement de durée du tour
- 14DéfiRelie un appel bloqué à sa reprise
- 15RécapitulatifSuis le processus auquel appartient le chemin de retour
Processus et appels système : QCM
Série 1 : Crée, remplace et récupère un processus10 Questions Pratiques
Question 1 sur 10
Afficher la réponseMasquer la réponse
getpid() pour connaître son propre identifiant. Renvoyer le PID du fils dans les deux processus supprimerait la distinction de valeur de retour utilisée pour choisir le comportement du père et celui du fils.Question 2 sur 10
Tous les forks réussissent. Combien de processus atteignent puts("done") dans ce code ?
if (fork() == 0) {
fork();
}
puts("done");
Afficher la réponseMasquer la réponse
puts, soit trois au total. Compter deux appels dans le code source comme des doublements automatiques jusqu’à quatre ignore la branche qui exclut le père initial.Question 3 sur 10
Afficher la réponseMasquer la réponse
Question 4 sur 10
Afficher la réponseMasquer la réponse
Question 5 sur 10
/opt/course/bin/checker et PATH comprend /opt/course/bin. Aucun fichier nommé checker ne se trouve dans le répertoire courant. Pourquoi execv("checker", args) ne parvient-il pas à le trouver ?Afficher la réponseMasquer la réponse
execv utilise directement son argument de chemin : dans ce cas, « checker » désigne un fichier du répertoire courant. execvp chercherait dans la variable d’environnement PATH fournie. La forme avec un vecteur d’arguments n’implique pas de recherche dans PATH ; ce comportement est indiqué par la variante p.Question 6 sur 10
exit(515). Après une attente réussie et un test WIFEXITED vrai, que renvoie WEXITSTATUS ?Afficher la réponseMasquer la réponse
WEXITSTATUS. Renvoyer la valeur d’origine 515 ignorerait l’interface de résultat sur huit bits ; celle-ci ne stocke pas un entier C quelconque.Question 7 sur 10
waitpid(child, &status, WNOHANG) renvoie 0. Que s’est-il passé ?Afficher la réponseMasquer la réponse
WNOHANG, zéro signifie que le fils correspondant existe mais qu’aucun résultat demandé n’est disponible. L’appel revient immédiatement dans le père sans récupérer le fils. Ce n’est pas le code de sortie du fils : la valeur de retour de waitpid identifie un fils en cas de succès et un objet d’état distinct indique comment ce fils s’est terminé.Question 8 sur 10
SIGKILL, son entrée reste visible. Quelle action libère l’enregistrement conservé du résultat de ce fils ?Afficher la réponseMasquer la réponse
SIGKILL ne peut pas le terminer une seconde fois et le fils n’exécute plus d’instructions qui pourraient traiter un autre signal.Question 9 sur 10
Afficher la réponseMasquer la réponse
Question 10 sur 10
producer | consumer. Le producteur se termine, mais le consommateur attend indéfiniment après avoir lu tous les octets disponibles. L’interpréteur a fermé ses copies du tube ; le consommateur détient encore son descripteur d’origine hérité de l’extrémité d’écriture. Comment corriger le blocage ?Afficher la réponseMasquer la réponse
Série 2 : Ressources, processus et protection10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 3 : Suis l’entrée dans le noyau et les commutations du processeur10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
errno vaut ENOENT. Que doit en conclure l’appelant ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 4 : Suis le comportement des processus et le partage des ressources10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
Un processus à un seul fil d’exécution possède une variable privée x égale à 6. Tous les forks réussissent. Tous les processus atteignent puts. Combien de lignes contiennent « 9 » ?
pid_t p = fork();
if (p == 0) x += 3;
fork();
if (x == 9) puts("9");
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
execvp pour un programme qui n’existe pas. Son instruction suivante affiche une erreur. Pourquoi cette instruction peut-elle s’exécuter ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
errno égal à EINTR. Que doit faire le père pour continuer à récupérer ses fils ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
chdir uniquement dans un fils créé par fork pour implémenter cd, attend ce fils, puis lance une autre commande. Pourquoi la commande suivante démarre-t-elle dans l’ancien répertoire ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 5 : Diagnostique les interactions entre processus et noyau10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
waitpid, le résultat d’un fils satisfait WIFSIGNALED. Quelle macro donne le numéro du signal qui l’a terminé ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
SIGSEGV. Quelle séquence distingue les deux événements ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
dup2(fd, 0), ferme fd sans condition, puis exécute la commande avec exec. Pourquoi l’entrée standard de la commande peut-elle être fermée ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
Un programme possède une variable privée x égale à 2. Tous les forks réussissent. Combien de processus affichent « hit » ?
pid_t p = fork();
if (p > 0) {
x = 7;
fork();
}
if (x == 7) puts("hit");
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Tu bloques sur ton propre exercice ? Aide aux Devoirs
Mots-Clés
A
abstraction
anneau de protection
appel système
attente non bloquante
B
bloc de contrôle de processus (PCB)
C
changement de mode
code de sortie
commande interne
commutation de contexte
compteur ordinal
concurrence
contexte noyau
contrôle coopératif
copie sur écriture
D
défaut de page
déroutement (trap)
descripteur de fichier
description de fichier ouvert
E
errno
errno est un indicateur d’erreur de la bibliothèque C défini par de nombreuses interfaces en cas d’échec et examiné après que la valeur de retour a signalé une erreur.espace d’adressage
exception
exec
exécution directe limitée
É
état bloqué
état en cours d’exécution
état prêt
état retourné par wait
F
fermeture à l’exécution (close-on-exec)
fin de fichier
fonction d’enveloppe de bibliothèque
fork
I
identifiant de processus (PID)
instruction privilégiée
interpréteur de commandes
interruption d’horloge
interruption matérielle
M
mécanisme
micronoyau
mode noyau
mode utilisateur
multiprogrammation
N
niveau d’exception
noyau
noyau monolithique
numéro d’appel système
O
ordonnanceur
P
parallélisme
partage du temps
partage spatial
PATH
execvp recherchent les noms d’exécutables.pile noyau
pointeur de pile
politique
processus
processus fils
processus orphelin
processus père
processus zombie
programme
R
récupération
redirection
retour de déroutement
S
signal
surcoût
système d’exploitation
T
table des vecteurs de déroutement
tâche en arrière-plan
tampon de sortie
tampon de traduction (TLB)
taux d’utilisation du processeur
traitement par lots
tranche de temps
tube
V
vecteur d’arguments
virtualisation
À propos de cette unité
Crée ton propre Matériel d'Étude
Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.