Corrigé de l'examen de systèmes I (licence - Janvier 2001)

Exercice

La séquence montre qu'il est possible d'obtenir la liste des références contenues dans le répertoire rep (droit de lecture sur le répertoire). La seconde commande tente d'obtenir des informations descriptives sur les références contenues. Pour cela elle doit effectuer un appel à stat() en utilisant la référence de chacun des objets, rep/f1 et rep/f2. La présence d'un répertoire dans un chemin d'accès n'est autorisée qu'à condition que le droit de le traverser soit présent (droit d'exécution). Par conséquent on peut affirmer que le répertoire est ouvert en lecture mais pas en exécution pour l'utilisateur considéré.

Exercice

L'exécutable a (dans le cas où aucune erreur n'est produite) a pour effet d'ouvrir en écriture le fichier f tout en le vidant de son contenu, puis d'y écrire 100000 exemplaires du premier caractère de la commande.

  1. La commande permet d'obtenir un nouveau lien b sur l'inoeud référencé par a.
    1. La commande exécute en concurrence deux exemplaires de la commande a. Quel que soit l'ordonnancement choisi 100000 caractères a seront placés dans le fichier préalablement vidé. Évidemment la dernière commande à exécuter l'appel à open() aura effacé les caractères déjà écrits par l'autre, mais comme elles écrivent la même chose pour finir rien ne sera visible. De plus même si la dernière opération de troncature crée un fichier à trous (puisque qu'une autre commande continue d'écrire dans le fichier avec une position déjà avancée), les trous seront tous bouchés grâce aux écritures séquentielles.
    2. Cette commande exécute en concurrence la commande a chargée d'écrire 100000 a et la commande b chargée d'écrire 100000 b. Le contenu de f sera probablement un mélange de caractères a et b pour un total de 100000. En effet il est possible (et fortement probable) que les processus se doublent. On aura par exemple l'exécution suivante :
      • a appelle open() et vide le fichier
      • a appelle write() et écrit un a en première position (le fichier contient a)
      • a appelle write() et écrit un a en seconde position (le fichier contient aa)
      • b appelle open() et vide le fichier (le fichier est vide)
      • a appelle write() et écrit un a en troisième position (le fichier contient <NUL><NUL>a)
      • b appelle write() et écrit un b en première position (le fichier contient b<NUL>a)
      • b appelle write() et écrit un b en deuxième position (le fichier contient bba)
      • b appelle write() et écrit un b en troisième position (le fichier contient bbb)
      • b appelle write() et écrit un b en quatrième position (le fichier contient bbbb)
      • a appelle write() et écrit un a en quatrième position (le fichier contient bbba)
      • etc.

      Dans ce cas, quelle que soit la suite des événements le fichier commencera par bbba.

  2. Maintenant il existe une nouvelle commande b (différente de a) qui tronque le fichier f à l'ouverture, mais effectue des écritures en mode ajout (écriture systématiquement réalisée en fin de fichier). Dans la suite on notera Ti l'opération de troncature réalisée par la commande i, et i l'opération d'écriture du caractère i par la commande i.
    1. Dans ce cas, il est possible que des caractères a écrasent des b (mais pas l'inverse!). En effet, la trace d'exécution suivante est possible : TaTbbbaaab... ce qui donne pour la trace du contenu du fichier correspondant : (vide),(vide),(b),(bb),(ab),(aa),(aaa),(aaab),...

      Dans ce cas, on constate que des b ont bien été recouverts par des a. L'inverse n'est pas possible car les b sont toujours écrits après la dernière position. On peut donc affirmer qu'au moins 100000 caractères seront présents dans le fichier (cas dans lequel tous les b sont recouverts par des a, le fichier contiendrait alors "a100000") et qu'au plus 200000 caractères seront présents (cas dans lequel aucun b n'a été recouvert, le fichier contiendrait "a100000b100000").

      Si aucun a ne peut être recouvert par un b cela ne signifie pas pour autant que des b ne puisse pas apparaître (dans le résultat) avant des a, car il ne faut pas oublier que des a écrits peuvent être effacés par l'opération de troncature de la commande b.

      On définit informellement de la façon suivante une trace correcte possible :

      • il n'apparaît pas d'opération i avant Ti (on ne peut écrire avant d'avoir ouvert le fichier)
      • le nombre d'opération i est égal à 100000 (on réalise toutes les écritures)

      Les traces peuvent donc être de deux sortes :

      TaaiTbbja...
      Deux cas se présentent :
      i<=j
      Les i premiers a sont effacés par l'opération Tb qui vide le fichier, ensuite certains b (j>=i) sont écrits puis un a en position i+1 et enfin le reste (des a et des b avec d'éventuels recouvrements). Dans ce cas on obtient un fichier contenant "bia100000-ibk" avec k<10000-j (la différence 100000-k-j est le nombre de recouvrements).
      j<=i
      Les i premiers a sont effacés par l'opération Tb qui vide le fichier, ensuite certains b (j<=i) puis un a en position i+1 (laissant des caractères nuls entre j+1 et i compris), enfin le reste (des a et des b avec d'éventuels recouvrements). Dans ce cas on obtient un fichier contenant "bj<nul>i-ja100000-ibk" avec k<100000-j (la différence est le nombre de recouvrements).
      TbbiTa...
      Les i premiers b sont effacés par l'opération Ta, ensuite seront écrits des a et des b avec d'éventuels recouvrements. Dans ce cas on obtient un fichier contenant "a100000bk" avec k<N-i (la différence étant le nombre de recouvrements).
    2. Dans ce cas on obtiendra au moins 100000 et au plus 200000 b dans le fichier. Ici on peut remarquer qu'il n'y a jamais de recouvrement, seuls certains caractères peuvent avoir été effacés lors de l'opération de troncature.
    1. La commande affiche le nombre de caractère lus dans le fichier f par la commande c laquelle est en concurrence avec la commande a qui construit le fichier f. S'il n'est pas possible de lire plus de 100000 caractères, il est envisageable d'en lire moins, pour cela il suffit que la commande c atteigne la fin du fichier avant que a n'ait terminé.
    2. Il est très difficile de dire exactement qu'elle sera son effet, mais il est fort probable que plus sa valeur sera grande moins le nombre de caractères lus dans le fichier sera important. L'effet aurait été bien plus visible si la condition d'arrêt avait été (l=read(d,c,LG))==LG (on aurait supposé que si moins de LG caractères sont lus alors il n'y en aura plus ensuite!).

Exercice

Tout d'abord il faut remarquer que le programme p copie caractère par caractère le fichier donné en premier argument dans le second. Les ouvertures sont effectuées dans l'ordre suivant : ouverture en lecture du premier puis en écriture du second.

  1. Il n'y a normalement aucun problème. Le fichier f2 contient une copie des données du fichier f1.
  2. Ici, il faut remarquer que t est un tube nommé sur lesquels les ouvertures en lecture et écriture sont synchronisées (en mode bloquant). Donc la commande qui reçoit le tube en premier paramètre et qui tente de l'ouvrir en lecture attendra que la commande qui le reçoit en second paramètre tente de l'ouvrir en écriture. Ensuite la recopie se produira par l'intermédiaire du tube (attente sur tube vide en lecture et sur tube plein en écriture).
  3. Ici, t1 et t2 sont des tubes nommés. p t1 t2 est bloquée en attente de l'ouverture en écriture de t1 par quelqu'un d'autre et p t2 t1 est bloquée en attente de l'ouverture en écriture de t2 par quelqu'un d'autre. Il y a donc une situation de blocage sur les ouvertures.
  4. Cette fois les ouvertures sont non bloquantes (en lecture pas de problème, mais en écriture il y a échec si pas de lecteur).

    Cela ne change rien à la première commande.

    Pour la seconde une erreur peut se produire si la commande qui tente d'ouvrir en écriture passe la première (pas de lecteur donc échec), alors la seconde ouvrira correctement en lecture mais échouera lors de l'appel à read(). Si les ouvertures se passent dans le bon sens, il est aussi possible que l'écrivain ne puisse pas assez vite ses données et que le lecteur se trouve face à un tube vide conduisant à une lecture de fin de fichier.

    Pour la troisième commande il n'y a plus d'interblocage à l'ouverture mais des échec divers et variés peuvent se produire soit sur une ouverture en écriture sans lecteur (terminaison), soit lecture sur tube vide (fin de fichier). On peut noter que rien ne circulera dans les tubes puisqu'aucune lecture n'aboutira...

L'auteur de cette page est : Jean-Baptiste Yunès

Valid XHTML 1.0!Valid CSS!W3C-Amaya