2017-11-25 254 views
0

我目前正在編寫一個簡單的shell在C中,我面臨的信號問題。處理信號sigtstp - sigcont - sigint與子進程在C

例如,當我啓動我的程序時,我鍵入ping命令,然後鍵入CTRL-Z我希望子進程(ping命令)暫停,然後在我使用fg時回來。

我認爲我需要存儲一個全局變量執行ping命令的子pid。

我已經檢查了其他帖子來解決我自己的問題,但我無法得到它的工作。

這是執行命令(多個命令| |)和存儲子pid的代碼。

int exec_proc(int input, int output, char** command) { 

pid_t runner; 

runner = fork(); 
f_pid = runner; 

if (runner == 0) { 
    // Use input for stdin 
    if (input != 0) { 
     dup2(input, 0); 
     close(input); 
    } 

    // Use output for stdout 
    if (output != 1) { 
     dup2(output, 1); 
     close(output); 
    } 
    // Return command code 
    execvp(command[0], command); 
} 

// An error occured 
return -1; 

這是我的處理程序c文件。

pid_t f_pid; 
/** 
* Handles every handler ! 
*/ 
void handlerManager() 
{ 
    signal(SIGINT,INTHandler); 
    signal(SIGTSTP,TSTPHandler); 
    signal(SIGCONT,CONTHandler); 
} 

/** 
* Handler for CTRL-C 
* @param sig 
*/ 
void INTHandler(int sig) 
{ 
    printf("\nDo you really want to quit ? [y/n] \n"); 
    int answer = getchar(); 

    if(toupper(answer) == 'Y') 
     kill(f_pid,SIGINT); 
} 

/** 
* Handler for CTRL-Z (processus sleep) 
* @param sig 
*/ 
void TSTPHandler(int sig) 
{ 
    printf("\nGoing to sleep! \n"); 
    printf("%d", f_pid); 
    kill(f_pid,SIGTSTP); 
} 

/** 
    * Handler to reset a processus 
    * @param sig 
*/ 
void CONTHandler(int sig) 
{ 
    printf("\nHey i'm awake\n"); 
    kill(f_pid,SIGCONT); 
}` 

當我打印PID時,我得到正確的PID。

最後這個地方我打電話給我的處理程序管理器。

int main() { 


char* line; 
char** args[MAX_ARG_SIZE] = {NULL}; 
int status; 

handlerManager(); 

do { 

    fflush(stdin); 

    prompt(); 

    line = readline(); 

    char linecpy[strlen(line)]; 
    strcpy(linecpy, line); 

    splitBy(line, " ", args); 

    status = exec(args, linecpy); 

    switch (status) { 
     case EMPTY_LINE: 
      break; 
    } 

} while (status); 


return 0; 

在此先謝謝您,並對我的英語感到抱歉。

回答

0

exec_proc文件應具有

pid_t f_pid; 

作爲全局變量(反向兩行)

pid_t runner; 

int exec_proc(int input, int output, char** command) { 

處理機C文件需要經由extern訪問在其它文件中聲明的全局變量

extern pid_t f_pid; 

這樣,兩個目標文件s野兔同樣變量f_pid

編輯 -----

嘗試改變處理器三偏磷酸鈉,並添加以下ALRM

void TSTPHandler(int sig) 
{ 
    signal(SIGTSTP,SIG_DFL);  // <+++++ 
    printf("\nGoing to sleep! \n"); 
    printf("%d", f_pid); 
    kill(f_pid,SIGTSTP); 
    kill(getpid(),SIGTSTP);  // <+++++ 
    alarm(1);      // <+++++ 
} 
void ALRMHandler(int sig)   // <+++++ 
{ 
    signal(SIGTSTP,TSTPHandler); 
} 

添加報警信號

void handlerManager() 
{ 
    signal(SIGINT,INTHandler); 
    signal(SIGTSTP,TSTPHandler); 
    signal(SIGCONT,CONTHandler); 
    signal(SIGALRM,ALRMHandler); // <+++++ 
} 

作品在我的Linux機器。當停止時

  1. 禁用三偏磷酸鈉處理
  2. 做好當前東西
  3. 殺死的主要過程!
  4. 啓動報警設置三偏磷酸鈉處理回(並稱該處理器似乎產生了一些麻煩......)

注意alarm()只需幾秒鐘,setitimer()下降到微秒(理論上)。

+0

嗨,謝謝你的回答我做了更改,但是當我在命令中按Ctrl-Z時,它確實改變了processus的狀態,但是當我鍵入fg時,我在子進程(ping命令) 。 –

+0

請參閱編輯。 –

3

做適當的工作控制信號處理可以使您的項目超出我所說的「簡單」外殼。 GLIBC手冊有執行作業控制外殼的a whole multi-part section,聽起來好像很多應用於您的項目。

您似乎無視的一個關鍵方面是管理進程組,以及哪些人控制了終端。你現在正在做的事情是,你的shell的子進程將和shell本身屬於同一個進程組,當一個信號(如SIGSTP)被髮送到子進程的整個進程組時,會出現問題。

爲了避免出現這樣的問題,您的shell應該讓新的子進程成爲他們自己進程組的進程組首部(通過setpgid())。當這些進程組最初處於前臺時,你的shell應該讓它們成爲終端的控制進程組(tcsetpgrp())。

當然,除此之外還有更多,但應該讓你朝着正確的方向前進。