Examen de Systèmes II
Licence - Juin 2000

Exercice

Soient les programmes suivants :
/* Programme 1 */
int main() {
  main();
}
/* Programme 2 */
int main() {
  while (1) fork();
}
/* Programme 3 */
int main(int argc,char *argv[]) {
  execvp(argv[0],argv);
}
Décrivez le comportement de chacun de ces programmes.

Exercice

Soient les deux programmes suivant :
/* Programme p1.c */
void ma_fonction(int signal_recu) {
  printf("J'ai bien recu le signal %d\n",signal_recu);
}

int main(int argc,char *argv[]) {
  struct sigaction action; pid_t pid; int retour;

  action.sa_handler = ma_fonction; sigemptyset(&(action.sa_mask)); action.sa_flags = 0;
  sigaction(SIGUSR1,&action,NULL);
  switch (pid=fork()) {
  case -1: fprintf(stderr,"Rate\n"); exit(EXIT_FAILURE);
  case 0:  execlp("p2","p2",NULL); fprintf(stderr,"Fils rate\n"); exit(EXIT_FAILURE);
  default: kill(getpid(),SIGUSR1); kill(pid,SIGUSR1); wait(&retour);
  }
  if (WIFEXITED(retour)) {
    printf("Le fils a pour code de retour %d\n",WEXITSTATUS(retour));
  } else if (WIFSIGNALED(retour)) {
    printf("Le fils est mort apres avoir recu %d\n",WTERMSIG(retour));
  } else {
    printf("Le fils a ete suspendu apres avoir recu %d\n",WSTOPSIG(retour));
  }
  exit(EXIT_SUCCESS);
}
/* Programme p2.c */
#include <stdlib.h>
#include <stdio.h>

void ma_fonction(int signal_recu) {
  printf("J'ai bien recu le signal %d\n",signal_recu);
  exit(EXIT_SUCCESS);
}

int main(int argc,char *argv[]) {
  while (1) pause();
  exit(EXIT_SUCCESS);
}
Le lancement de la commande p1 produit un résultat commençant par :
J'ai bien recu le signal 16
1.
Quel programme affiche ce résultat (p1, p2) ?
2.
Comment se termine le processus fils ?
3.
Quelles sont la/les autre(s) sortie(s) produite(s) ?
4.
Si p2 n'est pas accessible quel est le résultat produit ?

Exercice

Soit le manuel suivant :
NAME
     popen, pclose - créé un tube sur une commande shell

SYNOPSIS
     #include <stdio.h>

     FILE *popen(const char *command, const char *type);

     int pclose (FILE *stream);

DESCRIPTION

     La fonction popen()  créé un tube anonyme entre  le processus appelant et
     la  commande  à  exécuter.  <<  command  >>  est  une ligne  de  commande
     shell. <<  type >>  est le mode  d'entrée/sortie à utiliser,  ses valeurs
     sont r pour lire ou w pour écrire. La valeur renvoyée est un pointeur sur
     un flux représentant l'entrée standard de la commande (si le mode est w),
     ou représentant la sortie standard de la commande (si le mode est r).

     La commande est invoquée par l'intermédiaire d'un shell (bourne ou korn)
     en utilisant l'option suivante :

         <shell> -c <ligne_de_commande>
         Exemple : /bin/sh -c "ls *.c"

     D'autre part,  le flux ouvert par  popen() doit être  fermé par pclose(),
     qui ferme le tube, attends que le processus associé termine et renvoie le
     code de retour de l'interpréteur de commande.
1.
Écrivez le code de la fonction popen().
2.
Écrivez le code de la fonction pclose().

Problème

On se propose de d'implanter une fonctionnalité << similaire >> aux tubes anonymes d'UNIX en utilisant les segments de mémoire partagée.

Cette mémoire de taille (LONGMAXTUBE) sera << circulaire >> comme le suggère le dessin ci-dessous :


\begin{figure}
\psfig{file=tube.eps,width=8cm}\end{figure}

Les données présentes dans le tube sont représentées en gris. Le pointeur << début >> est l'adresse du premier octet des données. Le pointeur << fin >> est l'adresse du premier octet libre situé après les données. L'ajout de nouvelles données s'effectue à partir du pointeur << fin >> et la lecture (destructrice) à partir du pointeur << début >>.
1.
Si les deux processus tentent d'accéder concurremment à cette << structure >> quels sont les problèmes qui se posent ? Une lecture et une écriture ? Deux lectures ? Deux écritures ? Comment résoudre le problème ?
2.
La manipulation de cet objet se fera par l'intermédiaire des fonctions suivantes : réalisant les opérations non-bloquantes de lecture et écriture dans le tube. Définissez le type tube.
3.
Écrire la fonction ssize_t lit_tube_non_bloquant(tube t,void *buf,size_t lg) qui renverra -1 si le tube est vide et le nombre d'octets lus sinon.
4.
Écrire la fonction ssize_t ecrit_tube_non_bloquant(tube t,void *buf,size_t lg) qui renverra -1 si la place libre dans le tube n'est pas suffisante pour écrire les données et lg sinon.
5.
Écrire les fonctions tube cree_tube() et int ferme_tube().
6.
En quoi le mode bloquant est-il plus << difficile >> à réaliser ?
7.
Que doit-on modifier pour que le tube ne soit plus anonyme ?


Jean-Baptiste Yunes
2000-06-26