Blog ENI : Toute la veille numérique !
💥 Un livre PAPIER acheté
= La version EN LIGNE offerte pendant 1 an !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Unix
  3. Processus et mécanismes
Extrait - Unix Les bases indispensables (avec exercices pratiques et corrigés) (3ième édition)
Extraits du livre
Unix Les bases indispensables (avec exercices pratiques et corrigés) (3ième édition) Revenir à la page d'achat du livre

Processus et mécanismes

Quelques définitions

Un programme est un fichier de type ordinaire sur lequel est positionnée la permission d’exécution.

Un processus (ou tâche) est un objet système correspondant à l’environnement d’exécution du programme.

L’activité du système se traduit par la présence simultanée de nombreux processus dans une politique de temps partagé dans laquelle le noyau gère de façon équitable le partage des ressources.

Unix est, bien entendu, un système à mémoire virtuelle. Le noyau gère un espace mémoire constitué de pages qui séjournent soit en mémoire physique, soit dans un espace disque de pagination (appelé aussi zone de swap).

Sans rentrer dans les détails d’implémentation, nous pouvons considérer qu’un processus se compose de plusieurs éléments :

  • Zone de texte : cette partie correspond au code du programme. Cette zone est éventuellement partagée par plusieurs processus exécutant, en même temps, le même programme (notion de code réentrant).

  • Zone de données : il s’agit des données manipulées par le programme (pile d’exécution, allocations dynamiques de mémoire...). Cette zone est privée. Chaque processus a ses données.

  • Zone système : il s’agit des informations de gestion du processus (propriétaire, priorité, descripteurs de fichiers ouverts...). Cette zone est également une zone privée.

Les noyaux Unix intègrent également la notion de threads que l’on peut considérer comme des sous-processus. Ces threads constituent des activités indépendantes à l’intérieur d’un processus. Ils permettent aux développeurs de concevoir des applications client/serveur plus efficaces car le coût de création d’un thread est inférieur à celui de création d’un processus. Les threads permettent également de mieux exploiter les architectures matérielles multiprocesseurs.

Un processus en erreur ne peut pas compromettre l’intégrité du système car, dans ce cas de figure, le noyau met fin à ce processus via une interruption...

Signaux, interruption des processus

1. Description des signaux Unix

Un signal (ou interruption) correspond à une action dont la conséquence par défaut est l’élimination du processus concerné, à la condition d’en être propriétaire.

Les signaux peuvent être générés de différentes façons :

  • par une action de l’utilisateur au clavier,

  • par la commande kill,

  • par programme,

  • par le noyau souhaitant éliminer un processus en erreur.

Si rien n’a été prévu par le développeur, un processus est donc éliminé lors de la réception d’un signal provenant d’un autre processus, de même propriétaire ou de propriétaire root. Cependant, les programmes peuvent comporter des traitements associés à la réception de certains signaux, soit pour les ignorer, soit pour exécuter un sous-programme dit de déroutement, consistant souvent à supprimer des objets système avant de se terminer.

Certains signaux ont pour effet de générer un fichier core dans le répertoire courant. Ce fichier contient l’image mémoire du processus au moment de l’interruption et peut ainsi être examiné à l’aide d’un débogueur.

Les noms des signaux Unix sont standardisés au niveau des interfaces de programmation. Leur numéro interne peut, par contre, varier selon les versions. Cependant, pour les signaux qui concernent l’utilisateur, les numéros sont standards.

INT (2)

Ce signal peut être généré au clavier, le plus souvent par [Ctrl] c.

QUIT (3)

Ce signal peut être généré au clavier, le plus souvent par [Ctrl] \. Par rapport au précédent, son objectif est l’obtention d’un fichier core. En pratique, certains paramètres...

Redirections

Les concepteurs d’Unix ont souhaité qu’une commande puisse disposer, dès son démarrage, de trois descripteurs logiques de fichiers, implicitement ouverts. 

Ces descripteurs sont les suivants :

entrée standard

La commande peut y lire des données.

sortie standard

La commande peut y écrire des résultats.

erreur standard

La commande peut y écrire des messages d’erreur.

Ces descripteurs logiques seront mis en correspondance avec des fichiers physiques au niveau du shell, de façon transparente pour les commandes. Ils sont associés par défaut au terminal de contrôle du processus, si celui-ci est défini. Le shell de connexion possède, bien entendu, un terminal de contrôle et toutes les commandes de la session héritent naturellement de ce terminal (via le mécanisme du fork).

Concrètement, l’entrée standard correspond par défaut au clavier tandis que la sortie et l’erreur standard ne sont pas différenciées et sont associées, toutes deux, à l’écran.

Les commandes Unix n’exploitent pas systématiquement les trois descripteurs. Elles adoptent en général les comportements suivants :

1) Une commande dont le rôle n’est pas de produire une liste comme résultat n’utilise pas du tout la sortie standard. Elle préfère positionner un code retour pour les autres commandes qui souhaiteraient le tester. Cette tradition explique pourquoi une commande Unix qui se passe bien est souvent muette. Certains nouveaux utilisateurs d’Unix seront surpris, voire agacés, par ce comportement qui oblige souvent à s’assurer, par une autre commande, du bon fonctionnement d’une première commande.

Exemple


$ mkdir rep 
$ echo $? 
0 
$ ls -ld rep 
drwxr-xr-x   2 michel    michel    512 Sep 21 17:39 rep 
$
 

La commande mkdir a créé un répertoire mais n’a pas signalé la réussite de l’opération. Nous avons eu envie d’utiliser la commande ls pour nous assurer de la présence du nouveau répertoire. Au niveau du shell, le code retour de la dernière commande est disponible via la notation $? et son affichage, immédiatement après l’appel de la commande mkdir, nous...

Processus séquentiels

Plusieurs commandes peuvent être tapées sur la même ligne via le caractère ; (point-virgule). Les processus correspondants sont indépendants et s’exécutent séquentiellement, les uns après les autres.


$ id -a ; cal 7 1789 
uid=2000(michel) gid=2000(michel) groups=2000(michel),3000(eni)  
     July 1789 
Su Mo Tu We Th Fr Sa 
          1  2  3  4 
 5  6  7  8  9 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 31 
$
 

Dans l’exemple suivant, nous ne redirigeons que la sortie de la deuxième commande. 


$ id -a ; cal 7 1789 > toto 
uid=2000(michel) gid=2000(michel) groups=2000(michel),3000(eni) 
$ cat toto  
     July 1789 
Su Mo Tu We Th Fr Sa 
          1  2  3  4 
 5  6  7  8  9 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 24 25 
26 27 28 29 30 31 
$
 

L’utilisation intuitive de parenthèses permet de réaliser des redirections globales. Dans l’exemple suivant, toutes les sorties des différentes commandes sont redirigées séquentiellement dans un seul fichier résultat. Le regroupement de plusieurs commandes dans des parenthèses provoque, en fait, la création...

Mécanisme du pipeline

1. Principe de fonctionnement

Le pipeline est un mécanisme très caractéristique de l’esprit ”boîte à outils” Unix car il permet d’obtenir un traitement complet à partir d’une combinaison de commandes qui propagent leurs résultats intermédiaires. Les résultats d’une commande deviennent les données de la commande suivante et ainsi de suite jusqu’à obtenir le résultat recherché.

Pour concevoir un pipeline efficace, il convient, d’une part, de bien connaître les commandes disponibles et, d’autre part, d’avoir de bonnes idées afin de trouver des combinaisons intéressantes. Un peu d’astuce et d’expérience constituent les ingrédients nécessaires dans cette activité.

Syntaxiquement, le pipeline correspond au caractère | intercalé entre les différentes commandes.

La sortie standard du premier processus est redirigée vers un pipe (ou tube dans une traduction répandue) qui est l’équivalent d’un fichier temporaire se comportant comme une file (FIFO : First In, First Out).

L’entrée standard du processus suivant est redirigée vers ce même tube pour en réaliser la consommation.

Le nombre de commandes mises en jeu, ainsi que la quantité de données échangées, ne sont pas limités. Le shell initial crée un tube pour chaque couple de commandes et effectuent les redirections. Grâce au principe des descripteurs logiques, les commandes s’utilisent sans changement. Le système assure une synchronisation implicite de tous les processus. Ceux-ci s’exécutent en parallèle, ils sont tous créés, dès le départ, également par le shell initial. Le traitement a lieu aussi longtemps que le premier processus alimente le pipeline.

L’entrée standard du premier processus ainsi que la sortie du dernier restent disponibles pour des redirections classiques.

Toutes les commandes Unix ne se prêtent pas à une utilisation dans un pipeline. Pour jouer le rôle de producteur, il est clair que la commande doit utiliser sa sortie standard. Symétriquement, pour jouer le rôle de consommateur, il faut choisir des commandes...

Processus en arrière-plan

1. Principe et utilisation

Un programme peut être lancé dans un mode baptisé arrière-plan (background). Cela signifie que le processus shell parent ne se met pas, comme à l’habitude, en attente de la fin du processus fils. Concrètement, nous gardons la main pour effectuer d’autres traitements pendant le déroulement de ce fils.

Cette possibilité d’arrière-plan était fondamentale, dans les premières années, lorsque les utilisateurs ne disposaient que d’un seul terminal, sans autres possibilités de connexions simultanées. Aujourd’hui, dans les environnements graphiques, cette fonctionnalité reste malgré tout d’actualité car elle évite de multiplier inutilement les fenêtres d’émulateurs de terminaux.

D’autre part, au niveau de l’administration du système, des traitements réguliers tels que notamment les sauvegardes, peuvent ainsi être lancés de manière automatisée via un planificateur de travaux. Cela permet d’exploiter au mieux les heures creuses du système (nuits, week-ends) afin de ne pas pénaliser les temps de réponse des utilisateurs.

Pour lancer un programme en arrière-plan, il suffit de terminer la ligne de commande par le caractère &.

Exemple

La commande sleep reçoit en argument un nombre de secondes pendant lequel elle se met en attente. Cette commande n’est utile que dans un contexte de programmation mais elle va nous servir à illustrer simplement le concept d’arrière-plan.

Dans un premier essai, nous lançons la commande de façon classique (premier plan ou foreground). Notre shell de connexion est, bien entendu, en attente de la fin de la commande sleep mais nous décidons de l’interrompre...

Récapitulatif des commandes à approfondir  dans la documentation de référence

kill

Émission d’un signal.

nohup

Protection d’une commande contre le signal HUP.

ps

État des processus.

sleep

Suspension d’exécution.

tee

Duplication de la sortie standard.

touch

Modification des dates d’un fichier avec éventuelle création.

write

Dialogue avec un autre utilisateur (messagerie instantanée).

Quelques exercices

1) Afficher la liste des 15 premiers processus en éliminant la ligne de titre.

2) Récupérer dans un fichier "vierge" fic1 les 20 dernières lignes du fichier /etc/passwd.

3) Récupérer dans un deuxième fichier "vierge" fic2 le calendrier de l’année 1968.

4) Ajouter à la fin d’un fichier fic3 la concaténation des deux fichiers précédents.

5) Lancer en arrière-plan (en prévoyant de se déconnecter) la liste récursive de tous les fichiers du système. Éliminer les erreurs et mémoriser les résultats dans un fichier /tmp/maliste.

6) Se déconnecter autrement que par exit ou [Ctrl] d.

Solutions

1) Afficher la liste des 15 premiers processus en éliminant la ligne de titre.


ps -ef | tail +2 | head -15
 

2) Récupérer dans un fichier "vierge" fic1 les 20 dernières lignes du fichier /etc/passwd.


tail -20 /etc/passwd > fic1
 

3) Récupérer dans un deuxième fichier "vierge" fic2 le calendrier de l’année 1968.


cal 1968 > fic2
 

4) Ajouter à la fin d’un fichier fic3 la concaténation des deux fichiers précédents.


cat fic1 fic2 >> fic3
 

5) Lancer en arrière-plan (en prévoyant de se déconnecter) la liste récursive de tous les fichiers du système. Éliminer...