我目前正在C中编写一个简单的shell,而且我面临信号问题。
例如,当我启动程序时,我输入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 :(得分:3)
正确的作业控制信号处理可以使您的项目超出我的特点,简单的"简单的"贝壳。 GLIBC手册有a whole multi-part section来实现作业控制shell,听起来很多它都适用于你的项目。
您似乎无视的一个关键方面是管理流程组以及哪些流程控制终端。现在你正在做的事情,你的shell子进程将属于与shell本身相同的进程组,当信号(例如SIGSTP
)出现时,这将会出现问题。发送给孩子的整个过程组。
为避免此类问题,您的shell应使新的子进程成为其自己进程组的进程组负责人(通过setpgid()
)。当这些进程组最初位于前台时,你的shell应该使它们终端控制进程组(tcsetpgrp()
)。
答案 1 :(得分: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;
这样,两个目标文件共享相同的变量f_pid
。
编辑 -----
尝试更改处理程序TSTP,并添加以下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机器上运行。停止发生时
请注意,alarm()
需要几秒钟,setitimer()
会下降到微秒(理论上)。