Skip to content

Les mécanismes d'exécution / processus, ordonnancement

ExempleFork.c
/* ---------------------------------------------------------------------------
* Schéma de création de processus.
* Création d'un processus fils et test pour exécuter un code différent
* dans le père et dans le fils.
*/
#include <stdio.h> /* Pour perror */
#include <stdlib.h> /* Pour exit */
#include <unistd.h> /* Pour fork, getpid, getppid, sleep */
#include <sys/types.h> /* Pour pid_t (fork, getpid, getppid) */
#include <sys/wait.h> /* Pour wait */
int main(void) {
pid_t ident;
ident = fork();
if (ident == -1) { // pb système
perror("fork");
return EXIT_FAILURE;
}
/* A partir de cette ligne, il y deux processus */
printf("Cette ligne sera affichée deux fois\n");
if (ident > 0) {
/* Code exécuté uniquement par le pere */
// sleep(2); /* le pere dort pendant 2 secondes */
printf("Je suis le père avant wait\n");
int status;
// dans la variable status seront stockés:
// le type de fin (normal ou anormal), la raison de fin, le code de retour
// https://www.geeksforgeeks.org/wait-system-call-c/
wait(&status);
// WEXITSTATUS permet d'extraire le code de retour
printf("Je suis le père après wait, le code de retour de mon fils est %d \n",WEXITSTATUS(status));
}
else {
/* Code exécuté uniquement par le fils */
//sleep(5); /* le fils dort pendant 5 secondes */
printf("Je suis le fils\n");
// soit on remplace le contenu de l'image mémoire par le programme ci dessous
//execlp("/bin/ls","ls","-al",NULL);
// soit on affiche le message suivant et on retourne un code de retour arbitraire (ici 23)
printf("Je suis le fils juste avant de mourir\n");
exit(23);
}
return EXIT_SUCCESS;
}
Minishell.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
/*
* Code issu mais adapté du tuto : https://segfault42.github.io/posts/minishell/
*/
/* Fonction qui découpe la chaine raw_cmd en un tableau de sous chaines : programme + agruments */
/* Vous n'avez pas besoin de comprendre cette fcontion */
static char **split(char *raw_cmd, char *limit)
{
char *ptr = NULL;
char **cmd = NULL;
size_t idx = 0; // size_t = entioer non signé (d'au moins 16 bits)
// split sur les espaces
ptr = strtok(raw_cmd, limit); // ca tokenise (sépare) la chaine en sous chaines séparée par un des caractères de limit
while (ptr) {
cmd = (char **)realloc(cmd, ((idx + 1) * sizeof(char *))); // grosso modo, ca essaye d'ajouter une case au tableau char*[] cmd
cmd[idx] = strdup(ptr); // on stocke dans la case idx du tableau cmd, le pointeur vers une copie de la chaine
ptr = strtok(NULL, limit); // on passe au token suivant
++idx;
}
// On alloue un element qu'on met a NULL a la fin du tableau
cmd = (char **)realloc(cmd, ((idx + 1) * sizeof(char *)));
cmd[idx] = NULL;
return (cmd);
}
/* Fonction pour libérer la mémoire occupée par un tableau de chaines */
static void free_array(char **array)
{
for (int i = 0; array[i]; i++) {
free(array[i]);
array[i] = NULL;
}
free(array);
array = NULL;
}
/* Fonction qui execute la commande contenue dans cmd[0] avec éventuellement les arguments cmd[1], ... cmd[n].
* La commande est exécutée dans un nouveau processus (créé via fork). La commande est chargée via execve.
* Le processus père attend la fin de l'exécution de la commande avant de redonner la main
*/
static void exec_cmd(char **cmd)
{
pid_t pid = 0;
int status = 0;
// On fork
pid = fork();
if (pid == -1)
perror("fork");
// Si le fork a reussit, le processus pere attend l'enfant (process fork)
else if (pid > 0) {
// On block le processus parent jusqu'a ce que l'enfant termine puis
// on kill le processus enfant
waitpid(pid, &status, 0);
kill(pid, SIGTERM);
} else {
// Le processus enfant execute la commande ou exit si execve echoue
if (execve(cmd[0], cmd, NULL) == -1)
perror("shell");
exit(EXIT_FAILURE);
}
}
/* Programme principal du shell avec la boucle*/
int main()
{
char buffer[2048];
char **cmd = NULL;
// ecriture d'un prompt sur la sortie standard i.e. 1
write(1, "$> ", 3);
// lecture de STDIN en boucle
// si on lit quit (+ retour à la ligne) , on sort
while ( strcmp(fgets(buffer, sizeof(buffer)-1, stdin) ,"quit\n") != 0 ) {
/*printf("cmd = %s\n", buffer);
write(1, "$> ", 3);*/
cmd = split(buffer, " \n\t");
// Execute la commande en faisant un fork (voir ci-dessus la fonction exec_cmd(...) */
if (cmd[0] != NULL)
exec_cmd(cmd);
// ecriture d'un prompt sur la sortie standard i.e. 1
write(1, "$> ", 3);
free_array(cmd);
}
printf("Bye \n");
}