如何让readline响应SIGINT信号退出?设置rl_done无效问题排查
问题:Ctrl-C无法通过设置rl_done中断readline
我尝试实现按下Ctrl-C时让readline退出,原本以为设置rl_done变量就能达成目标,但实际并未生效。按下Ctrl-C后信号已被接收,且rl_done已设为1,但readline仍未退出,相关代码如下:
char **continue_input(char **input, char *str) { char *line; char *temp; ignore_signals(); init_signals(CONTINUE_INPUT); printf("start readline%c-----------%c", 10, 10);fflush(stdout); //debug line = readline(str); printf("readline ended%c-----------%c", 10, 10);fflush(stdout); //debug if (rl_done == 1) { rl_done = 0; return (NULL); } if (!line) { ignore_signals(); init_signals(FALSE); return (NULL); } temp = ft_strjoin(*input, "\n"); free(*input); *input = ft_strjoin(temp, line); free(line); free(temp); if (!input) exit(EXIT_FAILURE); ignore_signals(); init_signals(FALSE); return (input); } void continue_input_signal_handler(int sig) { if (sig == SIGINT) { printf("setting rl_done to 1%c-----------%c", 10, 10);fflush(stdout); //debug rl_done = 1; } else if (sig == SIGTERM) { exit(EXIT_SUCCESS); } }
解决方案
仅设置rl_done不足以中断readline的阻塞状态。readline等待输入时处于系统调用(如read())的阻塞状态,信号触发后系统调用会返回,但readline内部会重新进入等待逻辑,不会立刻检查rl_done的值。要让readline真正退出,需要在信号处理函数中主动触发readline的状态更新:
- 修改信号处理函数:添加readline专用的终端状态函数,强制中断等待并刷新显示:
#include <unistd.h> // 用于write void continue_input_signal_handler(int sig) { if (sig == SIGINT) { rl_done = 1; // 告诉readline切换到新行 rl_on_new_line(); // 清除当前输入行并刷新终端 rl_replace_line("", 0); rl_redisplay(); // 输出换行,让提示符出现在新行(用write保证异步安全) write(STDOUT_FILENO, "\n", 1); } else if (sig == SIGTERM) { exit(EXIT_SUCCESS); } }
- 禁用readline默认信号处理:在调用
readline()前设置rl_catch_signals = 0;,避免readline自带的SIGINT处理覆盖自定义逻辑:
在continue_input函数中,调用readline(str)前添加:
rl_catch_signals = 0;
- 注意异步安全:信号处理函数中尽量避免使用
printf这类非异步安全函数,改用write更稳妥,防止出现终端输出混乱的问题。
这样修改后,按下Ctrl-C时,readline会立刻退出阻塞状态,readline()函数返回,后续检查rl_done的逻辑就能正常触发,返回NULL实现退出。
内容的提问来源于stack exchange,提问作者Clément
相关产品推荐
相关产品推荐

