2015-03-10 9 views
4

Когда приложение Qt с использованием QSerialPort испытывает нечистое завершение работы (например, из-за приема и отсутствия обработки SIGINT), как влияет файловый дескриптор последовательного порта?Эффект QSerialPort на `/ dev/ttyS *` после завершения процесса?

после запуска приложения, которое открывает QSerialPort на /dev/ttyS0, а затем бросить курить с Ctl-C, я нахожу, что cat < /dev/ttyS0 возвращается мгновенно (без печати ничего), не дожидаясь данных (как это обычно бывает).

Я бы ожидал, что если это связано с открытием открытого дескриптора файла, он будет отображаться на выходе lsof, но lsof | grep ttyS0 ничего не возвращает. (Я не уверен, как еще искать ручки в определенном дескрипторе файла.)

Я понимаю, что это немного проблема XY, так как я мог полностью избежать проблемы, переписав мое приложение, чтобы правильно обрабатывать SIGINT , но я хотел бы получить более глубокое понимание того, что здесь происходит, и если есть способ восстановить последовательный порт, когда он находится в этом состоянии.


EDIT: В соответствии с просьбой, вот выход 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 
+1

Я могу вам сказать, что существует * не * открытый дескриптор файла, который висит вокруг: когда процесс завершает * любым способом * (SIGINT, '_exit', что угодно), ядро ​​автоматически закрывает каждый файл, который все еще был открыт , Тем не менее, есть * состояние, связанное с самим терминалом, а не с любым открытым файлом на нем, который может сохраняться. Было бы полезно, если бы вы могли опубликовать вывод 'strace cat/dev/ttyS0' (** NOT **' strace cat zwol

+0

@zwol Я добавил его к вопросу. –

+0

ОК, это подтверждает, что терминал оставлен в каком-то состоянии. Как насчет вывода 'stty -a -F/dev/ttyS0', пожалуйста? – zwol

ответ

2

Под POSIX, терминальных устройств (т.е. есть последовательные порты и псевдотермины) имеют a whole bunch of settings, которые позволяют компьютеру говорить множество вариаций на базовый протокол RS-232, который существует или существовал. Этот API был разработан еще в те времена, когда динозавры и teletypewriters (следовательно, «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 настроек являются ненормальными в том смысле, что программа, ориентированная на строку или файл, подключенная к последовательному порту в этом состоянии, будет неправильно вести себя. (Тем не менее, они отлично подходят для программы, которую знает, она разговаривает с серийным портом и готова справиться с последствиями превращения этих конкретных регуляторов, предположительно авторы QSerialPort знали, что они делают.) вызывающий cat, немедленно прекращается: min = 0, который (вместе со значением по умолчанию time = 0) означает, что «read() должен возвращать нулевые байты, если нет ожидающего ввода». При нормальных обстоятельствах нулевые байты, возвращаемые с read(), означают конец файла, поэтому cat немедленно прекращает работу, так как считает, что ему был доставлен пустой файл.(Этот режим, возможно, был изобретен за несколько лет до O_NONBLOCK.)

stty sane - это «способ восстановления последовательного порта», который вы искали. Документация не говорит в любом случае, но если QSerialPort::close() вызван из вашего обработчика SIGINT, то не восстановить терминал в исходное состояние, я бы счел, что ошибка в Qt. Вы также должны сделать это после получения SIGHUP, SIGQUIT, SIGABRT, SIGTERM и, возможно, SIGTSTP, SIGTTIN, SIGTTOU (но это сложнее, потому что это не фатально). Обязательно восстановите обработчик по умолчанию и снова поднимите сигнал, чтобы статус выхода был правильным.

+0

Хорошо, отлично. Поскольку я на самом деле просто повторно запускаю приложение Qt снова и снова, а не фактически нуждаюсь в доступе через 'cat', похоже, что мне даже не нужен« путь восстановления »; приложение Qt должно вести себя одинаково каждый раз, независимо от того, было ли оно выполнено раньше. Поскольку запуск программы заканчивается и вызов 'close()' фактически сохраняет работу 'cat', я предполагаю, что ошибок нет. Спасибо за помощь! –

 Смежные вопросы

  • Нет связанных вопросов^_^