QSerialPort对进程结束后的`/dev/ttyS *`有影响吗? [英] QSerialPort effect on `/dev/ttyS*` after process end?

查看:108
本文介绍了QSerialPort对进程结束后的`/dev/ttyS *`有影响吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用QSerialPort的Qt应用遇到不干净的关机(例如,由于接收和不处理SIGINT)时,串行端口的文件描述符如何受到影响?

When a Qt app using QSerialPort experiences a non-clean shutdown (e.g. due to receiving and not handling SIGINT), how is the file descriptor of the serial port affected?

运行一个在/dev/ttyS0上打开QSerialPort的应用程序,然后用Ctl-C退出后,我发现cat < /dev/ttyS0立即返回(不打印任何内容),而不是等待数据(通常这样做)

After running an app that opens a QSerialPort on /dev/ttyS0, then quitting with Ctl-C, I am finding that cat < /dev/ttyS0 returns instantly (without printing anything) rather than waiting for data (as it usually does).

我希望,如果这是由于打开的文件句柄悬而未决,它将显示在lsof的输出中,但是lsof | grep ttyS0不返回任何内容. (我不太确定如何在特定文件描述符上搜索句柄.)

I would expect that if this is due to an open file handle left hanging around, it would show up in the output of lsof, but lsof | grep ttyS0 returns nothing. (I'm not really sure how else to search for handles on a particular file descriptor.)

我意识到这是一个XY问题,因为我可以通过重写我的应用程序以正确处理SIGINT来完全避免该问题,但是我想对这里发生的事情以及是否存在这种情况有更深入的了解一种在此状态下恢复串行端口的方法.

I realize this is a bit of an XY problem, since I could avoid the problem entirely by rewriting my app to properly handle SIGINT, but I'd like to have a deeper understanding of what's going on here and if there's a way to recover the serial port when it's in this state.

:根据要求,这是strace cat /dev/ttyS0的输出:

As requested, here is the output of strace cat /dev/ttyS0:

execve("/bin/cat", ["cat", "/dev/ttyS0"], [/* 17 vars */]) = 0
brk(0)                                  = 0x91ce000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=72063, ...}) = 0
mmap2(NULL, 72063, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76e9000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240o\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1446056, ...}) = 0
mmap2(NULL, 1460600, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7584000
mmap2(0xb76e3000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15e) = 0xb76e3000
mmap2(0xb76e6000, 10616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb76e6000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7583000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75838d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb76e3000, 8192, PROT_READ)   = 0
mprotect(0x8054000, 4096, PROT_READ)    = 0
mprotect(0xb771a000, 4096, PROT_READ)   = 0
munmap(0xb76e9000, 72063)               = 0
brk(0)                                  = 0x91ce000
brk(0x91ef000)                          = 0x91ef000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=1534672, ...}) = 0
mmap2(NULL, 1534672, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb740c000
close(3)                                = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
open("/dev/ttyS0", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|S_ISVTX|0660, st_rdev=makedev(4, 64), ...}) = 0
fadvise64_64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "", 32768)                      = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?

这是stty -a -F /dev/ttyS0的输出:

speed 57600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 0; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

推荐答案

在POSIX下,终端设备(即串行端口和伪终端)具有 teletypewriters (因此称为"tty" )统治了地球,我们不会以同样的方式再做一次,但我们现在仍然坚持下去.

Under POSIX, terminal devices (that is, serial ports and pseudoterminals) have a whole bunch of settings which enable the computer to speak the multitude of variations on the basic RS-232 protocol that exist or have existed. A great deal of this API was designed back in the days when dinosaurs and teletypewriters (hence "tty") ruled the earth, and we wouldn't do it over again the same way, but we're stuck with it now.

终端设置是持久的;一旦一个程序设置了它们,它们将保持这种状态,直到另一个程序对其进行更改.命令行实用程序 stty 可以打印或更改这些设置. stty sane将它们全部重置为合理的"默认值; stty -a将它们全部打印出来.

The terminal settings are persistent; once one program sets them, they stay that way until another program changes them. The command-line utility stty can print or change these settings; stty sane resets them all to "reasonable" defaults; stty -a prints them all out.

以下是所有终端设置,这些设置在我的计算机上应用的stty sane和对您的串行端口执行的QSerialPort之间是不同的. (那些只是一个神秘标签,可能在前面带有破折号的是布尔标志;前导破折号表示"off",没有前破折号表示"on".)

Here are all the terminal settings that differ between what stty sane applies on my computer, and what QSerialPort did to your serial port. (The ones that are just a cryptic label, possibly with a dash in front, are boolean flags; the leading dash means "off", no leading dash means "on".)

  QSerialPort        stty sane    
----------------  ----------------
speed 57600 baud  speed 38400 baud
min = 0           min = 1         
clocal            -clocal         
-brkint           brkint          
ignpar            -ignpar         
-icrnl            icrnl           
-ixon             ixon            
-imaxbel          imaxbel         
-opost            opost           
-isig             isig            
-icanon           icanon          
-iexten           iexten          
-echo             echo            

许多QSerialPort设置都是异常的,从某种意义上说,在此状态下连接到串行端口的面向行或文件的程序将无法正常运行. (但是,它们非常适合知道正在与串行端口通信并准备处理已转动这些特定旋钮的后果的程序;想必QSerialPort的作者知道导致cat立即退出的是min = 0,它(与默认的time = 0一起)表示"read()应该在没有输入待处理的情况下返回零字节".在正常情况下,从read()返回的零字节表示文件结束,因此cat立即退出,因为它认为已将其交给了一个空文件. (此模式很可能是在O_NONBLOCK年前发明的.)

Many of the QSerialPort settings are abnormal in the sense that a line- or file-oriented program hooked up to a serial port in this state will misbehave. (However, they are perfectly appropriate for a program that knows it is talking to a serial port and is prepared to deal with the consequences of having turned these particular knobs; presumably the authors of QSerialPort knew what they were doing.) The one that is causing cat to quit immediately is min = 0, which (together with the default time = 0) means "read() should return zero bytes if there is no input pending." Under normal circumstances, zero bytes returned from read() means end of file, so cat quits immediately because it thinks it's been handed an empty file. (This mode may well have been invented years before O_NONBLOCK.)

stty sane是您正在寻找的恢复串行端口的方式".该文档没有给出任何说明,但是如果从您的SIGINT处理程序调用的QSerialPort::close()不能 not 将终端恢复到原始状态,我会认为这是Qt中的错误.您还应该在收到SIGHUPSIGQUITSIGABRTSIGTERM以及可以说是SIGTSTPSIGTTINSIGTTOU的情况下执行此操作(但这比较复杂,因为它们不是致命的).请确保恢复默认处理程序,然后再重新发出信号,以确保退出状态正确.

stty sane is the "way to recover the serial port" that you were looking for. The documentation does not say either way, but if QSerialPort::close() called from your SIGINT handler does not restore the terminal to its original state, I would consider that a bug in Qt. You should also do this upon receipt of SIGHUP, SIGQUIT, SIGABRT, SIGTERM, and arguably SIGTSTP, SIGTTIN, SIGTTOU as well (but that's more complicated, because those aren't fatal). Make sure to restore the default handler and re-raise the signal afterward, so that the exit status is correct.

这篇关于QSerialPort对进程结束后的`/dev/ttyS *`有影响吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆