2016-03-20 11 views
1

Ich versuche, einen Shell-Simulator unter Linux zu schreiben, der einen Einzelprozessbefehl, Zweiprozess-Pipelines und E/A-Umleitung ausführen kann. Wie ich einzelne Prozess mit den folgenden richtig ausgeführt, jedoch gibt es einige Probleme mit der Pipeline.Shell-Simulator mit Pipeline- und E/A-Umleitung unter Linux

Copy_STDIO();          //Copy the stdio for the restoration. 
Redirection();          //Determine whether should do Redirection. 
Pipeline(); 
Restore_stdio();         //Restore the stdio. 

Oben ist meine Funktionen in Haupt. Zuerst kopiere ich das STDIO für die Wiederherstellung nach der I/O-Umleitung. Dann verdopple ich meinen Dateideskriptor zu STD_IN und STD_OUT. Dann führe ich Pipeline aus, und schließlich stelle ich meine STD_IN und STD_OUT wieder her. Alles klingt perfekt, aber eigentlich nicht. Meine Umleitung von OUTPUT war fehlgeschlagen, was bedeutet, dass es nichts in die Zieldatei geschrieben hat (d. H. Wenn in der einzigen Situation: ls> 123, 123 zeigt nichts an), wenn mein Programm noch läuft. Aber als ich das Programm mit exit (EXIT_SUCCESS) beendete, erschien es !! (Wenn mit ctrl + c es auch fehlschlug), ich weiß nicht warum!

void Redirection() 
{ 
    fd_out = open(filename[0],O_WRONLY | O_TRUNC | O_CREAT,S_IRWXU | S_IRWXG | S_IRWXO); //O_WRONLY and O_CREAT must use at the same time. 
    dup2(fd_out,STD_OUTPUT); 
    close(fd_out); 
} 
void Copy_STDIO() 
{ 
    STDIN_COPY = dup(STD_INPUT);        //Copy for the stdin and stdout 
    STDOUT_COPY = dup(STD_OUTPUT); 
} 
void Pipeline() 
{ 
if(pipeline) 
{ 
    pipe(&fd[0]); 
    childID=fork(); 

    if(childID==0) 
    { 

     if(fork()!=0) 
     { 
      close(fd[1]); 
      dup2(fd[0],STD_INPUT); 
      close(fd[0]); 

      execvp(args2[0],args2); 

     } 
     else 
     { 
      close(fd[0]); 
      dup2(fd[1],STD_OUTPUT); 
      close(fd[1]); 

      execvp(args[0],args); 

     } 

    } 

    usleep(5000);            
} 
} 
void Restore_stdio() 
{ 
    dup2(STDIN_COPY,STD_INPUT);         //Restore the output and input to the stdin and stdout. 
    dup2(STDOUT_COPY,STD_OUTPUT); 
    close(STDIN_COPY); 
    close(STDOUT_COPY); 
} 
+0

Können Sie ein minimal nachprüfbares Beispiel, auch bekannt als ein Stück Code zur Verfügung stellen, die kompiliert werden kann? –

+0

Dateien müssen geschlossen werden, bevor sie angezeigt und gelesen werden können. Ausgang (0); schließt alle geöffneten Dateien. –

+0

@ArifBurhan wo sollte ich exit (0) hinzufügen; ? Ich habe mein fd_out geschlossen, nachdem ich es an STD_OUTPUT weitergeleitet habe. –

Antwort

0

Ich schob zwei Commits auf Ihr eigenes Repository, sie enthalten die Updates Sie

benötigen
void Pipelining() 
{ 
    int otherID = 0; 
    childID = 0; 
    int childs = 0; 
    int ret = 0; 
    if(pipeline) 
    { 
    pipe(fd); 
    childID=fork(); 

     if (childID < 0) { 
      fprintf(stderr, "error: 1 ... %s\n", strerror(errno)); 
      return; 
     } else if (childID > 0) { 
      ++childs; 
      otherID = fork(); 
      if (otherID < 0) { 
       fprintf(stderr, "error: 2 ... %s\n", strerror(errno)); 
       ret = waitpid(childID, NULL, 0); 
       if (ret < 0) { 
        fprintf(stderr, "error: 3 ... %s\n", strerror(errno)); 
       } 
       return; 
      } else if (otherID > 0) { 
       ++childs; 
      } else { 
      close(fd[0]); 
      ret = dup2(fd[1],STD_OUTPUT); 
       if (ret < 0) { 
        fprintf(stderr, "error: 4 ... %s\n", strerror(errno)); 
       } 
      close(fd[1]); 

      ret = execvp(args[0], args); 
       if (ret < 0) { 
        fprintf(stderr, "error: 5 ... %s\n", strerror(errno)); 
       } 
      } 
     } else { 
      close(fd[1]); 
      ret = dup2(fd[0],STD_INPUT); 
      if (ret < 0) { 
       fprintf(stderr, "error: 6 ... %s\n", strerror(errno)); 
      } 
      close(fd[0]); 

      ret = execvp(args2[0],args2); 
      if (ret < 0) { 
       fprintf(stderr, "error: 7 ... %s\n", strerror(errno)); 
      } 
     } 
     /* now it is safe to close pipe */ 
     close(fd[0]); 
     close(fd[1]); 
     /* wait children */ 
     ret = waitpid(childID, NULL, 0); 
     if (ret < 0) { 
      if (errno != ECHILD) 
       fprintf(stderr, "error: 8 ... %s\n", strerror(errno)); 
     } 
     ret = waitpid(otherID, NULL, 0); 
     if (ret < 0) { 
      if (errno != ECHILD) 
       fprintf(stderr, "error: 9 ... %s\n", strerror(errno)); 
     } 
    } 
} 

ich folgende Änderungen vorgenommen:

  1. jetzt sind beide Kinder aus dem gleichen oben erstellt -parent
  2. jetzt schließt der Top-Parent seine Kopie der Pipe-Dateideskriptoren
  3. jetzt die Top-Eltern warten richtig für ihre Kinder
  4. dringend benötigte Statusprüfungen hinzugefügt
+0

Danke !! Es ist sehr hilfreich für mich !! –

+0

Gern geschehen. –

+0

Ich habe meine Fehler in meinem Code gefunden. Ich stelle meine Pfeife() an die falsche Stelle. Es sollte nach dem ersten fork(), vor dem zweiten fork(), nicht vor dem ersten fork() hahaha! Und ich habe auch mein waitpid() Problem herausgefunden. Trotzdem danke! –