Systèmes d'exploitation : Trois pièces faciles. Partie 3 : API de Processus (traduction)

Introduction aux systèmes d'exploitation

Bonjour, Habr ! Je souhaite vous présenter une série d'articles traduits d'une littérature que je trouve intéressante — OSTEP. Ce matériel explore en profondeur le fonctionnement des systèmes d'exploitation de type Unix, en particulier — le travail avec les processus, les différents planificateurs, la mémoire et d'autres composants similaires qui forment un système d'exploitation moderne. Vous pouvez voir l'original de tous ces matériaux ici ici. Je vous demande de prendre en compte que la traduction a été réalisée de manière non professionnelle (assez libre), mais j'espère que le sens général a été conservé.

Les travaux pratiques sur ce sujet peuvent être trouvés ici :

Autres parties :

Vous pouvez également visiter ma chaîne sur Telegram =)

Attention ! il y a un labo pour cette leçon ! voir GitHub

API des processus

Considérons un exemple de création de processus dans un système UNIX. Cela se fait à travers deux appels systèmes fork() et exec().

Appel de fork()

Systèmes d'exploitation : Trois pièces faciles. Partie 3 : API de Processus (traduction)

Examinons un programme qui effectue un appel fork(). Le résultat de son exécution sera le suivant.

Systèmes d'exploitation : Trois pièces faciles. Partie 3 : API de Processus (traduction)

Tout d'abord, nous entrons dans la fonction main() et exécutons l'affichage d'une chaîne à l'écran. La chaîne contient l'identifiant de processus qui est appelé dans l'original PID ou identifiant de processus. Cet identifiant est utilisé dans UNIX pour faire référence à un processus. La commande suivante exécutera l'appel fork(). À ce moment, une copie presque exacte du processus est créée. Pour le système d'exploitation, il semble que deux copies du même programme sont en cours d'exécution, qui sortiront toutes deux de la fonction fork(). Le processus enfant nouvellement créé (par rapport à son processus parent) ne sera plus exécuté à partir de la fonction main(). Il convient de se rappeler que le processus enfant n'est pas une copie exacte du processus parent, en particulier il dispose de son propre espace d'adressage, de ses propres registres, de son propre pointeur vers les instructions exécutables, etc. Ainsi, la valeur retournée par l'appel de la fonction fork() sera différente. En particulier, le processus parent recevra comme retour la valeur PID du processus enfant, tandis que l'enfant recevra une valeur égale à 0. À partir de ces codes de retour, il est possible de séparer les processus et de faire en sorte que chacun exécute son propre travail. L'exécution de ce programme n'est pas strictement définie. Après la séparation en deux processus, le système d'exploitation commence à les surveiller et à planifier leur exécution. Dans le cas d'une exécution sur un processeur monocœur, un des processus poursuivra son travail, dans ce cas — le parent — puis le contrôle sera transféré au processus enfant. Lors d'un redémarrage, la situation peut être différente.

Appel wait()

Systèmes d'exploitation : Trois pièces faciles. Partie 3 : API de Processus (traduction)

Considérons le programme suivant. Dans ce programme, grâce à l'appel wait() le processus parent attendra toujours la fin du processus enfant. Dans ce cas, nous obtiendrons une sortie de texte strictement définie à l'écran.

Systèmes d'exploitation : Trois pièces faciles. Partie 3 : API de Processus (traduction)

Appel exec()

Systèmes d'exploitation : Trois pièces faciles. Partie 3 : API de Processus (traduction)

Considérons l'appel exec(). Cet appel système est utile lorsque nous souhaitons exécuter un programme complètement différent. Ici, nous allons appeler execvp() pour lancer le programme wc, qui est un programme de comptage de mots. Que se passe-t-il lors de l'appel d'exec()? Cette fonction reçoit en arguments le nom du fichier exécutable et quelques paramètres. Ensuite, le code et les données statiques de ce fichier exécutable sont chargés et le segment de code actuel est écrasé. Les autres zones de mémoire, telles que la pile et le tas, sont réinitialisées. Ensuite, le système d'exploitation exécute simplement le programme, lui passant un ensemble d'arguments. Ainsi, nous n'avons pas créé un nouveau processus, nous avons simplement transformé le programme actuellement en cours d'exécution en un autre programme en cours d'exécution. Après l'appel d'exec() dans l'enfant, il semble que le programme initial n'ait en fait jamais été lancé.

Cette complexité dans le lancement est tout à fait normale pour le shell Unix, et permet à ce shell d'exécuter du code après l'appel fork(), mais avant l'appel exec(). Un exemple de ce type de code pourrait être l'ajustement de l'environnement du shell en fonction des besoins du programme à exécuter avant son lancement immédiat.

Shell — c'est simplement un programme utilisateur. Il vous affiche une ligne d'invite et attend que vous y saisissiez quelque chose. Dans la plupart des cas, si vous y saisissez le nom d'un programme, le shell trouvera son emplacement, appellera la méthode fork(), puis, pour créer un nouveau processus, appellera l'un des types d'exec() et attendra son exécution via l'appel wait(). Lorsque le processus enfant se termine, le shell revient de l'appel wait() et affiche à nouveau la ligne d'invite, attendant la saisie de la prochaine commande.

La séparation de fork() & exec() permet au shell de faire les choses suivantes, par exemple :
wc file > new_file.

Dans cet exemple, la sortie du programme wc est redirigée vers un fichier. La façon dont le shell y parvient est assez simple : lors de la création du processus enfant avant l'appel de exec(), le shell ferme le flux de sortie standard et ouvre le fichier new_file, ainsi, toute la sortie du programme lancé par la suite wc sera redirigée vers le fichier au lieu de l'écran.

Le pipe Unix est réalisé de manière similaire, sauf qu'il utilise l'appel pipe(). Dans ce cas, le flux de sortie d'un processus sera connecté à une queue de pipe, située dans le noyau, à laquelle sera également connecté le flux d'entrée d'un autre processus.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster