[C] cas d'école : réécriture des pipes bash : chui pas loin...

cas d'école : réécriture des pipes bash : chui pas loin... [C] - C - Programmation

Marsh Posté le 27-03-2005 à 17:30:38    

Chui pas loin, mais c'est pas ça...
 
donc en gros mon problème de cours (évidemment, c'est pas pour le plaisir...), c'ets de réécrire le fonctionnement des pipes uni (|) en C. En gros, il faudrait que  

Citation :

monProg -m /bin/ls -m /bin/cat

donne la même sortie que

Citation :

/bin/ls | /bin/cat

(je vous prend pas pour des buses, je veux juste être clair).
 
Avec ce que j'ai déjà fait, ça marche avec une commande (cool), presque avec deux (pas mal) et pas du tout avec 3. Parce que avec 2, ça marche que presque, parce que le programme ne se fini pas, il ne retourne pas sous le shell, du coup, avec trois, ça ne passe jamais au troisième, ça bloque à la fin du deuxième...
 
Mon code n'est pas forcement clair, étant donné que le C, c'est pas mon point fort, je suis prèt pour les critiques.
 
La question : pourquoi ça bloque à après la deuxième mutation ?!
 

Code :
  1. int main(int argc, char ** argv){
  2. int i;
  3. int pid;
  4. int ppid;
  5. int tube [2];
  6. int status;
  7. char * cmd;
  8. //limite arbitraire
  9. char * param[8];
  10. int j;
  11. ppid = getppid();
  12. if (pipe(tube)!=0){
  13.  printf("Problème à la création du pipe.\n" );
  14.  switch (errno){
  15.   case EMFILE : printf("Trop de descripteurs de fichiers sont utilisés par le processus.\n" );break;
  16.   case ENFILE : printf("La table système pour les tubes est pleine.\n" );break;
  17.   case EFAULT : printf("Le pipe cible est invalide.\n" );break;
  18.   default : printf("Erreur improbable.\n" );
  19.  }
  20.  return(errno);
  21. }
  22. // On commence à 1, puisque l'argument 0 ne m'intéresse pas.. peut-être même pas le 1  
  23. // d'ailleurs...
  24. i=1;
  25. while (i<argc){
  26.  if (strcmp(argv[i],"-m" )==0){
  27.    if ((pid=fork())>0){
  28.     //père : ici, on dort, on attend simplement que le fils est fini
  29.    // son execution pour reprendre la boucle
  30.     waitpid(pid,&status,0);
  31.     i++;
  32.    // On cherche quel est le prochain programme à lancer
  33.     while (i<argc && strcmp(argv[i],"-m" )!=0) i++;
  34.    } else if (pid==0){
  35.    // Je ne redirige pas stdin à la première boucle, puisque dans ce  
  36.    // cas stdin reste stdin.
  37.     if (i>1)
  38.      dup2(tube[0],STDIN_FILENO);
  39.     cmd=argv[++i];
  40.    // on initialise le tableau des paramètres à NULL
  41.     for (j=0;j<8;param[j++]=NULL) ;
  42.     j=0;
  43.    // on recopie les paramètres effectifs dans le tableau
  44.     while (i<argc && strcmp(argv[i],"-m" )!=0) param[j++]=argv[i++];
  45.    // Si on est dans la dernière boucle, on ne redirige pas stdout
  46.    // Comme ça la sortie va se faire directement dans le shell
  47.    if (i<argc)
  48.      dup2(tube[1],STDOUT_FILENO);
  49.    // Je ne sais pas pourquoi je close... vu sur d'autres listings
  50.    // Je n'ai pas compris se mecanisme de fermeture... :-/
  51.    close(tube[0]);
  52.    close(tube[1]);
  53.    // On lance le programme...
  54.     execv(cmd,param);
  55.    // Si on revient là, c'est que ça a merdé, parce que les fonctions
  56.    // de type exec ne reviennent jamais à l'appellant
  57.    printf("Il y a eu une erreur !!\n" );
  58.    switch (errno){
  59.     case EACCES : printf("EACCES\n" );break;
  60.     (...)
  61.     case ELIBBAD : printf("ELIBBAD\n" );break;
  62.     default : printf("Erreur improbable !" );
  63.    }
  64.    return(errno);
  65.    } else {
  66.    printf("problème à la création du processus fils à muter.\n" );
  67.    switch (errno){
  68.     case EAGAIN : printf("Manque de mémoire pour fork.\n" );break;
  69.     case ENOMEM : printf("Manque de mémoire dans le noyau.\n" );break;
  70.     default : printf("Erreur improbable.\n" );
  71.    }
  72.    return(errno);
  73.    }
  74.  }
  75. }
  76. return(0);
  77. }


 
merci pour toute aide.
 
edit : ajouts des commentaires


Message édité par brisssou le 28-03-2005 à 18:00:13

---------------
HFR - Mes sujets pour Chrome - Firefox - vérifie les nouveaux posts des topics suivis/favoris
Reply

Marsh Posté le 27-03-2005 à 17:30:38   

Reply

Marsh Posté le 28-03-2005 à 11:38:59    

allé, vous qui l'avez lu, z'avez pas une idée ?


---------------
HFR - Mes sujets pour Chrome - Firefox - vérifie les nouveaux posts des topics suivis/favoris
Reply

Marsh Posté le 28-03-2005 à 13:47:41    

brisssou a écrit :

allé, vous qui l'avez lu, z'avez pas une idée ?


 
Putain si tu mettais des commentaires et si tu indentais un peu ça irait quand-même beaucoup mieux pour tout le monde !!!
 
Dejà les trucs bateaux:
1) Pourquoi tu limites "param" à 8 ?
2) A quoi sert "ppid" ?
Remarque je m'en fous et c'est pas important mais la question peut se poser...
 
Sinon je comprends pas trop ta logique. Pourquoi fermer les deux cotés du tube ? Pourquoi dupliquer dans certains cas l'entrée standard ou la sortie standard dans un autre cas. Commente un peu tes idées !!!
 
Petite remarque en passant: while (i<argc) au tout début te donne une boucle infinie si "i" n'est jamais incrémenté. Or, "i" ne s'incrémente que si argv[i] = "-m". C'est toujours le cas ? Il y a peut-être là une idée à creuser quand tu dis que ton programme ne s'arrête jamais...
 
PS: J'aime bien ta gestion des erreurs. Moi, je ne suis jamais allé aussi loin. Quand j'ai une erreur, j'affiche printf("%s\n", strerror(errno)) et basta.


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 28-03-2005 à 13:53:09    

Sve@r a écrit :

PS: J'aime bien ta gestion des erreurs. Moi, je ne suis jamais allé aussi loin. Quand j'ai une erreur, j'affiche printf("%s\n", strerror(errno)) et basta.


Et moi

  perror("" );


Message édité par Emmanuel Delahaye le 28-03-2005 à 13:53:32

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 28-03-2005 à 14:00:18    

Emmanuel Delahaye a écrit :

Et moi

  perror("" );



 
En fait, j'affiche plus de trucs dont, entre autres, "__LINE__" et "__FILE__" donc pour moi, "perror()" ne m'est pas utile ;) Mais tout ça ne fait pas avancer le schmiliblik...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 28-03-2005 à 17:52:30    

Sve@r a écrit :

Putain si tu mettais des commentaires et si tu indentais un peu ça irait quand-même beaucoup mieux pour tout le monde !!!
 
Dejà les trucs bateaux:
1) Pourquoi tu limites "param" à 8 ?
2) A quoi sert "ppid" ?
Remarque je m'en fous et c'est pas important mais la question peut se poser...
 
Sinon je comprends pas trop ta logique. Pourquoi fermer les deux cotés du tube ? Pourquoi dupliquer dans certains cas l'entrée standard ou la sortie standard dans un autre cas. Commente un peu tes idées !!!
 
Petite remarque en passant: while (i<argc) au tout début te donne une boucle infinie si "i" n'est jamais incrémenté. Or, "i" ne s'incrémente que si argv[i] = "-m". C'est toujours le cas ? Il y a peut-être là une idée à creuser quand tu dis que ton programme ne s'arrête jamais...
 
PS: J'aime bien ta gestion des erreurs. Moi, je ne suis jamais allé aussi loin. Quand j'ai une erreur, j'affiche printf("%s\n", strerror(errno)) et basta.


 
 
pour l'indentation, bha c'est déjà bon là je crois, c'est mon code copié/coller depuis Eclipse :-/
 
la limite à 8 est arbitraire... 2 ou 15, spareil pour moi...
 
ppid ne sert à rien, bien observé. merci.
 
Pour les commentaires, ok j'en rajoute un peu... voir le premier message, il est édité.
 
la fermeture des tubes, j'ai pas compris... j'ai copié ça sur d'autres listing où les tubes se fermaient, et d'un coup, ça a mieux marché chez moi... comment ça je tatonne ?! :o
 
la boucle possiblement infinie, c'est bien vu aussi... je vais voir si je peux corriger ça...
mais ce n'est pas ça qui faisait planter à priori, parce que le processeur n'est pas pris à 100% (indication de 'top')
 
merci en tout cas !


Message édité par brisssou le 28-03-2005 à 18:07:53

---------------
HFR - Mes sujets pour Chrome - Firefox - vérifie les nouveaux posts des topics suivis/favoris
Reply

Marsh Posté le 28-03-2005 à 19:19:51    

brisssou a écrit :

pour l'indentation, bha c'est déjà bon là je crois, c'est mon code copié/coller depuis Eclipse :-/
 
la limite à 8 est arbitraire... 2 ou 15, spareil pour moi...
 
ppid ne sert à rien, bien observé. merci.
 
Pour les commentaires, ok j'en rajoute un peu... voir le premier message, il est édité.
 
la fermeture des tubes, j'ai pas compris... j'ai copié ça sur d'autres listing où les tubes se fermaient, et d'un coup, ça a mieux marché chez moi... comment ça je tatonne ?! :o
 
la boucle possiblement infinie, c'est bien vu aussi... je vais voir si je peux corriger ça...
mais ce n'est pas ça qui faisait planter à priori, parce que le processeur n'est pas pris à 100% (indication de 'top')
 
merci en tout cas !


Excellent ! Avec tes commentaires au-moins 1) j'ai beaucoup ri 2) je comprends mieux ta logique qui est la suivante => j'y comprends rien mais jm'en fous je m'avance bravement
 
A mon avis, ton problème vient de tes tubes (hum... je m'avance pas beaucoup) mais je crois que je peux t'aider à t'en sortir. Faut juste que tu comprennes bien comment fonctionne les tubes inter-process
Un tube est un canal qui permet de faire dialoguer deux processus. Quand les processus sont liés par un "fork", on peut utiliser des tubes mémoires avec la fonction "int pipe(int cote[2]);".
Cette fonction t'ouvre un canal où les entrées/sorties sont représentées par "cote[0]" (sortie) et "cote[1]" (entrée).
Pourquoi on ferme les cotés ? En général, quand on fait communiquer un père et son fils, l'un écrit et l'autre lit. Donc le programme commence par ouvrir le tube puis génère le fils. Ensuite, comme les deux processus ont hérité chacun des deux cotés du tube mais que chacun n'en a besoin que d'un, ben il ferme l'autre. Toi, tu fermes allègrement les deux dans le fils et aucun dans le père.
De plus,  quand tu fais "dup2(tube[0], STDIN_FILENO) alors tu rediriges la sortie du tube vers le clavier alors qu'à mon avis, il faudrait rediriger le clavier dans l'entrée => dup2(STDIN_FILENO, tube[1]) mais je crois que le problème est quand-même un peu plus complexe (c'est d'ailleurs la première fois que je suis confronté à ça et je galère un peu à trouver l'idée)
 
Je crois qu'il faut que tu commences par le dernier programme et que tu remontes vers le premier. En effet, si quand tu lances "prog -m ls -m more" tu lances le "ls" en premier, ben le "ls" se déroulera connement et n'ira jamais dans le more. Alors que si tu lances le "more" en premier, ben il attendra sagement que des données lui arrivent. Evidemment, ta boucle sera moins évidente à programmer mais tu peux t'en sortir si tu commences par récupérer la liste de tous tes programmes dans un tableau. T'auras plus qu'à balayer ton tableau à l'envers.
En plus, comme t'as "n" programmes il te faut "n - 1" tubes donc le coup des tableaux c'est pas mal parce que tu peux allouer (malloc) et ouvrir (pipe) d'un coup tes "n - 1" tubes
 
Voilà ce que je propose pour ton programme
- Il stocke tous les processus à lancer et crée tous les tubes
- Il génère un fils pour chaque processus en commençant par le dernier
- Il ferme tous les tubes car il ne s'en sert pas
 
Le premier fils généré
- Il redirige STDIN_FILENO vers le cote[1] (entrée) de son propre tube
 
Chaque fils (même le premier mais pas le dernier)
- Il redirige le cote[0] (sortie) de son propre tube vers le cote[1] (entrée) du tube suivant
 
Le dernier fils
- Il redirige le cote[0] (sortie) de son propre tube vers STDOUT_FILENO
 
Tous les fils doivent, en plus, fermer les cotés de tous les tubes qu'ils n'utilisent pas. Putain, c'est pas facile à imaginer. Et je suis même pas certain que ce soit nickel. Mais c'est mon idée.


Message édité par Sve@r le 28-03-2005 à 19:20:39

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 28-03-2005 à 19:26:41    

wow !
 
je regarde tout ça, merci en tout cas...
 
mais quand même, je comprends pas pourquoi ça marche un peu mon code...
 
et puis, j'ai fait un petit top --forest, ça me donne ça :  

Code :
  1. stg1      2857  0.0  1.7  28640 15656 ?        S    17:51   0:03  \_ konsole [kdeinit] konsole --type shell
  2. stg1      2858  0.0  0.3   5848  2952 pts/1    Ss   17:51   0:00  |   \_ /bin/bash
  3. stg1      6902  0.0  0.0   1356   324 pts/1    S+   19:21   0:00  |   |   \_ ./MethodeProgTP1 -m /bin/ls -l -m /bin/grep obje -m /bin/cat
  4. stg1      6904  0.0  0.0   3388   720 pts/1    S+   19:21   0:00  |   |       \_ /bin/grep obje


 
et ça me donne ça quand ça bloque, donc en fait, c'est que grep ne fini pas...


Message édité par brisssou le 28-03-2005 à 19:35:58

---------------
HFR - Mes sujets pour Chrome - Firefox - vérifie les nouveaux posts des topics suivis/favoris
Reply

Marsh Posté le 28-03-2005 à 21:11:23    

brisssou a écrit :

wow !
 
je regarde tout ça, merci en tout cas...
 
mais quand même, je comprends pas pourquoi ça marche un peu mon code...
 
et puis, j'ai fait un petit top --forest, ça me donne ça :  

Code :
  1. stg1      2857  0.0  1.7  28640 15656 ?        S    17:51   0:03  \_ konsole [kdeinit] konsole --type shell
  2. stg1      2858  0.0  0.3   5848  2952 pts/1    Ss   17:51   0:00  |   \_ /bin/bash
  3. stg1      6902  0.0  0.0   1356   324 pts/1    S+   19:21   0:00  |   |   \_ ./MethodeProgTP1 -m /bin/ls -l -m /bin/grep obje -m /bin/cat
  4. stg1      6904  0.0  0.0   3388   720 pts/1    S+   19:21   0:00  |   |       \_ /bin/grep obje


 
et ça me donne ça quand ça bloque, donc en fait, c'est que grep ne fini pas...


Vi, le grep ne finit pas parce qu'il n'a aucune donnée à traiter.
 
Il se comporte comme si tu tapais la commande "grep obje" sans lui dire où chercher. Le grep cherche dans l'entrée standard...
 
Déjà, un premier exercice devrais t'aider :
Un père et deux fils avec le père qui envoie des données au premier fils qui les envoie au second...


Message édité par Sve@r le 28-03-2005 à 21:26:00

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 28-03-2005 à 22:56:57    

mais pourtant, si je met rien après le grep, il fonctionne. C'est là que je comprends pas en fait...


---------------
HFR - Mes sujets pour Chrome - Firefox - vérifie les nouveaux posts des topics suivis/favoris
Reply

Marsh Posté le 28-03-2005 à 22:56:57   

Reply

Marsh Posté le 29-03-2005 à 02:42:45    

brisssou a écrit :

mais pourtant, si je met rien après le grep, il fonctionne. C'est là que je comprends pas en fait...


Déjà, essaye juste avec 3 programmes en dur style "ls |sort |more".
Génère 3 fils et 2 tubes
Si ça marche, il te sera facile d'étendre à tous les programmes passés en paramètre.

Reply

Marsh Posté le 05-04-2005 à 15:07:45    

Sve@r a écrit :

Déjà, essaye juste avec 3 programmes en dur style "ls |sort |more".
Génère 3 fils et 2 tubes
Si ça marche, il te sera facile d'étendre à tous les programmes passés en paramètre.


 
Ce petit TP m'a plu et je me suis amusé à le faire.
 
Voici le source n° 1 (les programmes sont lancés dans l'ordre demandé)

Code :
  1. #include <sys/types.h>    // Types prédéfinis "c"
  2. #include <sys/wait.h>    // Attente fin de process
  3. #include <unistd.h>    // Standards Unix
  4. #include <stdio.h>    // I/O fichiers classiques
  5. #include <fcntl.h>    // Contrôle fichiers bas niveau
  6. #include <stdlib.h>    // Standard librairies
  7. // Structure qui gère les processus à lancer
  8. typedef struct {
  9. char *arg[100];    // Nom programme plus arguments
  10. int pid;    // N° processus
  11. int status;    // Code retour
  12. }t_pgm;
  13. // Structure qui gère les pipes
  14. typedef struct {
  15. int cote[2];    // Cotés du tube
  16. }t_pipe;
  17. typedef enum {lire=0, ecrire} e_cote;
  18. void fermeture(int, t_pipe*, int);  // Fermeture tubes inutilisés
  19. int main(int argc, char *argv[])
  20. {
  21. int pid;    // Pid fils
  22. int i;     // Indice de boucle
  23. int nb_process;    // Nb processus à lancer
  24. t_pipe *tabTube;   // Tableau des tubes
  25. static t_pgm tabPgm[]={
  26.  {{"cat", "/etc/passwd", NULL}, 0, 0},
  27.  {{"sort", "-r", NULL}, 0, 0},
  28.  {{"sed", "s/:/;/g", NULL}, 0, 0},
  29.  {{"sed", "s/home/maison/g", NULL}, 0, 0},
  30.  {{"tr", "'[a-z]'", "'[A-Z]'", NULL}, 0, 0},
  31.  {{NULL}, 0, 0},
  32. };     // Tableau des programmes à lancer
  33. t_pgm *ptPgm;    // Ptr balayage tabPgm
  34. // Récupérer le nb de processus
  35. for (ptPgm=tabPgm, nb_process=0; ptPgm->arg[0] != NULL; ptPgm++, nb_process++);
  36. // Création du tableau de tubes (un tube de moins que le nb de processus)
  37. if ((tabTube=(t_pipe*)malloc((nb_process - 1) * sizeof(t_pipe))) == NULL)
  38. {
  39.  perror("malloc" );
  40.  exit(-1);
  41. }
  42. // Création des tubes
  43. for (i=0; i < (nb_process - 1); i++)
  44. {
  45.  fprintf(stderr, "Création tube %d\n", i);
  46.  if (pipe(tabTube[i].cote) != 0)
  47.  {
  48.   perror("pipe" );
  49.   free(tabTube);
  50.   exit(-2);
  51.  }
  52. }
  53. // Lancement de chacun des processus
  54. for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
  55. {
  56.  switch(pid=fork())
  57.  {
  58.   case 0: // Fils
  59.    fprintf(stderr, "fils (%d) - pid=%d\n", i, getpid());
  60.    // Fermeture tubes inutilisés par ce processus
  61.    fermeture(i, tabTube, nb_process - 1);
  62.    // Pour tous les fils autres que le premier
  63.    if (i > 0)
  64.    {
  65.     // Redirection entrée venant du tube précédent
  66.     close(STDIN_FILENO);
  67.     dup2(tabTube[i - 1].cote[lire], STDIN_FILENO);
  68.    }
  69.    // Pour tous les fils autres que le dernier
  70.    if (i < (nb_process - 1))
  71.    {
  72.     // Redirection sortie sur mon tube
  73.     close(STDOUT_FILENO);
  74.     dup2(tabTube[i].cote[ecrire], STDOUT_FILENO);
  75.    }
  76.    // Lancement du processus
  77.    execvp(ptPgm->arg[0], ptPgm->arg);
  78.    exit(0);
  79.   default: // Père
  80.    tabPgm[i].pid=pid;
  81.    //sleep(1);
  82.  }
  83. }
  84. // Fermeture des tubes non utilisés par le père
  85. fermeture(-1, tabTube, nb_process - 1);
  86. // Attente de la fin de tous les processus
  87. for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
  88.  waitpid(ptPgm->pid, &ptPgm->status, 0);
  89. // Affichage de l'exécution
  90. for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
  91. {
  92.  if (WIFSIGNALED(ptPgm->status))
  93.   fprintf(stderr, "Pgm <%s> - Terminé par kill(%d)\n", ptPgm->arg[0], WTERMSIG(ptPgm->status));
  94.  else
  95.   fprintf(stderr, "Pgm <%s> - Terminé par exit(%d)\n", ptPgm->arg[0], WEXITSTATUS(ptPgm->status));
  96. }
  97. // Libération mémoire
  98. free(tabTube);
  99. return(0);
  100. }
  101. // Fonction qui ferme les tubes inutilisés
  102. void fermeture(int fils, t_pipe *tabTube, int nb_tube)
  103. {
  104. int i;     // Indice de boucle
  105. fprintf(stderr, "fermeture tubes processus(%d)\n", fils);
  106. for (i=0; i < nb_tube; i++)
  107. {
  108.  // Si on n'est pas sur le tube de notre prédécesseur
  109.  if (i != (fils - 1))
  110.  {
  111.   close(tabTube[i].cote[lire]);
  112.   fprintf(stderr, "\tfermeture(%d) %d.lire\n", fils, i);
  113.  }
  114.  // Si on n'est pas sur notre propre tube
  115.  if (i != fils)
  116.  {
  117.   close(tabTube[i].cote[ecrire]);
  118.   fprintf(stderr, "\tfermeture(%d) %d.ecrire\n", fils, i);
  119.  }
  120. }
  121. }


 
Voici le source n° 2 (les programmes sont lancés dans l'ordre inverse)

Code :
  1. #include <sys/types.h>    // Types prédéfinis "c"
  2. #include <sys/wait.h>    // Attente fin de process
  3. #include <unistd.h>    // Standards Unix
  4. #include <stdio.h>    // I/O fichiers classiques
  5. #include <fcntl.h>    // Contrôle fichiers bas niveau
  6. #include <stdlib.h>    // Standard librairies
  7. // Structure qui gère les processus à lancer
  8. typedef struct {
  9. char *arg[100];    // Nom programme plus arguments
  10. int pid;    // N° processus
  11. int status;    // Code retour
  12. }t_pgm;
  13. // Structure qui gère les pipes
  14. typedef struct {
  15. int cote[2];    // Cotés du tube
  16. }t_pipe;
  17. typedef enum {lire=0, ecrire} e_cote;
  18. void fermeture(int, t_pipe*, int);  // Fermeture tubes inutilisés
  19. int main(int argc, char *argv[])
  20. {
  21. int pid;    // Pid fils
  22. int i;     // Indice de boucle
  23. int nb_process;    // Nb processus à lancer
  24. t_pipe *tabTube;   // Tableau des tubes
  25. static t_pgm tabPgm[]={
  26.  {{"tr", "'[a-z]'", "'[A-Z]'", NULL}, 0, 0},
  27.  {{"sed", "s/home/maison/g", NULL}, 0, 0},
  28.  {{"sed", "s/:/;/g", NULL}, 0, 0},
  29.  {{"sort", "-r", NULL}, 0, 0},
  30.  {{"cat", "/etc/passwd", NULL}, 0, 0},
  31.  {{NULL}, 0, 0},
  32. };     // Tableau des programmes à lancer
  33. t_pgm *ptPgm;    // Ptr balayage tabPgm
  34. // Récupérer le nb de processus
  35. for (ptPgm=tabPgm, nb_process=0; ptPgm->arg[0] != NULL; ptPgm++, nb_process++);
  36. // Création du tableau de tubes (un tube de moins que le nb de processus)
  37. if ((tabTube=(t_pipe*)malloc((nb_process - 1) * sizeof(t_pipe))) == NULL)
  38. {
  39.  perror("malloc" );
  40.  exit(-1);
  41. }
  42. // Création des tubes
  43. for (i=0; i < (nb_process - 1); i++)
  44. {
  45.  fprintf(stderr, "Création tube %d\n", i);
  46.  if (pipe(tabTube[i].cote) != 0)
  47.  {
  48.   perror("pipe" );
  49.   free(tabTube);
  50.   exit(-2);
  51.  }
  52. }
  53. // Lancement de chacun des processus
  54. for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
  55. {
  56.  switch(pid=fork())
  57.  {
  58.   case 0: // Fils
  59.    fprintf(stderr, "fils (%d) - pid=%d\n", i, getpid());
  60.    // Fermeture tubes inutilisés par ce processus
  61.    fermeture(i, tabTube, nb_process - 1);
  62.    // Pour tous les fils autres que le premier
  63.    if (i > 0)
  64.    {
  65.     // Redirection sortie sur le tube précédent
  66.     close(STDOUT_FILENO);
  67.     dup2(tabTube[i - 1].cote[ecrire], STDOUT_FILENO);
  68.    }
  69.    // Pour tous les fils autres que le dernier
  70.    if (i < (nb_process - 1))
  71.    {
  72.     // Redirection entrée venant de mon tube
  73.     close(STDIN_FILENO);
  74.     dup2(tabTube[i].cote[lire], STDIN_FILENO);
  75.    }
  76.    // Lancement du processus
  77.    execvp(ptPgm->arg[0], ptPgm->arg);
  78.    exit(0);
  79.   default: // Père
  80.    tabPgm[i].pid=pid;
  81.    //sleep(1);
  82.  }
  83. }
  84. // Fermeture des tubes non utilisés par le père
  85. fermeture(-1, tabTube, nb_process - 1);
  86. // Attente de la fin de tous les processus
  87. for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
  88.  waitpid(ptPgm->pid, &ptPgm->status, 0);
  89. // Affichage de l'exécution
  90. for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
  91. {
  92.  if (WIFSIGNALED(ptPgm->status))
  93.   fprintf(stderr, "Pgm <%s> - Terminé par kill(%d)\n", ptPgm->arg[0], WTERMSIG(ptPgm->status));
  94.  else
  95.   fprintf(stderr, "Pgm <%s> - Terminé par exit(%d)\n", ptPgm->arg[0], WEXITSTATUS(ptPgm->status));
  96. }
  97. // Libération mémoire
  98. free(tabTube);
  99. return(0);
  100. }
  101. // Fonction qui ferme les tubes inutilisés
  102. void fermeture(int fils, t_pipe *tabTube, int nb_tube)
  103. {
  104. int i;     // Indice de boucle
  105. fprintf(stderr, "fermeture tubes processus(%d)\n", fils);
  106. for (i=0; i < nb_tube; i++)
  107. {
  108.  // Si on n'est pas sur le tube de notre prédécesseur
  109.  if (i != (fils - 1))
  110.  {
  111.   close(tabTube[i].cote[ecrire]);
  112.   fprintf(stderr, "\tfermeture(%d) %d.ecrire\n", fils, i);
  113.  }
  114.  // Si on n'est pas sur notre propre tube
  115.  if (i != fils)
  116.  {
  117.   close(tabTube[i].cote[lire]);
  118.   fprintf(stderr, "\tfermeture(%d) %d.lire\n", fils, i);
  119.  }
  120. }
  121. }


 
Les informations qu'affichent chacun de ces deux programmes sont affichées sur le canal "STDERR". On peut donc les shunter en redirigeant ce canal "2" vers "/dev/null".
 
En fait, qu'on lance les processus à l'endroit ou à l'envers, ça marche.


Message édité par Sve@r le 05-04-2005 à 15:17:06
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed