Signaux
Shell et signaux
Lors d'un TP précédent, vous avez implémenté un shell permettant d'exécuter des commandes. Le but de cet exercice est d'étendre ce shell en y ajoutant la gestion de certains signaux.
Pour commencer, téléchargez l'archive shell.tgz, extrayez la et vérifiez que le code fourni fonctionne. Ce code est inspiré du corrigé du TP shell, avec quelques modifications pour simplifier le fonctionnement du présent TP.
Terminaison du shell avec exit
Pour commencer, on souhaite "nettoyer" les processus lorsque le shell se termine. Pour cela, ajoutez une fonction void kill_pending_processes() qui parcourt la liste des processus en cours d'exécution (stockée dans la liste struct process* processes définie au début du fichier) en envoie le signal SIGINT à chacun d'entre eux. Après avoir envoyé SIGINT à un processus, il est nécessaire d'attendre sa terminaison avec waitpid et d'appeler complete_process pour supprimer le processus de la liste des processus en cours d'exécution.
Modifiez la fonction main pour qu'elle appelle kill_pending_processes lorsque l'utilisateur lance la commande exit.
Terminaison du shell avec Ctrl-C
On souhaite que la fonction kill_pending_processes soit appelée lorsque l'utilisateur arrête le shell avec Ctrl-C.
Modifiez le programme pour qu'il exécute void handle_signal(int signo) lorsqu'il reçoit le signal SIGINT. Si cette fonction est appellée avec signo == SIGINT, elle doit appeler kill_pending_processes, puis terminer le processus courant en appelant exit().
Suppression des tâches trop longues (1/2)
Certaines commandes peuvent s'exécuter pendant très longtemps, et on souhaite maintenant tuer les processus qui s'exécutent pendant trop longtemps. Pour cela, on fixe une durée limite pour chaque commande (ici la limite est de 2.5 s) et on demande au système d'exploitation de générer un signal une fois passé ce délai. Lorsque le shell reçoit ce signal, il parcourt la liste des processus en cours d'exécution et envoie SIGINT à tous ceux ayant atteint la date de péremption.
Modifiez la structure struct process pour y ajouter un champs struct timespec start_time. Dans la fonction execute_command, ajoutez un appel à clock_gettime pour initialiser ce champs avec la date actuelle. Modifiez également la fonction complete_process pour qu'il affiche la durée qui s'est écoulée entre le début et la fin du processus:
Suppression des tâches trop longues (2/2)
Pour faire en sorte d'arrêter les processus trop longs, programmez une alarme dans 2.5 secondes (en utilisant setitimer) lors de l'exécution d'une commande. La fonction setitimergénèrera le signal SIGALARM lorsque le temps imparti sera écoulé.
Interceptez ce signal avec la foncion handle_signal. Lorsque ce signal est reçu, la fonction doit parcourir la liste des processus (stockée dans processes) et envoyer le signal SIGINT à tous ceux qui ont été démarré il y a plus de 2.5 secondes.