如何在 SIGINT 上正确地重新打印 readline 提示?

问题描述 投票:0回答:1

我建立了以下信号处理程序:

void    sig_handler(int sig)
{
    if (sig == SIGINT)
    {
        printf("\n");
        rl_on_new_line();
        rl_replace_line("", 0);
        rl_redisplay();
    }
}

在 readline 提示符下效果很好,但如果我运行阻塞命令(比如

cat
),提示符会在同一行上打印两次。

如果我删除

rl_redisplay();
,它会在运行
cat
时起作用,但当
readline()
等待输入时,永远不会打印提示。我已阅读this问题,并且
SA_RESTART
设置在
sa.sa_flags
中。

c linux signals readline sigint
1个回答
0
投票

您无法在信号处理程序中安全地执行此操作。 您看到的任何这样做的代码示例都只是简单的错误

根据 C11 标准(草案)第 4 段7.1.4 使用库函数

标准库中的函数不保证可重入,并且可能会修改具有静态或线程存储持续时间的对象。

脚注188所述:

因此,信号处理程序通常不能调用标准库函数。

因此,从信号处理程序中调用任何 C 标准函数(例如

printf()

)都是不安全的。

但是

POSIX 允许从信号处理程序中进行 some 调用:

...

...

如果信号处理程序引用除 errno 之外的具有静态存储持续时间的任何对象,而不是通过为声明为 volatile 的对象赋值,sig_atomic_t,或者如果信号处理程序调用任何函数,则行为未定义

除下表中列出的功能之一之外,本标准中定义了
下表定义了一组异步信号安全的函数。因此,应用程序可以不受限制地从信号捕获函数中调用它们。

如果调用的函数
不在该表上,则无法从信号处理程序中安全地调用它。

Linux 的详细信息可以在 Linux

signal-safety

手册页:

 中找到

async-signal-safe
函数是可以安全调用的函数 从信号处理程序内部。 许多函数

异步信号安全。 特别是,不可重入函数通常是 从信号处理程序调用不安全。 导致函数不安全的问题类型可以很快被解决 当人们考虑 stdio

的实现时就可以理解 库,其所有函数都不是异步信号安全的。

可以
做的是设置一个标志,以便在进程退出时重新打印提示:

volatile sig_atomic_t reprintPrompt = 0; void sig_handler(int sig) { if (sig == SIGINT) { reprintPrompt = 1; } } ... int main(int argc, char **argv) { ... if (reprintPrompt) { printf("\n"); rl_on_new_line(); rl_replace_line("", 0); rl_redisplay(); } return(0); }


© www.soinside.com 2019 - 2024. All rights reserved.