UNIX - principes de fonctionnement

Index

interface de programmation, appels système, fichiers, contrôle de processus, tubes (pipes), signaux, interface utilisateur, shells, entrées-sorties standards, scripts C-shell

Dans les chapitres précédents nous avons jeté les bases pour l’introduction d’un système d’exploitation. Un système d’exploitation est un programme nécessaire pour pouvoir gérer les ressources matérielles et logicielles (données, programmes) d’un système informatique. Un système d’exploitation tout seul n’est pas un système informatique. Nous avons choisi est le système UNIX et ce chapitre présente les fonctions principales de ce système. Ces fonctions seront approfondies dans les chapitres suivants en s’appuyant sur des exemples de programmation.

Introduction

Le système UNIX est un système fonctionnant en temps partagé, c’est qui signifie l’exécution de plusieurs programmes gerés en temps réel et découpés en tranches dites quanta. Le système de fichiers est conçu comme un arbre à plusieurs niveaux. Les utilisateurs peuvent créer leur propres sous-répertoires. Chaque fichier utilisateur est une simple séquence d’octets (bytes).

Les unités de disques et autres périphériques (e.g. périphériques standard: clavier et écran) sont gérés de la façon la plus proche possible des fichiers . Différentes caractéristiques fonctionnelles des périphériques sont “cachées” par les programmes de pilotage (drivers).

Le système UNIX gère plusieurs programmes en exécution, ces entités actives s’appellent processus. Un processus peut facilement créer un autre processus. La gestion des processus est basée sur un simple mécanisme de priorité.
UNIX intègre la mémoire virtuelle. Les pages sont importées dans la mémoire principale à la demande.
Le fonctionnement d’UNIX est facile à comprendre car il a été développé initialement par un seul programmeur Ken Thompson (Bell Laboratories), puis par Dennis Ritchie. La dernière incarnation du système UNIX appelée LINUX a était réalisée également par une seule personne, Linus Torvalds.
Les objectifs principaux de ces développements sont la simplicité, la flexibilité et l’efficacité.
Le système UNIX est écrit presque totalement en langage C; il est disponible directement (on-line). Ce mode de développement et d’accès ont permis d’en fixer les bugs, de le faire évoluer et de s’imposer sur toutes les plate-formes matérielles des micro-ordinateurs aux serveurs et super-ordinateurs. L’intégration des protocoles internet dans le système UNIX a permis l’émergence du WWW.

Interface de programmation

UNIX est composé de deux parties importantes et indépendantes: le noyau et les programmes système. Le noyau s’appuie sur les fonctions BIOS et permet de gérer le système de fichiers, le système mémoire, le(s) processeur(s) et les périphériques. Les programmes système exploitent les fonctions du noyau par le biais des appels système.
Les appels système définissent l’interface de programmation du système UNIX; l’ensemble des programmes système, incluant l’interpréteur de commandes, définit l’interface utilisateur.
Les appels système peuvent être regroupés en trois catégories:

  • gestion de fichiers et entrées/sorties
  • contrôle de processus,
  • gestion de données système.

Fichiers

Un fichier UNIX est une séquence d’octets. Les programmes utilisateurs peuvent interpréter les contenus des fichiers selon leurs besoins; le noyau n’impose aucune structure interne aux fichiers. Par exemple, le caractère ASCII 0 (en binaire: 00000000), qui est utilisé pour marquer la fin d’une chaîne de caractères au niveau des applications, n’a aucune signification spécifique pour le noyau UNIX.

Le système de fichiers est organisé sous la forme d’une structure arborescente de répertoires. Les fichiers répertoires sont eux mêmes des fichiers qui contiennent les liens vers d’autres fichiers. Un chemin (path) vers un fichier est une chaîne de caractères qui mène via les noms des sous-répertoires au fichier lui-même. Par exemple, /usr/include/signal.h est un chemin complet vers le fichier signal.h. Ce chemin est appelé chemin absolu parce qu’il débute à la racine du système de fichiers.

Un fichier peut être connu sous plusieurs noms; ces noms sont des liens. Un fichier existant doit avoir au moins un lien. Il y a deux sortes de liens: les liens soft et les liens hard. Les liens soft (symboliques) peuvent pointer les répertoires et peuvent transcender la frontière d’un système de fichiers (un autre système peut être installé sur un autre disque).

Le nom “.” dans un répertoire est lien hard qui pointe vers le répertoire lui-même. Le nom “..” est un lien hard qui pointe vers le répertoire parent.

Les périphériques ont des noms dans le système de fichiers; ils s’appellent fichiers spéciaux (special files). Le répertoire initial, le root, contient un certain nombre de sous-répertoires de base: bin, lib, user, etc, tmp, dev, .. Ces répertoires sont disponibles dans tous les systèmes UNIX/LINUX.

Les fichiers d’administration sont gardés dans le répertoire /etc; nous y trouvons le fichier passwd qui contient les noms et les paramètres des utilisateurs enregistrés dans le système.

L’accès aux fichiers répertoires et au fichiers ordinaires peut être réalisé par le biais des appels système tels que:

  • creat - création d’un fichier,
  • open - ouverture d’un fichier,
  • read/write - lecture et écriture dans un fichier,
  • lseek - déplacement dans un fichier,
  • stat -lecture des paramètres (état) d’un fichier,
  • mkdir - créer un répertoire,
  • close/unlink - fermeture et destruction d’un lien.

Ces appels de base ou primitives système nous serviront pour le développement des applications (commandes UNIX). Nous allons voir que ces appels fonctionnent avec des descripteurs. Un descripteur est un index dans un tableau qui répertorie les fichiers ouverts dans un programme en exécution.

Contrôle de processus

Un processus est un programme en exécution. Les processus sont identifiés par leurs identificateurs (process identifier) qui sont des entiers. Un nouveau processus est créé par l’appel système fork(). Le nouveau processus (processus fils) est une copie de l’espace d’adressage du processus père: le même programme avec les mêmes variables avec les mêmes valeurs.

Les deux processus continuent exécution concurrente du même programme à partir de l’instruction qui suit l’appel fork().
L’appel exec() est utilisé pour remplacer le programme initial du processus fils par un autre programme.

La gestion plus complète des processus par un programme système implique l’utilisation des appels système suivants:

  • fork - création d’un nouveau processus
  • exec - exécution d’un nouveau programme par le processus
  • exit - fin d’exécution d’un processus
  • wait/pause - attente d’un événement de type fin d’exécution d’un processus

Dans l’ensemble, les primitives permettent d’organiser le lancement d’exécution d’un programme et l’attente de la fin de son exécution.

Nous allons utiliser ces appels pour le développement d’une application de type interpréteur de commandes.

Tubes (pipes)

La communication entre les processus est très importante pour toutes les applications complexes qui engendrent plusieurs processus. La solution la plus simple consisterait à exploiter un fichier commun à plusieurs processus. Malheureusement ce moyen est très lent. Le mécanisme de communication le plus approprié pour la communication rapide entre les processus est un tube (pipe). Le pipe est un tampon dans la mémoire principale, géré par le système d’exploitation et permettant une communication directe et organisée entre deux ou plus processus.

Les primitives système utilisées pour la gestion des tubes sont:

  • pipe - création d’un tube,
  • dup - duplication d’un lien (descripteur) pour la redirection des données vers un tube.

L’accès d’un processus à l’unité centrale (processeur) est géré en mode partage de temps (time-sharing) par le noyau du système (programme ordonnanceur). Selon sa priorité et son état, le processus peut (ou non) obtenir la tranche de temps suivante pour son exécution.

Signaux

Les signaux UNIX sont des mécanismes de signalisation permettant de gérer les événements de type interruptions logiciel ou matériel. Chaque type de signaux correspond à différentes conditions. Un signal peut être généré par le clavier (e.g. ^C), par le gestionnaire de fenêtres, par une erreur de fonctionnement d’un processus (e.g. dépassement de l’espace mémoire alloué au processus), etc. Les signaux peuvent être également générés par l’appel système kill.

Les signaux ont toujours une cible qui est un processus. L’arrivée d’un signal vers un processus arrête son fonctionnement. Néanmoins les processus peuvent ignorer l’occurrence d’un signal en bloquant son utilisation dans le tableau des vecteurs d’interruption associés à ce processus.

Les principaux appels système utilisés pour la gestion des signaux sont:

  • signal - permet d’établir réponse (e.g. signal doit être ignoré) à l’occurrence d’un signal,
  • kill - permet d’envoyer un signal vers un processus.

Interface utilisateur

Les utilisateurs du système UNIX et certains programmeurs ont besoin d’un ensemble de programmes système pour réaliser leurs tâches applicatives. Ces programmes font d’eux mêmes les appels systèmes nécessaires pour leur fonctionnement.

Les programmes système ou les commandes peuvent être regroupés en plusieurs catégories. La plupart des commandes gère les répertoires et les fichiers. Quelques unes de ces commandes sont citées ci-dessous:

  • cd - changement d’un répertoire,
  • mkdir/rmdir - création d’un répertoire/destruction d’un répertoire,
  • pwd - chemin du répertoire de travail,
  • ls - liste de fichiers dans un répertoire, ls -l (option longue),
  • more - affiche le contenu d’un fichier texte sur l’écran,
  • link/unlink - création ou destruction d’un lien,
  • rm - effacement de tous les liens.

Parmi les programmes applicatifs se trouvent les compilateurs, les éditeurs du texte, les logiciel de montage audio et vidéo, les logiciels CAO, le navigateurs WEB, etc.. Tous ces logiciels résident initialement sur le disque dur sous la forme de fichiers exécutables.

Shells

L’exécution des programmes applicatifs et des commandes est lancée par un interpréteur de la ligne de commandes. L’interpréteur de commandes est un processus normal du système UNIX. Il est également appelé shell (coquille) parce qu’il englobe le noyau du système. Dans le mode UNIX il y a plusieurs interpréteurs de commandes. Le plus ancien est le Bourne shell ou shell tout court. Parmi les interpréteurs, le plus répandus est le C-shell développé par Bill Joy le fondateur de Sun Microsystems. Sous LINUX on utilise souvent le shell appelé bash. bash est assez proche du C-shell.

Les programmes shells possèdent leurs langages de commandes permettant d’enchaîner l’exécution de plusieurs activités à réaliser pendant une session de travail. Le shell indique qu’il est prêt à accepter une nouvelle commande par l’affichage d’une invitation ( prompt) (% pour C-shell).

Exemple
%
ls -l *.c

Les commandes peuvent prendre des arguments et des options. Ces données sont des mots séparés par des espaces.

Les programmes shell intègrent un certain nombre de commandes qui sont liées à l’état d’une session. Par exemple, les commandes cd ou pwd sont des commandes internes. D’autres commandes sont de simples fichiers exécutables.

Une liste de plusieurs répertoires est maintenue par le shell. Pour chaque commande, tous les répertoires de cette liste sont scrutés pour y trouver le nom (le fichier) de la commande. Si le fichier est trouvé, il est chargé et son exécution est lancée.

L’exécution d’une commande est effectuée par l’appel système fork() suivi de exec() avec le fichier à charger et exécuter. Le programme shell normalement attend la fin d’exécution de la commande sur l’appel wait. Si l’utilisateur veut lancer une commande en “arrière plan” (background) il doit taper le caractère & après le nom de la commande. Dans ce cas le programme du shell, qui est le processus père n’attend pas la fin d’exécution du programme de processus fils et affiche à nouveau un prompt.

Exemple:
%
cc -o prog prog.c &

C-shell introduit la notion de job (tâche). Le contrôle des jobs permet d’envoyer un processus en arrière-plan ou de le rappeler en avant-plan (foreground). Dans un système à interface graphique, chaque fenêtre est traitée comme un terminal. Avec plusieurs fenêtres, plusieurs processus peuvent être en avant-plan à un instant donné.

Entrées/Sorties standards

Les processus peuvent ouvrir des fichiers à demande, mais les trois premiers fichiers associés aux entrées/sorties standards, sont ouverts par défaut dans chaque processus. Ces fichiers spéciaux désignent le clavier (descripteur 0: entrée standard), l’écran (descripteur 1: sortie standard), et l’écran d’erreurs (descripteur 2). Le premier fichier ouvert explicitement dans un processus est désigné par le descripteur numéro 3. La plupart des programmes acceptent un fichier à la place d’une entrée ou sortie standard. Cette solution permet d’effectuer les redirections en sortie et en entrée.

Exemples:
%
ls -l > liste,
%
ls -l > lpr
(lpr est un fichier spécial - imprimante)
%
lpr < liste

Les redirections peuvent être également effectuées sur des pipes. Cette solution permet d’enchaîner le fonctionnement de plusieurs commandes communicant par les tubes.

Exemple:
%
ls | more | lpr

Les scripts

Les scripts sont des programmes écrits en langage shell. Un langage shell exploite les variables système et ses propres variables locales et interprète les instructions de contrôle de type if, else, loop. L’exécution d’une commande ressemble à l’évocation d’une fonction. La programmation shell permet de combiner l’exécution de plusieurs programmes et de créer des applications complexes.

Exemple:

#la diese est necessaire pour indiquer l’utilisation du C-shell

set a=0 # creation d’une variable
while ($a != 70)
# test du contenu de la variable a
readkey
# lecture d’un caractere sur le clavier: programme utilisateur
set a=$status
# recuperation du code de retour apres l’execution du readkey
echo $a
# affichage du code de retour
switch ($a) # test de la variable a
case 65: # valeur cherchee est 65
ls -l # commande ls -l
breaksw
case 66:
echo “give name”
set b=$<
# lecture d’une chaine de caracteres a partir du clavier; chargement dans la variable b
cc -o $b $b.c # compilation du programme $b.c
breaksw
case 67:
echo “give name”
set b=$<
more $b.c
breaksw
default:
echo press F to exit
endsw
end

Résumé

Dans ce chapitre nous avons parcouru les grandes fonctions d’un système d’exploitation. Un système d’exploitation est composé d’un noyau et d’une interface utilisateur développée à partir des fonctions du noyau. Le programme noyau gère le système de fichiers, le temps de l’unité centrale partagé par plusieurs processus, la mémoire principale et la mémoire virtuelle et l’ensemble des périphériques accessibles dans la configuration matérielle du système.

Dans le chapitre suivant, nous nous intéressons à la conception et au fonctionnement du système de fichiers et aux appels système permettant d’effectuer les opérations sur les fichiers ordinaires et les répertoires UNIX.