Source de cours/processus.php

<?
  
require ("../page.inc");
  require (
"lessons.inc");

  
$currentPage = new LessonPage("processus");

  
$currentPage->setContent('');

  
$currentPage->addChapter('general''Généralités''
<p>
Linux sait gérer plusieurs programmes simultanément. C\'est ce que l\'on nomme le <a href="systemes_exploitation.php#multi">multitâche</a>. Dans un environnement graphique, ce concept est plus évident de part la présence de plusieurs fenêtres à l\'écran. Toutefois cet article s\'interessera plutôt à la gestion du multitâche en ligne de commande.
</p><p>
Ce qui est désigné comme <strong>processus</strong> est une instance de programme s\'exécutant à un instant donné ainsi que son <strong>contexte</strong> (ou <strong>environnement</strong>). Ce dernier terme désigne l\'ensemble des ressources utilisées par le programme pour pouvoir se dérouler comme par exemple la mémoire ou les fichiers ouverts.
</p><p>
Les processus sont identifiés par un numéro unique dans le système à un moment donné&nbsp;: le <acronym xml:lang="en" lang="en" title="Process IDentifier">PID</acronym>. C\'est à l\'aide de ce nombre que l\'on peut désigner une instance de programme et interagir avec. Ils sont également caractérisés par un <strong>propriétaire</strong>. Il s\'agit de l\'utilisateur qui a demandé l\'exécution. En général, seul ce propriétaire pourra entreprendre des actions sur le processus.
</p><p>
Ils sont de plus organisés en <strong>hiérarchie</strong>. Chaque processus doit être lancé par un autre. Ce dernier porte le nom de processus <strong>père</strong> ou <strong>parent</strong> et ceux initiés le nom d\'<strong>enfants</strong> ou processus <strong>fils</strong>.
</p><p id="demon">
Cette hierarchie a une racine. Il s\'agit le plus souvent sur un système GNU/Linux du programme <strong>init</strong> 
qui est lancé par le noyau à la fin de son initialisation et a le PID 1. Il va alors entre autres se charger de lancer 
les différents services du système qui sont appelés <strong>démons</strong>. Un démon (francisation du terme anglais <strong xml:lang="en" lang="en">daemon</strong>)  est un processus qui est constamment en activité et fournit des services au système ou à l\'extérieur. Un exemple serait un programme de serveur web ou <acronym xml:lang="en" lang="en" title="File Transfert Protocol">FTP</acronym> ou bien celui gérant la restitution de sons.
</p><p>
init lance aussi un programme permettant à un utilisateur (ou plusieurs) de se connecter au système. Ce pourra être une fenêtre en mode graphique ou une invite en mode texte qui permettra de saisir le nom d\'utilisateur et le mot de passe avant de lancer une interface utilisateur (également graphique ou non).
</p>
'
);

  
$currentPage->addChapter('process''Etats des processus''
<p>
Lors de sa vie (entre le moment où il est lancé et celui où il se termine), un processus peut passer par différents états. Les principaux sont les suivants&nbsp;:
</p>
<ul>
<li><strong>Actif</strong></li>
<li><strong>Exécutable</strong></li>
<li><strong>Endormi</strong></li>
<li><strong>Zombie</strong></li>
</ul>
<p>
Le premier état correspond au processus qui en train de réaliser des actions à un instant donné. Il possède le processeur et réalise les opérations nécessaires à son déroulement.
</p><p>
Le deuxième état est pour un processus qui pourrait tout à fait être en train de s\'exécuter, mais il doit attendre que le processus actif laisse sa place. En effet, le multitâche n\'est en quelque sorte qu\'une illusion. Sur une machine possédant un seul processeur, à un instant donné un seul programme peut opérer.
</p><p>
Ces deux premiers états ne sont généralement pas distingués du point de vue de l\'utilisateur pour qui ils correspondent l\'un comme l\'autre à un programme en cours d\'exécution. Cette nuance concerne plus le noyau.
</p><p>
Un processus endormi ne fait rien. Il attend une condition pour redevenir exécutable ou actif. Il peut se mettre lui-même en sommeil. Un programme par exemple peut attekndre quelques secondes avant de poursuivre son exécution pour laisser le temps à l\'utilisateur de lire un message affiché. Mais il peut aussi être mis en sommeil par le noyau en attendant que ce qu\'il demande soit disponible. Pour illustrer ceci, on peut observer un programme de chat (<acronym xml:lang="en" lang="en" title="Internet Relay Chat">IRC</acronym>) permettant de dialoguer sur Internet avec d\'autres personnes. Tant que personne n\'écrit rien, ce programme n\'a rien à faire. Il va tout d\'abord dire au système qu\'il souhaite lire les informations qui arrivent d\'Internet. Si rien n\'est présent, il est mis dans un état endormi. Il sera alors réveillé dès que quelqu\'un écrit un message afin que le processus puisse le traiter.
</p><p>
Le dernier des états évoqués ici est un peu particulier. Il s\'agit de l\'état zombie. Un tel processus est en réalité terminé. Il a fini son exécution et n\'a donc plus de raisons d\'exister. Seulement pour diverses raisons possibles, son père n\'a pas été informé de ceci. Et tout processus doit prendre connaissance de la fin de ceux qu\'il a lancés (ses fils). Le système conserve donc les informations correspondant au processus enfant afin que son parent puisse voir qu\'il a fini son exécution.
</p>
'
);

  
$currentPage->addChapter('list''Lister les processus''
<p>
Comme indiqué précédemment, un processus peut être identifié avec son PID. Pour connaître celui-ci, il existe un outil qui s\'appelle <strong>ps</strong>. Il affiche la liste des processus en cours d\'exécution (pas forcément tous selon les options) avec d\'autres informations comme la commande utilisée pour le lancer ou son état.
</p>
<p>
Pour connaître les options disponibles avec ps, le plus simple est de consulter sa <a href="references.php#ref">page de manuel</a>, d\'autant que selon les systèmes ces options peuvent changer. Une option courante est <strong>-e</strong> qui permet de lister tous les processus du système (et non ceux de l\'utilisateur courant uniquement). Ci-dessous un exemple d\'affichage à l\'utilisation de ps. L\'option -o a aussi été utilisée. Elle permet de spécifier quelles sont les informations devant être affichées. Sans s\'étendre sur les possibilités offertes, il faut juste préciser qu\'a été choisi ici d\'afficher le PID, le <acronym xml:lang="en" lang="en" title="Parent Process IDentifier">PPID</acronym> (le PID du parent), l\'utilisateur propriétaire et le programme concerné.
</p>
<pre class="terminal">
&gt; ps -e -o"%p  %P  %U  %c"

 PID   PPID  USER      COMMAND
   1      0  root      init
 506      1  root      syslogd
1411      1  root      httpd
1456      1  root      login
3713   1456  Tian      bash
7083   3713  Tian      ps
</pre>
<p>
On retrouve donc bien ici le processus init qui n\'a pas de père (il n\'y a pas de processus ayant 0 comme PID). Ensuite sont présents syslogd (responsable de l\'enregistrement des messages d\'information ou d\'erreur), httpd (le programme de serveur web) et login. Ce dernier permet à un utilisateur de se connecter sur le système. On peut voir ici que login a pour fils <a href="bash.php">bash</a> (le PPID de bash est 1456 qui est le PID de init). Il s\'agit du shell qui est lancé pour que l\'utilisateur puisse interagir avec le sustème. bash a comme processus enfant ps qui est créé par la commande tapée pour obtenir ce résultat.
</p>
<p>
Le programme ps ne permet d\'obtenir qu\'une vision instantanée des processus courant. Il existe un exécutable qui affiche ceux-ci à intervalles réguliers. Il s\'agit de <strong>top</strong> qui montre par défaut les processus en ordre décroissant d\'utilisation du processeur. Il indique aussi l\'utilisation mémoire ce qui fait de top un outil d\'administration utile pour connaître les programmes consommateurs de ressources.
</p>
'
);

  
$currentPage->addChapter('action''Intéragir avec les processus''
<p>
A un processus donné peut être envoyé un <strong>signal</strong>. Ceci peut être vu comme une indication donnée au programme de manière asynchrone. Ce dernier terme signifie que le signal doit être pris en compte immédiatement quelles que soient les opérations en cours de traitement. La personne ayant conçu le programme peut décider du comportement à adopter à la réception du signal pour remplacer celui par défaut. La partie du programme responsable de ceci est appelée <strong>gestionnaire de signal</strong> (en anglais <strong xml:lang="en" lang="en">signal handler</strong>).
</p>
<p>
Un signal sera désigné soit par sa valeur numérique soit par son nom. Etant donné que les valeurs numériques peuvent varier d\'un système à un autre, il vaut mieux utiliser le nom. Le tableau suivant liste les signaux les plus utilisés avec leur valeur sur un système Linux.
</p>
<div class="lesson-spacer">
<table class="lesson" summary="Les principaux signaux avec leurs comportements par défaut et une description">
<caption>Principaux signaux</caption>
<tr>
<th scope="col" abbr="Signal">Signal</th><th scope="col" abbr="Numérique">Valeur numérique</th><th scope="col" abbr="Défaut">Comportement par défaut</th><th scope="col" abbr="Description">Description</th>
</tr>
<tr>
<td class="lesson-spacing"></td><td class="lesson-spacing"></td><td class="lesson-spacing"></td><td class="lesson-spacing"></td>
</tr>
<tr>
<td><strong>SIGINT</strong></td><td>2</td><td>Terminer le processus</td><td>Il s\'agit d\'une demande venant du clavier, le plus souvent à l\'aide la combinaison de touches Ctrl-C.</td>
</tr>
<tr>
<td><strong>SIGKILL</strong></td><td>9</td><td>Terminer le processus</td><td>Ce signal permet d\'arrêter tout programme car il ne peut être géré différemment que le comportement par défaut. L\'arrêt du programme est brutal.</td>
</tr>
<tr>
<td><strong>SIGUSR1</strong></td><td>10</td><td>Terminer le processus</td><td>Ce signal n\'a pas de signification particulière. Il peut être utilisé de manière différente par chaque programme.</td>
</tr>
<tr>
<td><strong>SIGSEGV</strong></td><td>11</td><td>Terminer le processus</td><td>Ce signal est envoyé à un programme lorsque qu\'il tente d\'accéder à un endroit invalide en mémoire.</td>
</tr>
<tr>
<td><strong>SIGUSR2</strong></td><td>12</td><td>Terminer le processus</td><td>Identique à SIGUSR1.</td>
</tr>
<tr>
<td><strong>SIGTERM</strong></td><td>15</td><td>Terminer le processus</td><td>Si le programme n\'a pas prévu de gérer ce signal, l\'arrêt sera aussi brutal que pour SIGKILL. Mais comme le comportement par défaut peut être changé, le programme a la possibilité de réaliser des opérations avant de se terminer.</td>
</tr>
<tr>
<td><strong>SIGCHLD</strong></td><td>17</td><td>Ignorer ce signal</td><td>Envoyé à un processus dont un fils est arrêté ou terminé.</td>
</tr>
<tr>
<td><strong>SIGCONT</strong></td><td>18</td><td>Reprendre le processus</td><td>Permet de faire se continuer un processus qui avait été arrêté par exemple à l\'aide de SIGSTOP (voir ci-après).</td>
</tr>
<tr>
<td><strong>SIGSTOP</strong></td><td>19</td><td>Arrêter le processus</td><td>Ce signal demande au processus de suspendre son exécution. Comme SIGKILL, ce signal ne peut être géré différemment.</td>
</tr>
</table>
</div>
<p>
Ces signaux sont donc envoyés par le sytème à un processus pour le prévenir de certains événements. Mais un utilisateur peut aussi envoyer des signaux grâce à la commande intégrée à bash, <strong>kill</strong>. Elle s\'utilise en indiquant le numéro de signal à l\'aide de l\'option -s puis du PID du processus. Par exemple&nbsp;:
</p>
<code class="terminal">
&gt; kill -s SIGSTOP 256<br />
&gt; kill -SIGSTOP 256
</code>
<p>
Ces deux commandes sont identiques. La deuxième est plus courte à utiliser mais ne fonctionne pas sur tous les systèmes. L\'une comme l\'autre enverra le signal SIGSTOP au processus de PID 256.
</p>
<p>
Si l\'on utilise kill sans spécifier de numéro de signal, c\'est un SIGTERM qui sera envoyé.
</p>
<p>
Généralement lorsque l\'on souhaite arrêter un programme qui refuse de le faire ou présente un comportement étrange, on commence par essayer de lui envoyer un SIGTERM (avec kill sans option de signal par exemple). Cela permet de lui laisser une chance de se quitter proprement. Si toutefois cela ne fonctionne pas, il faut alors utiliser SIGKILL qui va obligatoirement terminer le processus.
</p>
'
);

  
$currentPage->addChapter('jobs''Gestion des jobs''
<p>
Le shell utilisé le plus fréquemment sur les systèmes GNU/Linux, <a href="bash.php">bash</a>, propose un système de contrôle des <strong>jobs</strong>. Un job correspond à une tâche demandée par l\'utilisateur. Cette tâche peut être composée de plusieurs processus. Ce qui les regroupe est un <a href="bash.php#redirect">tube</a>. Un job est donc un regroupement de plusieurs commandes devant s\'exécuter les unes à la suite des autres en communiquant leurs résultats.
</p>
<p>
Un exemple tout simple de job pourrait être le suivant&nbsp;:
</p>
<code class="terminal">
&gt; ls | less
</code>
<p>
ls permet de lister les fichiers. Mais quand ils sont trop nombreux, la consultation est dificile. less permet alors de paginer ce qui lui est passé sur son entrée standard et de naviguer facilement à l\'aide des touches fléchées.
</p>
<p>
Il faut bien voir que lorsque ceci aura été tapé, 2 processus seront créés. Un pour exécuter ls et l\'autre pour less. Mais bash fournit une abstraction permettant de manipuler ceci comme un tout, appelée donc job.
</p>
<p>
Mais un job pourrait tout aussi bien être constitué d\'une seule commande sans utilisation de tube. L\'utilisation d\'uniquement ls constituerait aussi le lancement d\'un job.
</p>
<p>
La commande intégrée à bash permettant de les lister s\'appelle <strong>jobs</strong>. La lancer dans un shell ne produira aucun résultat normalement.
</p>
<p>
Il est possible de lancer un job en arrière-plan. Cela permet alors de pouvoir continuer à utiliser le shell pour d\'autres tâches pendant qu\'il s\'exécute. Emacs est un éditeur de texte très utilisé (notamment pour faire ce site). Si dans une console au sein d\'un environnement graphique on le lance en tapant son nom, une fenêtre Emacs va s\'ouvrir par défaut. Mais la console ne sera plus utilisable car le shell attendra la fin de l\'exécution de l\'éditeur avant de laisser à nouveau la possibilité de lancer des commandes. Pour pouvoir donc lancer ce logiciel par exemple, il faut rajouter le symbole <strong>&amp;</strong> à la fin de la définition de la tâche. Pour cet exemple&nbsp;:
</p>
<code class="terminal">
&gt; emacs &amp;<br />
[1] 6373
</code>
<p>
La première valeur est le numéro du job. Celui-ci est unique dans le shell courant. Si plusieurs sont utilisés simultanément (comme par exemple avec plusieurs fenêtres de console), chacun aura ses propres jobs et ne pourra agir sur ceux des autres.
</p>
<p>
La seconde valeur affichée est le PID du dernier processus lancé pour ce job. Il correspondra à la dernière commande dans le tube. Etant donné qu\'il n\'y en a qu\'une ici, ce sera donc le PID pour le processus exécutant Emacs. Avec l\'exemple précédent, ce serait celui correspondant à less qui serait affiché.
</p>
<p>
On peut alors utiliser la commande jobs vue précédemment&nbsp;:
</p>
<pre class="terminal">
&gt; jobs
[1]+  Running       emacs &amp;
</pre>
<p>
On retrouve ici le numéro du job et la commande utilisée pour le lancer (dans la dernière colonne). La texte "<strong>Running</strong>" signifie qu\'il est en train de s\'exécuter. Le signe <strong>+</strong> indique qu\'il s\'agit du job le plus récemment manipulé (ce qui sera utile pour les commandes qui seront vues ensuite).
</p>
<p>
Si le programme avait été lancé en oubliant d\'ajouter le $ il est tout de même possible de pouvoir continuer d\'utiliser le shell. Pour cela, il faut utiliser la combinaison de touches <strong>Ctrl-Z</strong> (maintenir la touche Ctrl et appuyer sur la lettre Z). On aura alors ceci&nbsp;:
</p>
<pre class="terminal">
&gt; jobs
[1]+  Stopped       emacs
</pre>
<p>
Contrairement à l\'exemple précédent, l\'état du job est indiqué comme "<strong>Stopped</strong>". Le job est alors en sommeil et ne réalise aucune action. La fenêtre d\'Emacs est inactive et on ne peut utiliser ce programme.
</p>
<p>
Il existe toutefois une commande qui permet de demander à ce qu\'un job arrêté reprenne son exécution en arrière-plan. Il s\'agit de <strong>bg</strong> qui prend en paramètre le numéro de job. Par défaut, bg agit sur le job portant le + dans la liste affichée. Voici ce que l\'on obtient alors&nbsp;:
</p>
<pre class="terminal">
&gt; bg
[1]+ emacs &amp;
&gt; jobs
[1]+  Running       emacs &amp;
</pre>
<p>
Tout se passe alors comme si le &amp; avait été indiqué lors du lancement du programme. On peut remarquer qu\'il est d\'ailleurs ajouté à l\'affichage.
</p>
<p>
A l\'opposé de bg, il existe <strong>fg</strong> qui permet de mettre en avant-plan un job. Celui-ci s\'exécutera alors dans le shell empêchant de saisir d\'autres commandes. Le paramètre passé à fg est le même que pour bg (le numéro de job et par défaut celui avec un +). fg peut être utilisé pour un job tournant en arrière-plan ou arrêté.
</p>
<p>
L\'avant-dernier job manipulé est lui aussi indiqué d\'une manière particulière. Voici un exemple fictif d\'affichage&nbsp;:
</p>
<pre class="terminal">
&gt; jobs
[1]   Running       mozilla &amp;
[2]-  Stopped       su
[3]+  Stopped       emacs -nw &amp;
[4]   Running       dtfile &amp;
</pre>
<p>
En tapant seulement fg (sans paramètre donc), c\'est Emacs qui sera mis en avant-plan (l\'option -nw permet de l\'utiliser en mode texte directement dans la console). Pour rendre le programme su actif et utilisable, on peut taper indifféremment une des deux commandes suivantes&nbsp;:
</p>
<code class="terminal">
&gt; fg 2<br />
&gt; fg -
</code>
<p>
L\'utilisation du <strong>-</strong> permet donc d\'accéder à l\'avant-dernier job et d\'ainsi facilement passer d\'un job à un autre sans connaître leurs numéros.
</p>
<p>
Etant donné que kill est une commande intégrée à bash, il permet aussi d\'intéragir avec les jobs. Pour cela, il faudra à la place du PID indiquer le numéro du job précédé du caractère <strong>%</strong>. Comme par exemple&nbsp;:
</p>
<code class="terminal">
&gt; kill -SIGSTOP %1
</code>
<p>
Qui stoppera le job numéro 3. En fait l\'utilisation de Ctrl-Z vue précédemment est équivalente à l\'envoi d\'un signal SIGSTOP.
</p>
'
);

  
$currentPage->display();
?>