Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erickedji/1350956 to your computer and use it in GitHub Desktop.
Save erickedji/1350956 to your computer and use it in GitHub Desktop.
Exercices de la séance 4 - TP Systèmes Centralisés
/* Time-stamp: <02 Sep 2008 10:32 queinnec@enseeiht.fr> */
/* 8.1 */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define TAILLE 512
/* Copie le contenu du (descripteur de) fichier `desc' sur la sortie standard.
* La lecture est effectuée par bloc de TAILLE octets.
*/
void recopie (int desc)
{
char buf[TAILLE];
int n;
while ((n = read (desc, buf, TAILLE)) > 0) {
/* read peut lire moins que le nombre d'octets demandés, en
* particulier lorsque la fin du fichier est atteinte. */
if (write (1, buf, n) == -1) {
perror ("write");
exit (1);
}
}
/* Ici, (n == 0) or (n == -1).
* 0 signifie fin du fichier atteinte, -1 un problème. */
if (n == -1) {
perror ("read");
exit (1);
}
}
int main (int argc, char *argv[])
{
int i, d;
if (argc == 1) {
recopie (0); /* pas d'argument: recopie l'entrée standard */
} else {
for (i = 1; i < argc; i++) {
d = open (argv[i], O_RDONLY);
if (d == -1) {
fprintf (stderr, "Impossible d'ouvrir le fichier ");
perror (argv[i]);
exit (2);
}
recopie (d); /* recopie chacun des fichiers en arguments */
close (d);
}
}
exit (0);
}
/* Time-stamp: <02 Sep 2008 10:33 queinnec@enseeiht.fr> */
/* 8.2 */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
/* Uniquement cp f1 f2.
* On utilise cat pour recopier f1 sur la sortie standard, en faisant
* en sorte que cette sortie standard soit le fichier f2.
*/
int main (int argc, char *argv[])
{
int d;
if (argc != 3) {
fprintf (stderr, "Mauvais nombre de parametres\n");
exit (1);
}
d = open (argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (d == -1) {
fprintf (stderr, "Creation fichier %s impossible :", argv[2]);
perror (" ");
exit (2);
}
if (dup2 (d, 1) == -1) {
perror ("dup2");
exit (3);
}
if (close (d) == -1) {
perror ("close");
exit (4);
}
execl ("exo1p23_cat", "ex_cat", argv[1], NULL);
perror ("exec");
exit (5);
}
/* Time-stamp: <02 Sep 2008 10:35 queinnec@enseeiht.fr> */
/* 8.3 who | grep toto | wc -l */
/* Structure:
* père : wc,
* fils : grep,
* petit-fils: who.
*
* Le shell considère que l'exécution d'un programme est terminée quand
* le processus qu'il a créé pour l'exécuter est terminé (il affiche alors
* le prompt et est prêt à recevoir de nouveaux ordres). Il est donc
* important que ce soit le dernier élément de la chaîne qui soit exécuté
* par le processus père.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
int p[2], q[2];
int n, m;
if (argc != 2) {
fprintf (stderr, "Mauvais nombre de parametres.\n");
exit (2);
}
if (pipe (p) == -1) {
perror ("pipe");
exit (1);
}
n = fork ();
if (n == -1) {
perror ("fork");
exit (1);
}
if (n == 0) { /* fils: debut |... */
close (p[0]);
dup2 (p[1], 1);
close (p[1]);
if (pipe (q) == -1) { /* debut = who | grep */
perror ("pipe");
exit (1);
}
m = fork ();
if (m == -1) {
perror ("fork");
exit (1);
}
if (m == 0) { /* petit-fils: who|... */
close (q[0]);
dup2 (q[1], 1);
close (q[1]);
execlp ("who", "who", NULL);
perror ("exec who");
exit (1);
} else { /* fils : ...|grep */
close (q[1]);
dup2 (q[0], 0);
close (q[0]);
execlp ("grep", "grep", argv[1], NULL);
perror ("exec grep");
exit (1);
}
} else { /* pere : ...|wc */
close (p[1]);
dup2 (p[0], 0);
close (p[0]);
execlp ("wc", "wc", "-l", NULL);
perror ("exec wc");
exit (1);
}
}
/* Time-stamp: <02 Sep 2008 10:37 queinnec@enseeiht.fr> */
/* 8.3 who | grep toto | wc -l */
/* Structure:
* père : wc,
* fils 1: who,
* fils 2: grep.
*
* Le shell considère que l'exécution d'un programme est terminée quand
* le processus qu'il a créé pour l'exécuter est terminé (il affiche alors
* le prompt et est prêt à recevoir de nouveaux ordres). Il est donc
* important que ce soit le dernier élément de la chaîne qui soit exécuté
* par le processus père.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
int p[2], q[2];
int n, m;
if (argc != 2) {
fprintf (stderr, "Mauvais nombre de parametres.\n");
exit (2);
}
if (pipe (p) == -1) {
perror ("pipe");
exit (1);
}
n = fork ();
if (n == -1) {
perror ("fork");
exit (1);
}
if (n == 0) { /* fils 1: who|... */
close (p[0]);
dup2 (p[1], 1);
close (p[1]);
execlp ("who", "who", NULL);
perror ("exec who");
exit (1);
} else { /* pere: ...|suite */
close (p[1]);
dup2 (p[0], 0);
close (p[0]);
if (pipe (q) == -1) { /* suite = grep|wc */
perror ("pipe");
exit (1);
}
m = fork();
if (m == -1) {
perror ("fork");
exit (1);
}
if (m == 0) { /* fils2 : grep|... */
close (q[0]);
dup2 (q[1], 1);
close (q[1]);
execlp ("grep", "grep", argv[1], NULL);
perror ("exec grep");
exit (1);
} else { /* pere: ...|wc */
close (q[1]);
dup2 (q[0], 0);
close (q[0]);
execlp ("wc", "wc", "-l", NULL);
perror ("exec wc");
exit (1);
}
}
/* NOTREACHED */
}

Quand un pipe est ouvert, et que le descripteur associé à un bout d'écriture (desc[1]) reste ouvert dans un processus, le système attendra que ce processus ferme ce descripteur (après y avoir éventuellement écrit), pour signifier qu'il a fini d'y écrire.

Conséquence: Quand on créé des processus fils, ou qu'on duplique des descripteurs, il faut fermer systématiquement tous ceux qu'on n'utilise pas dans le processus courant.

En TP, sur certaines machines, pour l'exercice 3, les deux pipes p et q étaient créés dès l'entrée dans le programme principal (pipe(p); pipe(q);). Or, seul le pipe p a été fermé ensuite dans le programme principal, ce qui fait que le système est toujours en attente d'écriture sur q[1] (d'où la non terminaison constatée chez certains).

Il faut soit fermer explicitement le pipe q (utilisé pour la communication entre le fils et le petit-fils) dans le programme principal (père), ou créer ce pipe seulement dans le fils.

Pour rappel, en TP, on avait deux pipes p et q, et trois processus: père, fils, petit-fils. Le pipe q permettait de communiquer entre le père (wc -l) et le fils (grep <user>). Le pipe p permettait de communiquer entre le petit fils (who) et le fils (grep <user>). Ceci correspond à exo3p23_wgw_v1.c.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment