2010-11-19 25 views
2

Şu anda kendi kabuğumu bir sınıf projesi olarak yazmaktayım ve neredeyse her şeye sahip olmak zorundayım. Benim sorunum benim borularım, bazen çalışıyorlar ve bazen onları kesene kadar beklerler. Bu konuda araştırma yaptım ve görünüşe göre, ilk süreçten bir EOF almayan bir şekilde stdin almanın işlevi; genellikle problemi öğrendiğim gibi boru kapatılmıyor, fakat bu benim kodumla (bilgimle) ilgili değil.Bazı kabukları ele alırken kendi kabuğunu yazma - kod kilitleniyor - C

tüm yönlendirme çalışmaları ve bunların herhangi bir varyasyonu aşağıdaki borulu komutlarının çalışma

  • ls -l > file1
  • wc <file1> file2

:

  • w | head -n 4
  • w | head -n 4 > file1

Bu işe yaramazsa: Bir kesme sinyali kullanıcı tarafından kendisine gönderilen sürece ls | grep file1 doğru çıkışını gösterir ve asla sona erer. ls | grep file1 > file2 da çalışmıyor. Çıktısını göstermeden askıda kalıyor, dosya2 yaratıyor ama asla yazmıyor.

Neyse, umarım bir başkasının fark edebileceği bir şey vardır; Bir süredir bu işteyim. Sağladığım bir kod varsa bana bildirin. Aşağıda kaydettiğim kod ana dosyadır, hiçbir şey kaldırılmaz.

/* 
* This code implemenFts a simple shell program 
* At this time it supports just simple commands with 
* any number of args. 
*/ 

#include <stdio.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <errno.h> 
#include <signal.h> 
#include <sys/wait.h> 
#include <fcntl.h> 
#include <sys/stat.h> 
#include <stdlib.h> 
#include <string.h> 

#include "input.h" 
#include "myShell.h" 
#include "BackgroundStack.h" 

/* 
* The main shell function 
*/ 
main() { 
    char *buff[20]; 
    char *inputString; 

    BackgroundStack *bgStack = malloc(sizeof(BackgroundStack)); 
    initBgStack(bgStack); 

    struct sigaction new_act; 
    new_act.sa_handler = sigIntHandler; 
    sigemptyset (&new_act.sa_mask); 
    new_act.sa_flags = SA_RESTART; 
    sigaction(SIGINT, &new_act, NULL); 

    // Loop forever 
    while(1) { 
     const char *chPath; 

     doneBgProcesses(bgStack); 

     // Print out the prompt and get the input 
     printPrompt(); 

     inputString = get_my_args(buff); 
     if (buff[0] == NULL) continue; 

     if (buff[0][0] == '#') continue; 

     switch (getBuiltInCommand(buff[0])) { 
      case EXIT: 
       exit(0); 
       break; 
      case CD: 
       chPath = (buff[1]==NULL) ? getenv("HOME") : buff[1]; 
       if (chdir(chPath) < 0) { 
        perror(": cd"); 
       } 
       break; 
      default: 
       do_command(buff, bgStack); 
     } 

     //free up the malloced memory 
     free(inputString); 
    }// end of while(1) 
} 

static void sigIntHandler (int signum) {} 

/* 
* Do the command 
*/ 
int do_command(char **args, BackgroundStack *bgStack) { 
    int status, statusb; 
    pid_t child_id, childb_id; 
    char **argsb; 
    int pipes[2]; 

    int isBgd = isBackgrounded(args); 
    int hasPipe = hasAPipe(args); 

    if (isBgd) removeBackgroundCommand(args); 
    if (hasPipe) { 
     int cmdBi = getSecondCommandIndex(args); 
     args[cmdBi-1] = NULL; 
     argsb = &args[cmdBi]; 
     pipe(pipes); 
    } 

    // Fork the child and check for errors in fork() 
    if((child_id = fork()) == -1) { 
     switch(errno) { 
      case EAGAIN: 
       perror("Error EAGAIN: "); 
       return; 
      case ENOMEM: 
       perror("Error ENOMEM: "); 
       return; 
     } 
    } 

    if (hasPipe && child_id != 0) { 
     childb_id = fork(); 
     if(childb_id == -1) { 
      switch(errno) { 
       case EAGAIN: 
        perror("Error EAGAIN: "); 
        return; 
       case ENOMEM: 
        perror("Error ENOMEM: "); 
        return; 
      } 
     } 
    } 

    if(child_id == 0 || (childb_id == 0 && hasPipe)) { 
     if (child_id != 0 && hasPipe) args = argsb; 
     if (child_id == 0 && isBgd) { 
      struct sigaction new_act; 
      new_act.sa_handler = SIG_IGN; 
      sigaction(SIGINT, &new_act, 0); 
     } 

     if (child_id == 0 && hasPipe) { 
      if (dup2(pipes[1], 1) != 1) fatalPerror(": Pipe Redirection Output Error"); 
      close(pipes[0]); 
      close(pipes[1]); 
     } 
     if (child_id != 0 && hasPipe) { 
      if (dup2(pipes[0], 0) != 0) fatalPerror(": Pipe Redirection Input Error"); 
      close(pipes[0]); 
      close(pipes[1]); 
      waitpid(child_id, NULL, 0); 
     } 

     if ((child_id != 0 && hasPipe) || !hasPipe) { 
      if (hasAReOut(args)) { 
       char outFile[100]; 
       getOutFile(args, outFile); 

       int reOutFile = open(outFile, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE); 
       if (reOutFile<0) fatalPerror(": Redirection Output Error"); 

       if (dup2(reOutFile,1) != 1) fatalPerror(": Redirection Output Error"); 
       close(reOutFile); 
      } 
     } 

     if ((child_id == 0 && hasPipe) || !hasPipe) { 
      if (hasAReIn(args)) { 
       char inFle[100]; 
       getInFile(args, inFle); 

       int reInFile = open(inFle, O_RDWR); 
       if (reInFile<0) fatalPerror(": Redirection Input Error"); 

       if (dup2(reInFile,0) != 0) fatalPerror(": Redirection Input Error"); 
       close(reInFile); 
      } else if (isBgd && !hasPipe) { 
       int bgReInFile = open("/dev/null", O_RDONLY); 
       if (bgReInFile<0) fatalPerror(": /dev/null Redirection Input Error"); 

       if (dup2(bgReInFile,0) != 0) fatalPerror(": /dev/null Redirection Input Error"); 
       close(bgReInFile); 
      } 
     } 

     // Execute the command 
     execvp(args[0], args); 
     perror(args[0]); 

     exit(-1); 
    } 

    // Wait for the child process to complete, if necessary 
    if (!isBgd) waitpid(child_id, &status, 0); 
    else if (!hasPipe) { 
     printf("Child %ld started\n", (long)child_id); 
     BackgroundProcess *bgPrs = malloc(sizeof(BackgroundProcess)); 
     bgPrs->pid = child_id; 
     bgPrs->exitStatus = -1; 

     addProcessToBgStack(bgStack, bgPrs); 
    } 
    if (hasPipe) waitpid(childb_id, &statusb, 0); 
    if (WIFSIGNALED(status) && !isBgd) printf("Child %ld terminated due to signal %d\n", (long)child_id, WTERMSIG(status)); 
    if (hasPipe && WIFSIGNALED(statusb)) printf("Child %ld terminated due to signal %d\n", (long)childb_id, WTERMSIG(status)); 

} // end of do_command 
+0

Eğer çalışma kodunu görmek isteyen biri varsa, bu benim grep’in neden sonlanmadığını açıklayan http://pastebin.com/VevMrng9 –

cevap

7

ikinci çocuk gerektiğini ilk çocuk için değil beklemek çıkmak için - bu sadece (bazı çıkış ilk çocuk tarafından boruya üretilir kadar engeller) uzakta düz yayınlanmaya başlaması, böylece kaldırmalısınız waitpid(), childb tarafından yürütülür. Bunun yerine, ebeveyn süreci hem çocuk süreçlerini (ya da belki de sadece ikincisini) beklemelidir. (Gerçekten de, JeremyP tarafından belirtildiği gibi, bu waitpid() numaralı çağrı, childb numaralı telefonun child numaralı ana öğe olmadığı için yine de başarısız oluyor.)

Sorununuz, bununla birlikte, ana işlemin, açık dosya tanıtıcılarını boruna göstermesidir.

close(pipes[0]); 
close(pipes[1]); 

ebeveyn açık dosya tanıtıcı çocuk grep süreç EOF görür asla anlamına gelir, bu yüzden çıkmasını sağlamaz: Sağ comment // Wait for the child process to complete, if necessary önce, ana süreç boru dosya tanımlayıcıları kapatmalıdır.

+0

+1. – JeremyP

+0

Teşekkürler, önerdiğin gibi, ebeveynler çocuklarının işleyişini beklemeden önce boruları kapattım (eğer komut bir boru içeriyorsa); güzel çalıştı. Borunun üç farklı yerde olduğunu hatırlamayı ihmal ettim. –

1

Cevabı bilmiyorum ama bir sorun tespit ettim.

Sen

if(child_id == 0 || (childb_id == 0 && hasPipe)) 

koşulu sadece iki çocuk süreçleri için geçerli olduğunu kabul edeceğiz, ama eğer deyim bloğunun içinde bu vardır:

if (child_id != 0 && hasPipe) { 
     if (dup2(pipes[0], 0) != 0) fatalPerror(": Pipe Redirection Input Error"); 
     close(pipes[0]); 
     close(pipes[1]); 
     waitpid(child_id, NULL, 0); 
    } 

waitpid() çağrı yanlıştır çünkü ilk çocuktan beklemek için ikinci çocuktan çağrılır.Muhtemelen ECHILD ile başarısız oluyor çünkü ilk çocuk ikinci çocuğun bir çocuğu değil.

Gerçek sorununuza gelince, grep komutunun giriş kapatılıncaya kadar sonlandırılmaması gerektiğinden şüpheleniyorum. Bu durmadan devam eden bazı kilitlenme durumları olabilir. Bunu bir hata ayıklayıcısında çalıştırmanız veya üst işlemin nerede asılı olduğunu görmek için giriş yapmanız gerekir.

Düzenleme

Caf cevabı bize her şeyi anlatır.

Grep girişinin kapatıldığını varsayıyordum çünkü sonlandırıldığında çıkışları kapatacak, ancak tabi ki ana işlem de grep giriş dosya tanıtıcısını açık tutuyor. head kullanan sürüm, head -n 4 girdi dosyası tanımlayıcısının kapalı olup olmadığına bakılmaksızın dört satırdan sonra sonlandırıldığı için düzgün şekilde çalışır.

+0

Niçin ikinci çocuğun ilkini beklemesinin gerekli olduğunu düşündüğümden emin değilim, sanırım programın düzeltilmesi için uğraştığım çılgın bir hareketti. Devam ettim ve kaldırdım. –