Cours:TdProgSyst : Différence entre versions
(→Exercices) |
(→Duplication de processus) |
||
| Ligne 71 : | Ligne 71 : | ||
#include<sys/types.h> | #include<sys/types.h> | ||
#include<unistd.h> | #include<unistd.h> | ||
| − | + | ||
main() { | main() { | ||
int pid; | int pid; | ||
| Ligne 87 : | Ligne 87 : | ||
... | ... | ||
} | } | ||
| + | |||
| + | === Exécution de processus (Pour les plus avancés) === | ||
| + | |||
| + | 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); | ||
| + | ... | ||
Version du 14 décembre 2015 à 09:45
Sommaire
Td 12 Eléments de programmation système
Gestion des signaux
Deux fonctions du langage C permettent de travailler avec les signaux d’UNIX: la fonction **kill** et **signal**. La première permet d’envoyer un signal à un processus dont on connait le numéro de processus (le PID), et
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() {
... // 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.
La fonction alarm permet à un processus de s’auto-envoyer 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 ignorant le signal émis lors de la déconnexion.
3. Ecrire un programme affichant toutes les dix secondes la chaîne de caractères coucou sur l’écran.
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>
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
perror("erreur dans fork");
exit(-1);
default: // -------------------- on est dans le père
... // code du père
}
...
}
Exécution de processus (Pour les plus avancés)
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);
...