Previous Up Next

2  Implantation d’un gestionnaire de travaux


Exercice 2
 (Structures de données pour les jobs et fonctions associées)   La gestion des différents jobs nécessite de maintenir des informations sur chaque job. Un job est identifié par son pid ou bien son job id, ces numéros lui sont attribués à son lancement. Ainsi, par exemple, le job xeyes de la session shell montrée précédemment a pour pid 503 et pour job id 2. De plus, a tout moment, on a besoin de savoir si le job est exécuté en arrière-plan (BG), en avant-plan (FG) ou s’il est stoppé (ST).

Proposez des structures de données pour représenter toutes ces informations. De plus, proposez un ensemble de fonctions permettant de manipuler ces structures.

Traitants de signal

Il est nécessaire de rediriger les signaux SIGINT, SIGTSTP et SIGCHLD envoyés au mini-shell par le système. Un signal SIGINT est envoyé à chaque fois que l’utilisateur fait un control-C au clavier. Un signal SIGTSTP est envoyé lors d’un control-Z. Enfin le signal SIGCHLD est envoyé à chaque fois que l’exécution d’un programme lancé dans le mini-shell a terminé ou a été bloquée.


Exercice 3
   Donnez l’implémentation du traitant de signal pour SIGINT :
void sigint_handler(int sig);
Ce traitant redirige le signal vers le processus qui est en avant-plan afin de provoquer sa terminaison.

Exercice 4
   Donnez l’implémentation du traitant de signal pour SIGTSTP :
void sigstp_handler(int sig);
Ce traitant redirige le signal vers le processus qui est en avant-plan afin de le suspendre.

Exercice 5
   Donnez l’implémentation du traitant de signal pour SIGCHLD :
void sigchld_handler(int sig);
Ce traitant recherche tous les jobs terminés ou stoppés. Il détermine si le job a été stoppé, terminé par un signal ou a terminé normalement son exécution. Selon les cas, les structures de données sont mises à jour de façon appropriée et un message est affiché sur la sortie standard pour renseigner sur l’état du job.

Exercice 6
   Il est nécessaire d’installer ces traitants de signal pour personnaliser le traitement des signaux SIGINT, SIGTSTP et SIGCHLD. Donnez l’implémentation de la fonction signal_wrapper()
typedef void handler_t(int);
int signal_wrapper(int signum, handler_t *handler);
qui permet d’associer un traitant à un signal donné.

Organisation du code du gestionnaire de travaux

Les fichiers sources d’un squelette de l’implantation d’un gestionnaire de travaux sont disponibles dans cette archive. Vous y trouverez :

A priori, vous n’avez à modifier que les fichiers cmd.c et sighandlers.c. Les squelettes des fonctions à implémenter sont déjà donnés ; aucune autre fonction n’est nécessaire.


Le mini-shell peut fonctionner en mode verbose (mshell -v) ce qui permet d’avoir des informations sur les handlers, fonctions sollicités, etc. Une variable globale verbose est prévue à cet effet. Pensez à l’utiliser ! Le fichier jobs.c contient un exemple de son utilisation, à vous de voir selon les situations quelles informations afficher.

Commandes du mini-shell

Le mini-shell offre un certain nombre de commandes :


Exercice 7
   La commande fg est invoquée soit par fg pid ou fg jid

Le prototype de la fonction implémentant la commande fg est le suivant :

void do_fg(char **argv);

argv contient la chaîne de caractères correspondant à la commande tapée dans le mini-shell, comme par exemple "fg %1". Une fonction treat_argv() est mise à votre disposition pour chercher un job dans la liste des travaux en fonction d’un pid ou d’un jid. Son prototype est :

struct job_t * treat_argv(char **argv);

La valeur NULL est retournée si aucun job n’a été trouvé.


Lorsqu’un job est exécuté en avant-plan, l’utilisateur n’a pas la main. Pour pouvoir implémenter ce comportement, écrivez une fonction

void waitfg(pid_t pid)

qui bloque tant le job pid n’est pas mis en arrière-plan.

La fonction do_fg() envoie le signal approprié au job qui doit être passé en avant-plan, met à jour les informations associées au job et bloque tant que le job n’est pas passé en arrière-plan. Donnez son implémentation.

Les commandes bg, stop et kill sont invoquées sur le même modèle que fg et sont respectivement implémentées par :

void do_bg(char **argv);
void do_stop(char **argv);
void do_kill(char **argv);

Donnez leurs implémentations.


Exercice 8
   La commande exit permet de sortir du mini-shell. Le prototype de la fonction qui implémente exit est le suivant :
void do_exit();
Inspirez-vous du comportement du shell que vous utilisez habituellement (cette remarque est d’ailleurs aussi valable pour toutes les autres commandes). Par exemple, que se passe-t-il lorsque vous faites un exit dans un shell alors qu’un job de ce shell est arrêté ?

Exercice 9
   La commande jobs affiche l’état de tous les jobs lancés dans le mini-shell, voyez l’exemple donné en début de document.

La fonction qui implémente cette commande a pour prototype :

void do_jobs();

Implémentez cette fonction.


Previous Up Next