2016-03-22 1 views
2

Mon programme mini-shell accepte la commande pipe, par exemple, ls -l | wc -l et utilise excevp pour exécuter ces commandes.La fonction Tuyau dans le shell Linux est cochée C

Mon problème est qu'il n'y a pas de fork() pour execvp, la commande pipe fonctionne bien mais le shell se termine par la suite. S'il y a un fork() pour execvp, une boucle morte se produit. Et je ne peux pas le réparer.

code:

void run_pipe(char **args){ 
    int ps[2]; 
    pipe(ps); 

    pid_t pid = fork(); 
    pid_t child_pid; 
    int child_status; 

    if(pid == 0){ // child process 

     close(1); 
     close(ps[0]); 
     dup2(ps[1], 1); 

     //e.g. cmd[0] = "ls", cmd[1] = "-l" 
     char ** cmd = split(args[index], " \t"); 

     //if fork here, program cannot continue with infinite loop somewhere 
     if(fork()==0){ 
      if (execvp(cmd[0],cmd)==-1){ 
       printf("%s: Command not found.\n", args[0]); 
      } 
     } 
     wait(0); 
    } 
    else{ // parent process 

     close(0); 
     close(ps[1]); 
     dup2(ps[0],0); 

     //e.g. cmd[0] = "wc", cmd[1] = "-l" 
     char ** cmd = split(args[index+1], " \t"); 

     //if fork here, program cannot continue with infinite loop somewhere 
     if(fork()==0){ 
      if (execvp(cmd[0],cmd)==-1){ 
       printf("%s: Command not found.\n", args[0]); 
      } 
     } 
     wait(0); 
     waitpid(pid, &child_status, 0); 
    }  
} 

Je sais fork() est nécessaire pour excevp afin de ne pas mettre fin au programme shell, mais je ne peux toujours pas le réparer. Toute aide sera appréciée, merci!


Comment devrais-je faire deux enfants en parallèle?

pid = fork(); 
if(pid == 0){ 
    // child 
} else{ // parent 
    pid1 = fork(); 
if(pid1 == 0){ 
    // second child 
} else // parent 

} 

est-ce correct?

+0

Vous êtes 'fork()' deux fois. On ne sait pas ce que fait le premier enfant (parent du deuxième enfant) après le 'wait()' s pour son enfant, car il revient simplement de cette fonction. Postez plus de code ou expliquez pourquoi vous avez 'fork()' deux fois. – EOF

+0

Notez que 'dup2()' ferme automatiquement le nouveau descripteur de fichier s'il est déjà ouvert, il n'est donc pas nécessaire de 'close()' ce FD d'abord. Il n'est pas faux de le faire si vous savez que FD doit être ouvert, mais en le fermant explicitement d'abord insère un appel de fonction supplémentaire dont vous devriez vérifier la valeur de retour. –

Répondre

2

Oui, execvp()remplace le programme dans lequel il est appelé avec un programme différent. Si vous voulez générer un autre programme sans mettre fin à l'exécution de celui qui génère (c'est-à-dire un shell), ce programme doit fork() créer un nouveau processus et faire en sorte que le nouveau processus exécute le execvp().

Votre source de programme présente un faux parallélisme qui probablement vous trouble ou reflète une confusion plus profonde. Vous structurez le comportement du premier enfant de la même manière que le comportement du processus parent après la fourche, mais devrait être parallèle est le comportement du premier enfant et le comportement du deuxième enfant. Un résultat est que votre programme a trop de fourches. Le processus initial doit se diviser exactement deux fois - une fois pour chaque enfant qu'il veut engendrer - et aucun des deux enfants ne doit bifurquer car c'est déjà un processus dédié à l'une des commandes que vous voulez exécuter. Dans votre programme actuel, cependant, le premier enfant fait une fourchette. Ce cas est probablement sauvé par l'enfant aussi pour le petit-fils, mais c'est une mauvaise forme. Un autre résultat est que lorsque vous définissez les descripteurs de fichiers du deuxième enfant, vous manipulez les parents, avant de les forger, au lieu de manipuler ceux de l'enfant après le forking. Ces changements persisteront dans le processus parent, dont je suis assez confiant n'est pas ce que vous voulez. C'est probablement pourquoi le shell semble se bloquer: quand run_pipe() retourne (l'entrée standard du shell a été changée à l'extrémité de lecture du tuyau).

En outre, le processus parent doit fermer à la fois extrémités de la canalisation après que les enfants ont tous deux été fourchus, pour plus ou moins la même raison que les enfants doivent chacun fermer la fin qu'ils n'utilisent pas. À la fin, il y aura exactement une copie ouverte du descripteur de fichier pour chaque extrémité du tuyau, un dans un enfant et l'autre dans l'autre. Ne pas le faire correctement peut également provoquer un blocage dans certaines circonstances, car les processus que vous bifurquez ne peuvent pas se terminer.

Voici un résumé de ce que vous voulez que le programme à faire:

  • Le processus original met en place le tuyau.
  • Le processus d'origine forks deux fois, une fois pour chaque commande.
  • Chaque sous-processus manipule ses propres descripteurs de fichiers pour utiliser l'extrémité correcte du tube en tant que FD standard approprié et ferme l'autre extrémité du tube.
  • Chaque sous-processus utilise execvp() (ou l'une des autres fonctions dans cette famille) pour exécuter le programme demandé
  • le parent ferme ses copies des descripteurs de fichiers pour les deux extrémités de la conduite
  • le parent utilise wait() ou waitpid() pour recueillir deux enfants.

Notez aussi que vous devriez vérifier les valeurs de retour de tous vos appels de fonction et de fournir un traitement approprié pour les erreurs.

+0

J'ai modifié la question. S'il vous plaît regarder à nouveau. Merci beaucoup. – whatthekey