即使在control-C之后还原串口属性?

时间:2010-10-24 17:22:15

标签: serial-port posix signals

通过POSIX使用串行端口时,建议使用tcgetattr()保存原始属性,然后再使用tcsetattr()进行更改,然后在关闭端口之前将其恢复。通过按control-C或程序收到SIGINT来终止程序时怎么办?我没有在任何系列教程中看到这一点。

显然atexit()函数是不够的,因为它没有被默认的SIGINT处理程序调用。因此,似乎需要安装信号处理程序,以便将属性恢复到仍然打开的任何串行端口。从信号处理程序调用{​​{1}}是否安全?

有人可能只是将此问题视为无关紧要,但通常使用control-C终止程序,尤其是可能需要几十秒才能完成操作的程序。如果在这种情况下不保留串口设置是可以的,那么根本没有理由保留它们。如果有的话,最好不要打扰,而不是不一致。

我找到了一些examples of source code doing the above,但没有详细记录。我想我对这是否是一个好主意的讨论感兴趣。感谢。

1 个答案:

答案 0 :(得分:1)

经过进一步研究后,我想我已经满意地回答了这个问题。

首先,在man page for signal中,我注意到特别允许信号处理程序与其他一些人一起调用tcsetattr()

信号处理程序例程必须非常小心,因为其他地方的处理在某个任意点被中断。 POSIX具有“安全功能”的概念。如果信号中断了不安全的函数,并且处理程序调用了不安全的函数,则行为是未定义的。安全功能在各种标准中明确列出。 POSIX.1-2003列表是......`raise()```signal()```tcsetattr()`[修剪到相关的]

这有力地表明POSIX委员会已经考虑到了这种确切的事情,并且导致了一种直接的方法,在您打开串行并保存其属性后更改SIGINT处理程序,然后在您的处理程序,恢复它们和旧的SIGINT处理程序,然后重新提升信号:

static void (*prev_sigint)( int );
static termios saved_attr;
static int fd;

static void cleanup( int ignored )
{
    tcsetattr( fd, TCSANOW, &saved_attr );
    signal( SIGINT, prev_sigint );
    raise( SIGINT );
}

int main( void )
{
    open_serial_and_save_attrs();
    prev_sigint = signal( SIGINT, cleanup );
    ...
}