我面临一个问题,即我的终端上看不到来自标准输入的文本。我的程序执行以下操作
设置一个 SIGALRM 处理程序,当用户在一定时间后没有输入时,该处理程序将退出程序。
void sigalrm_handler(int arg)
{
exit(0);
}
在主要功能中:
{
...
alarm(100);
line = readline(line = readline(prompt);)
...
}
但是,在我的程序退出后,我看不到我在终端上输入的内容。但命令工作正常。
运行
system("reset")
暂时解决了这个问题。但我需要一个更清洁的解决方案。我已经尝试过
int rl_reset_line_state ()
,int rl_reset_terminal (char *terminal_name)
但它们似乎不起作用。
答案1
现代 shell 倾向于在程序退出后恢复终端状态;正如您所观察到的,旧的或能力较差的炮弹可能不会。 APUE 和其他文本中常见的方法是使用 保存终端状态的副本tcgetattr
,然后在程序退出时恢复该状态:
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
struct itimerval Alarm_Timer;
struct termios Original_Termios;
int Need_Reset;
void sigalrm_handler(int arg)
{
if (Need_Reset)
tcsetattr(STDIN_FILENO, TCSANOW, &Original_Termios);
exit(0);
}
int main(void)
{
char *line;
tcgetattr(STDIN_FILENO, &Original_Termios);
Need_Reset = 1;
signal(SIGALRM, sigalrm_handler);
Alarm_Timer.it_value.tv_sec = 3;
setitimer(ITIMER_REAL, &Alarm_Timer, NULL);
line = readline("* ");
if (Need_Reset)
tcsetattr(STDIN_FILENO, TCSANOW, &Original_Termios);
exit(0);
}
答案2
首先,正在为、等libreadline
安装自己的信号处理程序,并且在收到此类信号后将正常退出(恢复 termios/stty 设置后)。ALRM
INT
您可以通过运行/跟踪一个简单的程序来进行检查,如下所示:
#include <readline/readline.h>
#include <unistd.h>
int main(void){
alarm(3); readline("foo> ");
}
所以你可以摆脱你的信号处理程序。
其次,你应该绝不exit(3)
从信号处理程序调用。exit(3)
与_exit(2)
系统调用不同的是不是信号安全,主要是因为它必须运行注册的处理程序atexit(3)
。例如,想象一下,如果在另一个处理程序已经在运行这些处理程序exit(3)
时调用该处理程序,会发生什么情况。exit(3)
如果您使用自己的代码而不是readline(3)
使用将终端置于原始模式等,则应始终在启动时保存终端的状态和收到SIGCONT
信号后,退出前恢复和收到信号后SIGTSTP
。不仅仅是像很多例子中那样在启动/退出时。如果您使用光标寻址,则在保存/恢复 termios 设置时还应该使用 /ca_mode
转义符打开smcup
/关闭。rmcup