Cours:TdProgSyst

De troyesGEII
Aller à : navigation, rechercher

Éléments de correction (accès limité)

Td 12 Eléments de programmation système

Gestion des signaux


fonction signal


la fonction signal permet d’associer une fonction écrite par l’utilisateur à un signal UNIX: lorsque ce dernier est reçu, la fonction est exécutée.

Les signaux les plus classiques sont les suivants:

  SIGINT   signal envoyé par UNIX lors d’un Ctrl C pour stopper le processus
  SIGHUP   signal émis par UNIX lors de la déconnexion
  SIGALRM  signal émis par la fonction alarm()
  SIGUSR1  signal à la disposition de l’utilisateur
  SIGUSR2  autre signal à la disposition de l’utilisateur

Un exemple d’utilisation de ces fonctions est représenté ci-dessous:

    #include <stdio.h>
    #include <sys/types.h>
    #include <signal.h>
    
    void gestion_signal(int s) {
    ...                               // code de gestion du signal
    }
    
    main() {
    ...
    signal(SIGUSR1,gestion_signal);   // qd on reçoit SIGUSR1, exécute gestion_signal()
    ...
    }

Chaque fois que le processus recevra le signal SIGUSR1, on ira exécuter la fonction gestion_signal. Pour ceux qui connaissent le concept d’ interruption, il s’agit ici d’une interruption logicielle.

fonction alarm


La fonction alarm (définie dans unistd.h) permet à un processus de s’auto-envoyer une seule fois le signal SIGALRM au bout d’une certaine temporisation exprimée en secondes.

Exercices

1. Ecrire un programme ignorant les arrêts claviers (CTRL+C, ...).

2. Ecrire un programme affichant toutes les Troyes secondes la chaîne de caractères coucou sur l’écran.

3. (Hors TD) Ecrire un programme ignorant le signal émis lors de la déconnexion.

4. (Hors TD) Ecrire un programme permettant d’afficher le numéro des signaux reçus par le programme.

Duplication de processus

La fonction fork permet à un processus de se dupliquer en mémoire: le segment de code, le segment de données et la pile sont dupliqués. Après l’appel de fork, deux processus identiques s’exécutent alors en mémoire. La valeur de retour de fork permet de savoir dans quel processus on se trouve. Si fork retourne:

  • la valeur 0, on est dans le fils.
  • une valeur positive, on est dans le père. La valeur retournée est le PID du fils.
  • la valeur -1, fork n’a pu s’exécuter pour des raisons diverses: par exemple, plus de mémoire disponible...

Un exemple d'utilisation est:

    #include<sys/types.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    main() {
    int pid;
    ...
    switch (pid=fork()) {
           case  0:            // -------------------- on est dans le fils 
                    ....       // code du fils
                    exit(0);   // fin du fils
           case -1:            // -------------------- erreur du fork
                    cerr << "erreur dans fork" << endl;
                    exit(-1);
           default:            // -------------------- on est dans le père
                    ...        // code du père
           } 
    ...
    }

Exercices

1. Ecrire un programme se dupliquant en mémoire: le fils écrit des f sur l’écran et le père écrit des P'. Expliquer l'affichage obtenu.

2. (Pour les plus avancés) Ecrire un programme se dupliquant en mémoire: le fils lit une valeur saisie par l’utilisateur et se termine en retournant la valeur lue dans exit. Le père affiche alors cette valeur (en utilisant la fonction wait) ou le signal qui a terminé le fils.

La fonction wait permet d’attendre qu’un processus fils se termine et de récupérer sa valeur de retour. On lui envoie l'adresse d'une variable entière (par exemple, &valeurRetour) et la valeur récupérée dans les deux octets de poids faible de cette variable se décompose de la manière suivante:

  • si le fils s’est terminé par un appel à exit, l’octet de poids le plus faible est nul et l’autre contient la valeur transmise par l’intermédaire d’ exit.
  • si le fils s’est terminé suite à la réception d’un signal, l’octet de poids le plus faible contient le numéro du signal et l’autre octet est nul. Si ce dernier n’est pas nul mais si son bit numéro 7 est positionné, un extrait de la mémoire a été placé sur le disque (core dump).


3. (Hors TP) Ecrire un programme se dupliquant dix fois en mémoire: le fils numéro i écrit un fichier de nom File_i.txt de 100 lignes identiques constituées chacune de 50 lettres majuscules aléatoires (ce fichier est réécrit en permanence pendant toute la durée de vie du fils). Après avoir généré ses fils, le processus père attend l’appui de la touche ’Q’ pour les supprimer et se terminer. On vérifiera la présence des fils par la commande ps ou encore top. Puis, on essaiera de supprimer le père brutalement (CTRL+C, ...) et l’on reverifiera l’état de la mémoire.

Exécution de processus (Pour les plus avancés)

fonctions exec

La famille d’appels systèmes exec permet de remplacer le processus courant par un autre placé en arguments dans l’appel de exec. Le nom générique de cet appel est exec. Le premier suffixe possible permet d’expliciter le passage des arguments:

  • suffixe l indique que les arguments sont passés en tant que liste terminée par NULL.
  • suffixe v spécifie que les arguments sont passés dans un tableau: la dernière valeur est NULL.

Le deuxième suffixe possible indique la façon de rechercher la commande:

  • suffixe e indique de rechercher la commande en utilisant les variables d’environnement passées en argument (sous forme d’un tableau terminé par NULL).
  • suffixe p indique de rechercher la commande dans le chemin de recherche standard (la variable PATH).

Donnons deux exemples possibles d’utilisation (pour plus de renseignements, se réferer au manuel man exec)

     #include <unistd.h>
     ...
     char *v[10];
     ...
     execlp("ls","2>/dev/null",NULL);
     ...
     v[0]="ls";                              // idem
     v[1]="-l";
     v[2]=NULL;
     execvp(v[0],v);
     ...

fonction system

La fonction system permet d'exécuter une commande du système d'exploitation et lorsque cette commande est terminée, de revenir exécuter la suite du programme.


Exercice

Ecrire un minishell permettant de lire des commandes tapées par l'utilisateur et de les exécuter.

Ressources