2017-11-25 294 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())。

当然,除此之外还有更多,但应该让你朝着正确的方向前进。