1. Fork
1.1. Duplication de processus
1.1.1. Premier pas avec les processus
-
Compilez et exécutez le code en page suivante.
-
Que fait la fonction
getpid()? -
Que fait la fonction
getppid()? -
Quel est l’effet de la fonction
fork? -
Quelles sont les trois valeurs de retour possible de la fonction
fork? (Détaillez les valeurs de retour). -
Quelle est la valeur retournée par
getppid()lorsque la fonction est exécutée par le processus dupliqué ? -
Pourquoi le processus dupliqué n’exécute pas les lignes situées avant l’appel à
fork?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
printf("pid=%d, parent_pid:%d, retour de la fonction fork: "
"N/A. Début du processus\n", getpid(), getppid());
const int pid = fork();
if (pid == -1) {
perror("Impossible de dupliquer le processus courant");
return errno;
}
if (pid > 0) {
printf("pid=%d, parent_pid:%d, retour de la fonction fork: %d."
" Début du traitement\n", getpid(), getppid(), pid);
// On simule un traitement de trois secondes
sleep(3);
printf("pid=%d, parent_pid:%d, retour de la fonction fork: %d. "
"Fin du traitement\n", getpid(), getppid(), pid);
}
if (pid == 0) {
printf("pid=%d, parent_pid:%d, retour de la fonction fork: 0. "
"Début du traitement\n", getpid(), getppid());
// On simule un traitement d'une seconde
sleep(1);
printf("pid=%d, parent_pid:%d, retour de la fonction fork: 0. "
"Fin du traitement\n", getpid(), getppid());
}
printf("pid=%d, parent_pid:%d, retour de la fonction fork: %d. "
"Fin du processus\n", getpid(), getppid(), pid);
return EXIT_SUCCESS;
}
1.1.2. Création d’un petit fils
-
Modifiez le code précédent pour que le processus fils se duplique (créant ainsi un autre processus appelé ici petit fils). Le processus petit fils suivra l’algorithme suivant :
-
Affichage des informations contextuelles (son PID, le PID de son processus parent et le nouveau retour de la fonction
fork) et de"Début du traitement du petit fils\n" -
Attente de 5 secondes
-
Affichage de
"Fin du traitement du petit fils\n" -
Retourne la valeur
42(returnouexit)
-
-
Décrivez le comportement du programme lorsqu’il est exécuté depuis un terminal.
-
Quel est l’impact de la fin du processus parent sur les processus fils et petit fils ?
1.2. Attente de la fin d’un processus
-
A l’aide de l’appel system
waitattendez la fin du processus fils depuis le processus père -
A l’aide de l’appel system
waitattendez la fin du processus petit fils depuis le processus fils
| Les deux questions se basent sur la résolution de l’exercice Création d’un petit fils. Si vous n’avez pas réussi l’exercice précédent, basez-vous sur le code fourni dans le TP et ne réalisez que la première question. |
1.3. Récupération de la valeur de retour d’un fils
-
A l’aide des
macros préprocesseurdéfinies dans le fichier d’entête sys/wait.h. Récupérez la valeur de retour du processus petit fils depuis le processus fils.
| La question se base sur la résolution de l’exercice Création d’un petit fils. Si vous n’avez pas réussi l’exercice précédent, basez-vous sur le code fourni dans le TP et essayez de récupérer le code de retour du processus fils depuis le processus père. |
2. Transformation de processus
-
Recopiez le code ci-dessous dans deux fichiers distincts:
launcher.cetèxecuted.c. -
Compilez le fichier
executed.c. -
Modifiez le code du fichier
launcher.cafin de remplacerREPLACE_BY_THE_PATH_TO_THE_EXECUTED_PROGRAMpar le chemin absolu de votre programme compilé. -
Compilez, exécutez le fichier
launcher.cet expliquer le résultat obtenu. -
Commentez la valeur de
argv[0]par rapport à une exécution classique (lancez le programmeèxecuted.cdans un terminal). -
Modifiez le fichier
launcher.cpour que l’appel systèmeexecvesoit réalisé depuis un *processus fils (fork). -
Modifiez le fichier
launcher.cafin d’ajouter une boucle infinie (while(1){}juste après l’appel systèmeexecve. Expliquez le résultat.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
printf("Trying to run execve system call...");
char *args[] = {
"Execve ran program",
"My Name",
NULL
};
if (execve("<REPLACE_BY_THE_PATH_TO_THE_EXECUTED_PROGRAM>", args, NULL) == -1) {
perror("Error returned by execve: ");
} else {
printf("Error in system call");
}
return EXIT_SUCCESS;
}
1
2
3
4
5
6
7
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
printf("I am ran by an execve system call.\nProgram: %s\nWell done %s!\n", argv[0], argc > 1 ? argv[1] : "dear");
return EXIT_SUCCESS;
}
3. Redirections
3.1. Lecture depuis l’entrée standard
Compilez et exécutez le code
-
Note: le programme attend que quelque chose soit écrit sur l’entrée standard (écrivez dans la console et appuyez sur
Enter)
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
// Lecture de L'entrée standard
char tab[200] = {};
printf("Please enter something: \t");
fgets(tab, sizeof(tab) / sizeof(char), stdin);
printf("\nRead data from STDIN: %s\n", tab);
return EXIT_SUCCESS;
}
3.2. Changement de l’entrée standard
Le but de cet exercice et de changer l’entrée standard du programme. Par défaut, l’entrée standard d’un programme est le terminal qui le lance. On peut alors interagir avec le programme en utilisant le clavier. Ici, le but est de changer l’entrée standard du programme précédent afin de ne plus lire depuis le clavier mais depuis un fichier.
Créez un fichier nommé input.txt situé à côté de votre binaire.
Ajoutez le texte suivant dans le fichier:
1
2
Hello world from input.txt file.
Bye.
3.2.1. Ouverture du fichier
L’ouverture d’un fichier en utilisant un appel système UNIX se fait par l’utilisation de
la fonction open.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int text_file_descriptor = open("input.txt", O_RDONLY); (1)
if (text_file_descriptor == -1) { (2)
perror("Unable to open text.txt file: "); (3)
exit(errno); (4)
}
return EXIT_SUCCESS;
}
| 1 | Ouverture du fichier input.txt en lecture seule (O_RDONLY) |
| 2 | Comme tous les appels systèmes -1 est le retour d’erreur |
| 3 | Affichage du message d’erreur sur la sortie d’erreur |
| 4 | Fin du programme en retournant le code d’erreur |
Question :
Modifiez le programme précédant afin d’ouvrir le fichier input.txt au début du programme.
3.2.2. Fermeture du fichier
La fermeture d’un fichier en utilisant un appel système UNIX se fait par l’utilisation de
la fonction close.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int text_file_descriptor = ...
if (close(text_file_descriptor) == -1) { (1)
perror("Unable to close text.txt file: "); (2)
exit(errno); (3)
}
return EXIT_SUCCESS;
}
| 1 | Fermeture du fichier et test de la valeur de retour.
Comme tous les appels systèmes -1 est le retour d’erreur |
| 2 | Affichage du message d’erreur sur la sortie d’erreur |
| 3 | Fin du programme en retournant le code d’erreur |
Question :
Modifiez le programme de l’exercice Ouverture du fichier afin de fermer le fichier input.txt en fin de programme.
3.3. Redirection de l’entrée standard
Tout programme, est initialisé avec trois descripteurs de fichiers dans la table des descripteurs de fichiers:
-
L’entrée standard (dans la case
0) -
La sortie standard (dans la case
1) -
La sortie d’erreur (dans la case
2)
Comme vu ensemble lors de l’introduction de ce TP, la fonction dup permet de dupliquer un descripteur de fichier.
Le nouveau descripteur de fichier est alors inséré dans la table des descripteurs de fichiers dans la première place disponible.
En faisant une analogie avec le TP sur l’utilisation de Bash, les redirections sont réalisées avec les opérateurs < ou > :
-
echo Hello > my_file: redirection de la sortie standard vers le fichier 'my_file' (descripteur de fichier 1) -
cat < my_file: redirection de l’entrée standard depuis le fichier 'my_file' (descripteur de fichier 0) -
echo Hello 2> my_file: redirection de la sortie d’erreur vers le fichier 'my_file' (descripteur de fichier 2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int text_file_descriptor = open("some-file.txt", O_RDONLY);
int new_file_descriptor = dup(text_file_descriptor); (1)
if (new_file_descriptor == -1) { (2)
perror("Unable to duplicate file descriptor:"); (3)
exit(errno); (4)
}
return EXIT_SUCCESS;
}
| 1 | Duplication du descripteur du fichier input.txt |
| 2 | Comme tous les appels systèmes -1 est le retour d’erreur |
| 3 | Affichage du message d’erreur sur la sortie d’erreur |
| 4 | Fin du programme en retournant le code d’erreur |
Question : Modifiez le programme de l’exercice Fermeture du fichier afin qu’il suive l’algorithme suivant:
-
Ouverture du fichier
input.txt -
Fermeture de l’entrée standard (identifié par le descripteur de fichier
0) -
Duplication du descripteur du fichier
input.txt -
Lecture depuis l’entrée standard
-
Fermeture du fichier
input.txt
3.4. Redirection de la sortie standard
Tout programme, est initialisé avec trois descripteurs de fichiers dans la table des descripteurs de fichiers:
-
L’entrée standard (dans la case
0) -
La sortie standard (dans la case
1) -
La sortie d’erreur (dans la case
2)
Comme vu ensemble lors de l’introduction de ce TP, la fonction dup permet de dupliquer un descripteur de fichier.
Le nouveau descripteur de fichier est alors inséré dans la table des descripteurs de fichiers dans la première place disponible.
En faisant une analogie avec le TP sur l’utilisation de Bash, les redirections sont réalisées avec les opérateurs < ou > :
-
echo Hello > my_file: redirection de la sortie standard vers le fichier 'my_file' (descripteur de fichier 1) -
cat < my_file: redirection de l’entrée standard depuis le fichier 'my_file' (descripteur de fichier 0) -
echo Hello 2> my_file: redirection de la sortie d’erreur vers le fichier 'my_file' (descripteur de fichier 2)
Question : Écrivez un programme redirigeant sa sortie standard vers un fichier et suivant l’algorithme suivant :
-
Ouverture du fichier
output.txten le créant s’il n’existe pas (attention aux droits et aux paramètres) -
Fermeture du descripteur de fichier de la sortie standard
-
Duplication du descripteur du fichier
output.txt -
Écriture sur la sortie standard (via
printf("……\n")) -
Fermeture du fichier
output.txt
4. Bonus
Question : Écrivez un programme suivant l’algorithme ci-dessous :
-
Le processus père
-
Créé un processus fils
-
Affiche un message sur sa sortie standard
-
Se termine
-
-
Le processus fils
-
Redirige sa sortie standard vers un fichier en écrivant à la fin du fichier
-
Affiche un message sur sa sortie standard
-