Gestion De Processus sous UNIX
Unix est un système d'exploiration multi-tâche et multi-utilisateurs, ce qui veut dire d'une part que plusieurs individus peuvent accéder aux ressources de l'ordinateur en même temps et d'autre part que plusieurs programmes peuvent s'exécuter en même temps.
En même temps ? non, pas tout à fait ... En effet, de nous jours, la majorité des ordinateurs ne compte encore qu'un seul processeur, lequel n'est capable d'exécuter qu'une seule instruction à un instant précis. Si nous désirons lancer plusieurs programmes en même temps, (nous parlerons ici de processus), ces derniers accèderont chacun à leur tour aux ressources de la machine. Une telle politique est dite de time sharing (partage du temps).
Bien entendu, un tel système n'est pas simple à gérer. En effet, il faut prévoir un partage équitable des ressources entre les divers utilisateurs, de manière, par exemple, à favoriser les processus interactif (ceux qui communiquent et interagissent directement avec l'utilisateur, comme, par exemple, un éditeur de texte, ou un programme de dessin vectoriel) au détriment des programmes de calcul batch.
Certains programmes sont privilégiés dans leur accès aux ressources par rapport aux autres. Ce sont des programmes du système assurant son bon fonctionnement. Nous ne parlerons ici que de trois d'entre eux tout particulièrement importants :
Comme nous le verrons dans une prochaine section, tous les processus sont lancés par le même schéma de duplication / recouvrement. De ce fait, chaque processus a un père : le processus qui l'a lancé. Chaque processus ? pas tout à fait, il en est un qui déroge à la règle, tout simplement par ce qu'il est le premier à être lancé et qu'il sera également responsable de l'arrêt du système. Ce processus si particulier s'appelle init, comme il est le premier à apparaître sur le système, son PID est égal à 1.
Le tableau suivant résume les principales caractéristiques d'un processus Unix. Certaines d'entre elles peuvent manquer dans certaines versions un peu ésotériques d'Unix (SCO, par exemple), alors que d'autres versions en ajouteront.
PID | Identificateur numérique unique de chaque processus. Ils sont affectés par le système en ordre croissant. Lorsque l'on arrive en bout de plage, on recommence à 2 en prenant bien soin de ne pas réaffecter un numéro déjà présent | ||||||||||||||||||
PPID | PID du père du processus. Par défaut,
tous les processus ont un père. Il n'existe que 2 exceptions :
|
||||||||||||||||||
Mode d'exécution | Le mode d'exécution est représentatif de
l'état du processus, plusieurs modes sont possibles :
|
||||||||||||||||||
Taille mémoire | La taille mémoire d'un processus est
composée de 2 grands éléments : la taille statique et
la taille dynamique. La taille statique est liée à l'éxécutable au moment de son lancement, elle comprend : La taille dynamique est plus complexe à définir, toutefois, on peut énumérer les grandes composantes suivantes : Comme nous le verrons dans les exemples liés à la commande ps, BSD et System V ont des manières différentes de calculer la taille mémoire d'un processus. |
||||||||||||||||||
Priorité | Conditionne l'affectation de la CPU aux processus. | ||||||||||||||||||
Nice | L'utilisateur a la possibilité d'influencer la
priorité de l'un de ces processus gràce au nombre de nice. Qu'est
ce que cela signifie en clair ? Supposez que vous lanciez un gros
programme de calcul non interactif dont vous n'attendez pas le résultat
avant le lendemain. Plutôt que de lui accorder la priorité
normale, vous décidez d'être sympa avec les autres utilisateurs
(être nice en Rosbif) et vous lui donnez une priorité
inférieure gràce à l'ordre nice. Certains administrateurs système obligent leurs utilisateurs à déclarer nice tout processus de calcul nécessitant plus de n secondes pour s'exécuter afin de laisser la priorité aux utilisateurs effectuant du traitement de texte ou de la compilation. |
||||||||||||||||||
Temps CPU | Il y a trois «durées d'exécution
différentes pour un processus »
On peut considérer que la durée CPU totale est la somme de la durée utilisateur et de la durée système. |
||||||||||||||||||
Date de lancement | Spécifie la date de l'heure de lancement d'un processus. Bien que la commande who indique depuis combien de temps, le système est « debout », cette information peut être obtenue en regardant la date de lancement du processus init. | ||||||||||||||||||
Propriétaire et groupe |
Chacune de ces informations est donnée selon
deux modalités : réel et effectif. Ainsi, le
propriétaire réel est le nom de login de l'utilisateur qui a
lancé la commande. Idem pour son groupe. Le propriétaire effectif (respectivement, le groupe effectif) est identique au propriétaire réel (respectivement, le groupe réel), à moins que l'exécutable de la commande ne soit doté du flag setuid (respectivement setgid), auquel cas le propriétaire effectif (respectivement, le groupe effectif) devient le propriétaire (respectivement le groupe) du fichier exécutable. |
||||||||||||||||||
Répertoire de travail | Habituellement, le répertoire à partir duquel a été lancé la commande | ||||||||||||||||||
Terminal de contrôle | Indique le nom du répertoire à partir duquel a été lancée une commande. Aucun terminal n'est affecté à une commande lancée en mode asynchrone. De même, si vous avez lancé une commande en mode no hangup puis tué le terminal de lancement, cette information n'est pas disponible car sans intérêt. |
Cette commande fondamentale permet d'obtenir la majorité des informations sur les processus actifs sur le système ... à condition d'activer les bonnes options ! Par défaut, elle n'affiche que très peu d'informations relativement aux processus lancés sur le terminal courant, tout son interet réside dans les très nombreuses options dont elle dispose. Malheureusement, ces options varient énormément d'une version à l'autre.
Lorsque l'affichage long est activé, nous aurons, en particulier, les renseignements suivants :
-e | Tous les processus |
-f | Version longue, à combiner avec -l |
-l | Autre version longue, à combiner avec -f |
-u uid | nom | Affiche les processus de l'utilisateur spécifié, soit pat son identificateur numerique uid soit par son nom |
Question : Sous System V, il est bon de se faire une commande permettant de récupérer l'ensemble de ces processus, saurez vous la réaliser de manière simple ? (solution). Les options -f et -l permettent toutes les deux d'avoir un affichage long, en fait elles diffèrent principalement sur le format d'affichage du temps CPU. La combinaison des deux offre un affichage très complet.
Personnellement, c'est ma préférée :)
-a | Tous les processus attachés à un terminal de contrôle |
-u | Version longue |
-uw | Version très longue ! en particulier, la ligne de commande complète est fournie |
-x | Affiche les processus qui n'ont pas de terminal de contrôle |
Par rapport à la version System V, la version BSD offre, à mon avis, une meilleure présentation des choses.
Question : Saurez vous écrire, une commande permettant de lister tous vos processus ? si vous avez déjà répondu à cette question pour System V, cela ne devrait pas pous poser de problème particulier. (solution)
Les versions récentes d'AIX sont plutôt de type System V. Toutefois, les gens de chez IBM ont compris que la syntaxe BSD de la commande ps était préférable à la syntaxe System V. Aussi, ils ont équipé leur commande ps du double jeu d'options. Pour utiliser les options System V, il faut les préfixer d'un -alors que les options BDS s'utilisent nues. Attention à ne pas vous emmeler les baskets, en particulier avec l'option -u/u qui ne veut pas du tout dire la même chose dans les deux cas !
En outre, il ne faut pas se leurrer, même si AIX propose la syntaxe BSD, il n'en deumeure pas moins un système de type System V. Aussi, certaines informations fournies par BSD seul seront toujours absentes
Nous donnons ici un exemple d'utilisation de ps sur un ordinateur AIX en utilisant les 2 syntaxes. Ne perdez toutefois pas de vue que le ps BDS n'est qu'émulé par celui, natif sous AIX, de System V.
Commande : ps ux
USER | PID | %CPU | %MEM | SZ | RSS | TTY | STAT | STIME | TIME | COMMAND |
bruno | 20922 | 0.0 | 0.0 | 140 | 336 | pts/5 | A | 12:41:06 | 0:00 | -bin/csh |
bruno | 22492 | 0.0 | 0.0 | 140 | 240 | pts/4 | A | 12:43:06 | 0:00 | ps ux |
bruno | 24196 | 0.0 | 0.0 | 488 | 864 | - | A | 12:41:01 | 0:00 | /usr/bin/X11/aixi |
bruno | 28596 | 0.0 | 0.0 | 728 | 1004 | - | A | 12:41:05 | 0:00 | /usr/dt/bin/dtter |
bruno | 30062 | 0.0 | 0.0 | 556 | 916 | - | A | 12:41:00 | 0:00 | /usr/dt/bin/dtses |
bruno | 29872 | 0.4 | 0.0 | 1496 | 2292 | - | A | 12:41:02 | 0:01 | dtwm |
bruno | 29618 | 0.0 | 0.0 | 1072 | 1428 | - | A | 12:41:05 | 0:00 | /usr/bin/X11/xter |
bruno | 27320 | 0.0 | 0.0 | 140 | 344 | pts/4 | A | 12:41:06 | 0:00 | -sh |
bruno | 26786 | 0.0 | 0.0 | 368 | 824 | - | A | 12:41:01 | 0:00 | /usr/dt/bin/ttses |
bruno | 7130 | 41.7 | 0.0 | 28 | 36 | - | A | 2:43:00 | 0:00 | ./boucle |
Commande: ps -lf -u `whoami`
F | S | UID | PID | PPID | C | PRI | NI | ADDR | SZ | WCHAN | STIME | TTY | TIME | CMD |
200001 | A | bruno | 7024 | 27320 | 0 | 60 | 20 | 1f4fa | 368 | 15:04:58 | pts/4 | 0:00 | xterm | |
240001 | A | bruno | 20922 | 28596 | 0 | 60 | 20 | cacc | 156 | 5b4de44 | 12:41:06 | pts/5 | 0:00 | /bin/c |
200001 | A | bruno | 22136 | 27320 | 0 | 60 | 20 | 12471 | 340 | 15:05:16 | pts/4 | 0:00 | xterm | |
240001 | A | bruno | 24196 | 30062 | 0 | 60 | 20 | 17ede | 500 | 12:41:01 | - | 0:00 | /usr/bin | |
240001 | A | bruno | 25202 | 7024 | 1 | 60 | 20 | 5963 | 140 | 15:04:58 | pts/6 | 0:00 | -sh | |
200001 | A | bruno | 26320 | 25202 | 10 | 65 | 20 | 177bf | 180 | 15:05:53 | pts/6 | 0:00 | ps -lf - | |
240001 | A | bruno | 26786 | 1 | 0 | 60 | 20 | 1c535 | 380 | 12:41:01 | - | 0:00 | /usr/dt/ | |
240001 | A | bruno | 27320 | 29618 | 0 | 60 | 20 | d2ec | 156 | 5a88844 | 12:41:06 | pts/4 | 0:00 | -sh |
240001 | A | bruno | 27514 | 22136 | 0 | 60 | 20 | 10234 | 140 | 5afc444 | 15:05:17 | pts/8 | 0:00 | -sh |
200001 | A | bruno | 27786 | 27514 | 92 | 125 | 39 | 15156 | 28 | 15:05:32 | pts/8 | 0:20 | ./boucle | |
240001 | A | bruno | 28596 | 30062 | 0 | 60 | 20 | 7c6 | 744 | 12:41:05 | - | 0:00 | /usr/dt/ | |
240001 | A | bruno | 29618 | 30062 | 0 | 60 | 20 | 3ce7 | 1088 | 12:41:05 | - | 0:00 | /usr/bin | |
240401 | A | bruno | 29872 | 30062 | 0 | 60 | 20 | 1dddd | 1520 | 12:41:02 | - | 0:01 | dtwm | |
240001 | A | bruno | 30062 | 29262 | 0 | 60 | 20 | 1bbba | 568 | 12:41:00 | - | 0:00 | /usr/dt/ |
De toute évidence, les informations présentées dans les deux cas sont totalement différentes ! En outre, vous remarquerez que la gestion de la taille des processus n'est pas la même dans les deux cas. Donnons tout de suite quelques explications quand à certaines informations données par System V et non présentes sous BSD.
Permettez moi encore d'insister sur le fait que la présentation de ps en mode BSD précédente est soumis à caution car elle a été effectuée sur un système System V émulant BSD. Tous les administrateurs système chevronnés vous le diront, la commande ps de BSD est nettement supérieure à celle de System V.
Les processus étant reliés entre eux par des relations père / fils, il semble naturel de les représenter par une structure arborescente, aussi certains systèmes ont ils transposé cette organisation sous forme d'une arboresence de répertoires enracinée dans une partition spéciale (et en mémoire) nommée /proc.
A chaque niveau de l'arborescence, on retrouve des fichiers significatifs du processus courant ainsi que des sous répertoires représentatifs des processus fils.
Cette organisation est très intéressante car elle évite aux commandes orientées processus telles que ps ou top d'aller fourrer leurs sales pattes dans le /dev/kmem. Toutefois, elle ouvre des brêches de sécurité non négligeables.
A l'heure actuelle, le /proc est fourni par défaut sur certaines implémentations de Linux et en option pour Solaris.
A la suite de csh, tous les interpréteurs de commandes modernes ont proposé des mécanismes permettant à un utilisateur de gérer aisément les différents processus lancés depuis un même terminal de contrôle. Les mécanismes proposés vont permettre :
En guise de préliminaire, rappelons qu'une commande est dite au premier plan si elle reçoit les événements du clavier. Tant que le processus au premier plan n'est pas terminé, il est impossible d'en lancer un autre depuis le même terminal.
Par défaut, lorsque vous lancez un processus, il s'installe au premier plan, toutefois, il est possible de lancer une commande en arrière plan en la faisant suivre du symbole et commercial &.
Elle permet de connaître la liste et l'état des divers processus attachés à votre terminal. Utilisée avec l'option -l, elle vous fournira également le PID de chaque processus.
Chaque processus est associé à un numéro d'ordre. Il est possible d'utiliser ce numéro, précédé du signe % avec les autres commandes du job control, et même la commande kill. Le processus courant est repéré par la lettre +. Toute commande de job control exécutée sans argument lui est directement appliqué.
Lorsque l'on lance un nouveau processus en tâche de fond, ou que l'on stoppe le processus de premier plan avec ^Z, ce processus devient le nouveau processus courant. Sous certains systèmes, il est également nanti du numéro 1, les autres processus voyant leur numéro augmenter.
Cette commande permet de relancer un processus stoppé au premier plan ou bien de ramener au premier plan un processus s'exécutant en arrière plan.
Elle peut s'utiliser avec pour argument :
Elle permet de relancer en arrière plan un processus stoppé. Elle prend les mêmes arguments que son homologue fg.
La commande kill est souvent associée au job control car elle permet d'envoyer des signaux, c'est à dire des messages de commande aux processus. En outre, elle reconnaît la syntaxe %n permettant de spécifier un processus par son numéro d'ordre dans le job control.
L'exemple suivant est typique d'une session de travail avec le job control.
bipro: jobs -l [1] + 25908 Running ./boucle bipro: xterm & [1] 27692 bipro: jobs -l [1] + 27692 Running xterm [2] 25908 Running ./boucle bipro: fg %2 ./boucle ^Z Suspended bipro: jobs -l [1] - 27692 Running xterm [2] + 25908 Suspended ./boucle bipro: bg %2 [2] ./boucle & bipro: jobs -l [1] + 27692 Running xterm [2] 25908 Running ./boucle bipro: kill %2 bipro: [2] Terminated ./boucle
Etudions cas par cas ces différentes lignes ...
Il est intéressant de noter que le processus courant (dénoté par +) évolue tout au long de la séquence.
Question (très simple) : Au moment de lancer emacs, vous avez oublié de le mettre en tâche de fond (comme toute bonne commande X qui se respecte). Comment allez vous faire pour rectifier le tir ? (solution)
Il est souvent intéressant de vouloir lancer de manière asynchrone un ou plusieurs processus. Unix nous propose plusieurs commandes permettant de différer l'exécution d'un programme. Toutes partagent une caractéristique commune : le traitement de la sortie et de l'entrée standard.
En effet, ici se propose un problème majeur : puisque l'utilisateur ne sera pas derrière son écran pour surveiller son programme, que doit on faire de la sortie standard de son programme, et que se passe-t-il si le programme en question attend des données au clavier ?
Considérons pour commencer le cas de l'entrée standard. La réponse est simple : il faut faire très attention dès lors que l'on désire lancer de manière asynchrone un programme susceptible de poser une question au clavier. Deux grands cas peuvent se produire :
Pour ce qui est la sortie standard, le problème est moins grave. En effet, le fait que la sortie standard ne soit pas consultable directement n'agit pas directement sur le déroulement du processus.
Il faut bien noter qu'un mail sera généré même si la sortie standard est en fait vide ! Si vous ne souhaitez pas recevoir le fameux mail, il vous est possible de rediriger la sortie standard vers /dev/null.
Notons pour finir que les commandes de lancement asynchrone n'acceptent habituellement pas que la commande différée ne contienne de redirection (le shell aurait du mal à savoir à quelle commande est associée ladite redirection). Le plus simple consiste à créer un script minimaliste contenant la commande et ses redirection et passer ce dernier à la commande de lancement asynchrone.
Trois formes de lancement asynchrone vont être étudiées
C'est la plus simple des commandes de lancement asynchrone. En effet, elle permet d'exécuter son argument dès que la charge du système le permet. Le seuil de charge dépend du système, mais en général, aucune commande ne sera lancée tant que la charge de chaque processeur est supérieure à 1.
La commande at permet d'exécuter la commande passée en argument à la date et à l'heure spécifiés. Les options -l et -r permettent respectivement à un utilisateur de consulter la liste des commandes qu'il a mis en attente et d'en supprimer certaines.
Le démon cron est vital pour l'administrateur système car il permet de lancer des commandes à date et heure fixe et ce de façon répétitive. Par exemple, cela vous permet de lancer tous les soirs à 22h00 une commande de sauvegarde incrémentale par rapport à la veille et chaque dimanche matin à 10h20 (pendant auto moto :)) une sauvegarde complète.
Le démon cron est en fait très simple. A chacun de ces réveils, il consulte une table des processus à activer. Si la combinaison date/heure d'activation correspond avec la date/heure courante, le processus est exécuté. Notez bien que l'exécution du processus ne le retire absolument pas de la table ! et c'est précisément sur ce fait que repose l'exécution répétitive.
La commande crontab permet d'ajouter des processus dans la table du démon, de lister son contenu et d'en retirer certains processus. La syntaxe changeant énormément d'une version à l'autre, il est bon de consulter l'aide en ligne afin d'obtenir une confirmation directe.
La commande est la suivante :
La commande whoami permet de retrouver votre nom de login, donc il est naturel de passer son résultat à l'option -u de ps.
Cette commande, fort utile au demeurant, peut être mise en alias si vous utilisez Korn Shell ou Csh.
La commande est la suivante :
Elle est beaucoup plus simple que son homologue SystemV. Il convient toutefois de ne pas oublier le -x des processus non attachés à un terminal.
La séquence de commandes est très simple. Dans le terminal de lancement, vous tappez ^Z pour stopper le processus. Celui-ci devient alors le processus par défaut du job control de votre terminal. Il vous suffit alors de tapper bg pour le réexécuter en arrière plan.