B.5. L'espace utilisateur
On appelle espace utilisateur l'environnement d'exécution des processus normaux, par opposition aux processus qui font partie du noyau. Cela ne signifie pas pour autant que tous ces processus soient réellement lancés directement par l'utilisateur : un système normal exécute un certain nombre de « démons » (ou processus d'arrière-plan) avant même que l'utilisateur ouvre une session de travail. Les « démons » sont alors considérés comme des processus de l'espace utilisateur.
Lorsque le noyau a terminé son initialisation, il lance le tout premier processus, init
, qui n'est généralement pas utile par lui-même. Les systèmes Unix fonctionnent donc avec de nombreux processus supplémentaires.
Tout d'abord, un processus peut se dupliquer (on parle de fork). Le noyau alloue alors une nouvelle zone de mémoire pour le deuxième processus, de contenu identique à celle du premier, et se retrouve simplement avec un processus supplémentaire à gérer. À ce moment précis, la seule différence entre les deux processus est leur pid. Par convention, le nouveau processus est appelé le fils, alors que celui dont le pid n'a pas changé est appelé le père.
Il arrive que le processus fils reste tel quel et « vive sa vie », indépendamment de son père, avec ses propres données correspondant au programme initial. Néanmoins, le cas le plus fréquent est que ce fils exécute un autre programme ; à de rares exceptions près, sa zone mémoire est alors simplement remplacée par le nouveau programme, dont l'exécution démarre. C'est précisément ce mécanisme que le système d'initialisation (le processus n°1) exploite pour démarrer des services additionnels et exécuter la séquence de démarrage, jusqu'à aboutir au lancement d'une interface graphique pour l'utilisateur (la séquence des événements est décrite avec plus de détails dans la
Section 9.1, « Démarrage du système »).
Lorsqu'un processus finit la tâche qui lui était dévolue, il se termine. Le noyau récupère alors la mémoire qui lui était affectée et cesse de lui distribuer des intervalles de temps d'exécution. Le processus père est informé de la destruction du fils : cela permet entre autres au père d'attendre la complétion d'une tâche sous-traitée. On retrouve ce mode de fonctionnement dans les interpréteurs de commandes (shells) : lorsque l'on tape une commande dans un shell, on ne retrouve l'invite que lorsqu'elle s'est terminée. La plupart des shells permettent cependant de ne pas attendre la fin de l'exécution d'une commande : il suffit pour cela de faire suivre le nom du programme à exécuter par &. On retrouve alors l'invite aussitôt, ce qui peut poser des problèmes si la commande a des données à afficher.
Un démon est un processus lancé automatiquement au démarrage et qui fonctionne en tâche de fond pour accomplir certaines tâches de maintenance ou fournir des services aux autres processus. Cette notion de « tâche de fond » est arbitraire et ne correspond à rien de particulier du point de vue du système : ce sont des processus comme les autres, qui sont exécutés chacun à leur tour pendant un bref intervalle de temps de la même manière que les applications visibles. La distinction est simplement humaine : un processus qui fonctionne sans interaction avec l'utilisateur (sans interface graphique, notamment) est dit fonctionner en tâche de fond ou en tant que démon.
B.5.3. Communications entre processus
Qu'il s'agisse de démons ou d'applications interactives, un processus isolé n'est souvent pas très utile. Il existe donc différentes méthodes permettant à des processus séparés de communiquer entre eux, soit pour s'échanger des données, soit pour se contrôler l'un l'autre. Le terme générique les désignant est InterProcess Communications (IPC) c'est-à-dire communications inter-processus.
Le système le plus simple est le fichier : le processus qui souhaite émettre des données les écrit dans un fichier dont le nom est convenu à l'avance ; le processus destinataire n'a alors qu'à lire ce fichier pour y récupérer les données.
Pour éviter que les données soient stockées sur un disque dur, on peut également utiliser un tuyau ou tube (pipe en anglais). Il s'agit simplement d'un système de communication où des octets écrits à un bout ressortent tels quels à l'autre bout. Si les deux extrémités sont contrôlées par deux processus différents, on obtient un canal de communication simple et pratique. Les tubes se décomposent en deux catégories. Un tube nommé dispose d'une entrée spéciale dans le système de fichiers (bien que les données qui y transitent n'y soient pas stockées) et les deux processus peuvent donc l'ouvrir indépendamment l'un de l'autre, si l'emplacement du tube nommé est connu. Dans les cas où l'on cherche à faire communiquer deux processus apparentés (par exemple un père et son fils), il est possible au père de créer un tube anonyme, dont héritera son fils après le fork ; les deux processus pourront alors s'échanger des données sans passer par le système de fichiers.
Mais toutes les communications inter-processus ne servent pas à faire transiter des flux de données. Il arrive également que des applications aient simplement besoin de se transmettre des messages comme « suspendre l'exécution » ou « reprendre ». Unix (et donc Linux) fournit pour cela un mécanisme de signaux, par lequel un processus peut simplement envoyer un signal spécifique (parmi une liste prédéfinie de signaux) à un autre, simplement en connaissant son pid.
Pour des communications plus complexes, il existe aussi des mécanismes par lesquels un processus peut par exemple ouvrir l'accès d'une partie de sa zone mémoire à d'autres ; cette mémoire est alors partagée entre plusieurs processus, ce qui autorise à faire passer des données de l'un à l'autre.
Enfin, les connexions par le réseau peuvent également servir à faire communiquer différents processus, susceptibles de s'exécuter sur des ordinateurs différents (voire séparés de milliers de kilomètres).
Tous ces mécanismes sont utilisés, à des degrés divers, dans le fonctionnement normal d'un système Unix typique.
Les bibliothèques de fonctions jouent un rôle crucial dans le fonctionnement d'un système d'exploitation Unix. Ce ne sont pas à proprement parler des programmes, puisqu'elles ne s'exécutent pas indépendamment, mais des collections de fragments de programmes qui sont utilisés par des programmes classiques. Parmi les bibliothèques les plus courantes, citons par exemple :
la bibliothèque C standard (glibc), qui contient des fonctions de base telles que celles permettant d'ouvrir des fichiers ou des connexions réseau, mais aussi de faciliter les interactions avec le noyau ;
les boîtes à outils graphiques (toolkits), Gtk+ et Qt, qui permettent à de nombreux programmes de réutiliser les objets graphiques qu'elles proposent ;
la bibliothèque libpng, qui charge, interprète et sauvegarde des images au format PNG.
L'existence de ces bibliothèques permet aux applications de réutiliser du code existant ; leur développement en est simplifié d'autant, surtout lorsque de nombreuses applications font appel aux mêmes fonctions. Comme les bibliothèques sont souvent développées par des personnes différentes, le développement global du système est ainsi plus proche de la philosophie historique d'Unix.
De plus, ces bibliothèques sont souvent dites « partagées », parce que le noyau est capable de ne les charger qu'une fois en mémoire même si plusieurs processus y font appel. Si le code qu'elles contiennent était au contraire intégré dans les applications, il serait présent en mémoire autant de fois qu'il y a de processus qui l'utilisent.