通过POSIX使用串行端口时,建议使用tcgetattr()
保存原始属性,然后再使用tcsetattr()
进行更改,然后在关闭端口之前将其恢复。通过按control-C或程序收到SIGINT
来终止程序时怎么办?我没有在任何系列教程中看到这一点。
显然atexit()
函数是不够的,因为它没有被默认的SIGINT
处理程序调用。因此,似乎需要安装信号处理程序,以便将属性恢复到仍然打开的任何串行端口。从信号处理程序调用{{1}}是否安全?
有人可能只是将此问题视为无关紧要,但通常使用control-C终止程序,尤其是可能需要几十秒才能完成操作的程序。如果在这种情况下不保留串口设置是可以的,那么根本没有理由保留它们。如果有的话,最好不要打扰,而不是不一致。
我找到了一些examples of source code doing the above,但没有详细记录。我想我对这是否是一个好主意的讨论感兴趣。感谢。
答案 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 );
...
}