5

を使用している Qt アプリQSerialPortでクリーンでないシャットダウンが発生した場合 (たとえば、受信して処理していないためSIGINT)、シリアル ポートのファイル記述子はどのように影響を受けますか?

QSerialPortonを開いて/dev/ttyS0終了するアプリを実行した後、(通常のように)データを待つのではなく、(何も印刷せずに)即座に戻るCtl-Cことがわかりました。cat < /dev/ttyS0

これが開いたままのファイル ハンドルが原因である場合は、 の出力に表示されると思いますがlsoflsof | grep ttyS0何も返されません。(特定のファイル記述子でハンドルを検索する方法が他にあるかどうかはよくわかりません。)

を適切に処理するようにアプリを書き直すことで問題を完全に回避できたので、これは少し XY の問題であることを認識してSIGINTいますが、ここで何が起こっているのか、シリアルを回復する方法があるかどうかをより深く理解したいと思います。この状態のときはポート。


編集:要求に応じて、次の出力があります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
4

1 に答える 1

3

POSIX では、端末デバイス (つまり、シリアル ポートと疑似端末) には、コンピュータが存在する、または存在していた基本的なRS-232プロトコルのさまざまなバリエーションを使用できるようにする設定が多数あります。この API の大部分は、恐竜とテレタイプライター(したがって「tty」) が地球を支配していた時代に設計されたものであり、同じ方法でやり直すことはありませんが、今はそれで行き詰まっています。

端末設定は永続的です。あるプログラムがそれらを設定すると、別のプログラムがそれらを変更するまでそのままになります。コマンドライン ユーティリティsttyは、これらの設定を出力または変更できます。stty saneそれらをすべて「合理的な」デフォルトにリセットします。stty -aそれらをすべて印刷します。

stty sane私のコンピューターに適用されるものQSerialPortと、シリアルポートに適用されるものとの間で異なるすべての端末設定を次に示します。(前にダッシュが付いている可能性がある単なる不可解なラベルのものは、ブール値のフラグです。先頭のダッシュは「オフ」を意味し、先頭のダッシュがない場合は「オン」を意味します。)

  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この状態でシリアル ポートに接続された行指向またはファイル指向のプログラムが誤動作するという意味で異常です。(ただし、シリアルポートと通信していることを認識し、これらの特定のノブを回した結果に対処する準備ができているプログラムには完全に適しています。おそらく、の作成者は自分が何をしていたかを知っていました。)すぐに終了するには です。これは (デフォルトの とともに)、 「保留中の入力がない場合は 0 バイトを返す必要がある」ことを意味します。通常の状況では、ゼロバイトが返された場合、ファイルの終わりを意味するため、QSerialPortcatmin = 0time = 0read()read()cat空のファイルが渡されたと見なされるため、すぐに終了します。(このモードは何年も前に発明された可能性がありますO_NONBLOCK。)

stty saneあなたが探していた「シリアルポートを回復する方法」です。ドキュメントにはどちらの方法も記載されていませんがハンドラーQSerialPort::close()から呼び出されてもターミナルが元の状態に戻らない場合は、Qt のバグと考えます。また、、、、およびほぼ間違いなく、を受信したときにもこれを行う必要があります(ただし、これらは致命的ではないため、これはより複雑です)。終了ステータスが正しくなるように、必ずデフォルト ハンドラーを復元し、後でシグナルを再発生させてください。SIGINTSIGHUPSIGQUITSIGABRTSIGTERMSIGTSTPSIGTTINSIGTTOU

于 2015-03-23T21:12:33.063 に答える