簡體   English   中英

手工殼背景問題中的子過程

[英]Child Process in Background Issues for Handmade Shell

我在實現自己的手工外殼時遇到了一些麻煩。 我已經能夠派生一個進程,並使用waitpid在前驅中運行它,但是當我嘗試在后台運行諸如“ sleep 5&”之類的簡單進程時,該進程似乎可以永遠運行。 checkListJobs將確定該進程是否已完成運行,但永遠不會停止。 任何幫助將不勝感激。 我認為錯誤出在我的“ foo”函數中。

void insertJob(int pid) {
    printf("beginning job %d.\n", pid);
    struct job *node = malloc(sizeof(struct job));
    node->pid = pid;
    node->next = NULL;

    if(root == NULL) {
        root = node;
    } else {
        node->next = root;
        root = node;
    }
}    

void checkListJobs(int z) {
    curr = root;
    while(curr!=NULL) {
        if(kill(curr->pid,0) != 0)   {
            if(prev==NULL) {
                prev = curr;
                root = curr;
            } else {
                prev->next = curr->next;
            }
        } else {
            if(!z) printf("%d is still running.\n", curr->pid);
        }
        prev = curr;
        curr = curr->next;
    }
}   


//code for child forking
void foo(char *cmd, char *argv[], int args) {
    int bgFlag;

    if(!strcmp(argv[args], "&")){
        argv[args] = '\0';
        bgFlag = 1;
    }

    int pid = fork();
    int status = 0;

    if(pid==0){
        if(bgFlag) {
            fclose(stdin); // close child's stdin
            fopen("/dev/null", "r"); // open a new stdin that is always empty
        }
        execvp(cmd, argv);
        // this should never be reached, unless there is an error
            fprintf (stderr, "unknown command: %s\n", cmd);
            exit(0);
    } else {
        if(!bgFlag) {
            waitpid(pid, &status, 0);
        } else {
            insertJob(pid);
        }
        if (status != 0) {
            fprintf  (stderr, "error: %s exited with status code %d\n", cmd,     status);
        } else {
            // cmd exec'd successfully
        }
    }

    // this is the parent still, since the child always terminates from exec or exit

    // continue being a shell...
}

您將需要為SIGCHLD安裝信號處理程序,因為它將在子進程完成時告訴您的程序。 收到SIGCHLD后,您應該再調用wait()(或PID值為-1的waitpid(),因為您不知道哪個孩子完成了,只是一個孩子完成了)。

編寫處理程序的最安全方法是:

volatile sig_atomic_t sigchld;
int handle_child(int sig)
{
  if (sig == SIGCHLD)
    sigchld = 1;
}

然后在主循環中檢查sigchld是否為1。如果為sigchld則子進程結束,然后可以在其中調用waidpid() (使用-1的PID,因為您不知道哪個子進程結束)。循環(請參閱下文),因為可能有多個子項同時結束。 另外,如果有任何系統調用返回錯誤,並且errnoEINTR則它已被信號中斷,因此可以返回到主循環的頂部,或者檢查sigchld並進行相應的處理(並且不要忘記將sigchld重置為0)盡快)。

for(;;)
{
  int status;
  pid_t child;

  child = waitpid(-1,&status,WNOHANG);
  if (child == -1) 
  {
    if (errno == ECHILD) break; /* no more children */
    /* error, handle how you wish */
  }
  /* handle the return status of the child */
}
sigchld = 0;

可以從信號處理程序中調用waitpid() (POSIX表示這樣做是安全的),但實際上您不應在信號處理程序中進行任何其他操作 ,因為它可能導致非常細微的錯誤(例如,在調用過程中引發了SIGCHLD)到malloc() ---在導致一個呼叫信號處理程序的任何代碼malloc()會導致非常討厭的問題 。這就是為什么我建議在信號處理程序設置一個標志---越少,你在做信號處理程序)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM