c中的shell:仅在按键盘上的enter键后响应SIGTSTP
我想用c写一个shell。它的一部分是一个处理程序,用于捕获SIGTSTP信号,并将其设置为使程序进入和退出仅前台模式 以下是相关的代码片段:c中的shell:仅在按键盘上的enter键后响应SIGTSTP,c,signals,job-control,C,Signals,Job Control,我想用c写一个shell。它的一部分是一个处理程序,用于捕获SIGTSTP信号,并将其设置为使程序进入和退出仅前台模式 以下是相关的代码片段: //global variables int global; //header void catch_tstp(int); //main function int main(int argc, char** argv){ ... // initiate sigaction struct for CTRL-Z action s
//global variables
int global;
//header
void catch_tstp(int);
//main function
int main(int argc, char** argv){
...
// initiate sigaction struct for CTRL-Z action
struct sigaction ctrlz_act;
ctrlz_act.sa_handler = catch_tstp;
ctrlz_act.sa_flags = SA_SIGINFO|SA_RESTART;
sigfillset(&(ctrlz_act.sa_mask));
sigaction(SIGTSTP, &ctrlz_act, NULL);
global = 0;
...
}
//handler
void catch_tstp(int sig){
if(sig == SIGTSTP){
if(global){
global=0;
printf("Entering foreground-only mode (& is now ignored)\n");
}
else{
global=1;
printf("Exiting foreground-only mode\n");
}
}
}
现在,我的输出如下所示:
: ^ZExiting foreground-only mode //pressed ctrl+z
//nothing here, had to press enter again
: //pressing enter just gives me another :, which is what I want
: ^ZEntering foreground-only mode (& is now ignored)
^ZExiting foreground-only mode
我希望输出可以如下所示:
: ^Z
Entering foreground-only mode (& is now ignored)
: //":"should show up own automatically on the next line after I press ctrl-z, then enter
: ^Z
Exiting foreground-only mode
:
有人能指出我做错了什么吗?任何帮助都将不胜感激。谢谢大家! 您的信号处理程序和设置方式有几个问题 正如我在评论中已经指出的那样,信号处理程序可以安全地访问文件范围变量,例如
全局
,前提是该变量是易失的
,并且类型为sig\u atomic\t
。如果它试图访问任何其他变量,则有可能看不到该变量的最新值集,处理程序范围之外的代码将看不到处理程序写入该变量的值(如果有),由于信号处理程序对变量的写入是非原子的,因此变量的值将被破坏
注释中还指出了一个更严重的问题,即将SA_SIGINFO
标记指定为sigaction()
,告诉它您已经通过struct sigaction
的SA_sigaction
成员指定了处理程序,而实际上,您已经通过sa_处理程序
成员指定了它如果通过sa_handler
指定处理程序,则必须从标志中省略sa_sigino
,反之亦然。如果不适当地指定了SA_SIGINFO
标志,则接收到该信号将导致未定义的行为,或者使用错误的参数调用处理程序,或者尝试通过垃圾函数指针调用函数
此外,信号处理程序调用的所有函数必须是异步信号安全的。手册第7章中的“信号”条目包含可安全调用的函数列表,而printf()
不在其中
但是影响你欲望的主要问题是
“:”按ctrl-z键后,应在下一行自动显示own
似乎您已将SA_RESTART
包含在sigaction标志中。该标志导致在信号处理程序完成后,因接收信号而中断的(某些)系统功能自动重新启动,而不是向调用者返回EINTR
错误或部分结果。在特定情况下,如果shell在读取命令时收到SIGSTP
,则重新启动读取意味着控件不会返回shell以打印新提示。这也可能意味着^Z之前输入的字符丢失,具体取决于您如何读取命令的详细信息
此外,从程序的消息传递来看,您可能对终端接口和标准shell对^Z和
SIGSTP
的含义和用法有误解。它们为shell执行的作业提供作业控制功能;它们主要不是关于shell本身的模式。shell不需要在接收到^Z(信号处理程序本身的范围之外)后维护标志或以不同的方式进行操作——所需的交互行为主要来自这样一个事实,即shell只有在前台才能读取标准输入
当外壳接收到SIGSTP
时
- 如果它在前台,它应该什么也不做(并避免丢失未处理的输入)
- 如果它在后台,它应该向前台进程组发送一个
(注意区别),并在必要时将自己放回前台。在这种情况下,它可能会发出消息和/或提示SIGSTOP
global
,它必须是易失性的
,并且具有类型sig\u atomic\t
。但是,我怀疑您没有这样做并不是问题的直接原因。我相应地修改了global
,但您是对的,它没有解决问题。此外,您不应该将SA_sigino
标志指定为sigaction()
,因为您使用的是struct sigaction
的sa_处理程序
成员,而不是sa_sigaction
成员。这是一个严重的问题,但我敢打赌,删除该标志不会改变观察到的行为。我无法根据您提供的代码复制您描述的行为。我假定您的程序在键入^Z时正在执行某种I/O操作,例如尝试读取命令。这可能与观察到的行为有关,但也有一种情况,即shell应该静默地使用信号,因为它本身就是前台进程;bash是一个非常特殊的解释器,它是POSIX sh规范的一个大型超集,而像这样的玩具外壳是很小的子集——它们几乎没有任何共同之处。关于这一点,shell标签的wiki明确表示,它的重点是用POSIX兼容语言寻找答案的问题,而不是关于实现类似于shell的程序的问题。感谢您的详细解释。我对最后一部分有点困惑。在我的shell中,在添加^Z
处理程序之前,每当我输入^Z
时,我的shell输出[1]+停止。我想让它做的是,如原文章中所述,进入前台模式,同时显示“进入/退出前台模式”。在修复了sau重启标志之后,它仍然没有这样做,所以我假设t