Цикл poll()
делает упрощенческое предположение о том, что он всегда может записать столько, сколько в состоянии прочитать. Это почти всегда верно и не вызывает проблем на практике, поскольку блокирование на короткие периоды незаметно при нормальных условиях. Цикл никогда не считывает из файлового дескриптора, пока poll()
не сообщит, что файловый дескриптор ожидает считывания данных, чтобы мы знали, что блокировки во время чтения нет.
Для данных, поступающих с клавиатуры, может понадобиться обработка управляющих последовательностей перед записью, если пользователь не выбрал неформатируемый режим при запуске robin
. Вместо включения этого кода в цикл мы вызываем функцию cook_buf()
(строка 78), которая при необходимости обращается к send_escape()
(строка 58). Обе эти функции просты. Единственный трюк состоит в том, что cook_buf()
может быть вызвана один раз с управляющим символом, а затем второй раз с интерпретируемым символом, а также в оптимизации количества вызовов функции write()
.
Функция cook_buf()
вызывает функцию send_escape()
один раз для каждого символа, которому предшествует неотменяемый управляющий символ ^\
. Символ q
восстанавливает исходные установки termios
и завершается вызовом обработчика сигнала (с фальшивым номером сигнала 0), что восстанавливает настройки termios
перед выходом. Символ b
генерирует состояние разрыва, которое является длинной строкой, состоящей из нулей. Любой другой символ, включая второй управляющий символ ^\
, передается в последовательный порт без изменений.
Если какой-то из входных файловых дескрипторов вернет признак конца файла, robin
выходит из цикла poll()
и передает управление обработке завершения, что соответствует обработчику сигнала: восстановление старых настроек termios
на обоих входных файловых дескрипторов и завершение. В неформатируемом режиме существует только два способа завершения robin
: закрыть один из файловых дескрипторов или передать ей сигнал.
16.4. Отладка termios
Отладка кода tty далеко не всегда проста. Варианты пересекаются и влияют друг на друга разными способами, часто незапланированными. Но с помощью лишь отладчика невозможно увидеть то, что происходит, поскольку обработка, которой вы пытаетесь управлять, происходит в ядре.
Эффективным способом отладки кода, передающего информацию через последовательный порт, является использование программы-сценария. Во время разработки robin
мы соединили два компьютера последовательным кабелем и убедились, что соединение работает, запустив известную программу kermit
. В то время как программа kermit
уже работала на локальном компьютере, мы запустили программу-сценарий на удаленном компьютере, которая начала регистрировать все символы в файле. Затем мы вышли из kermit
и запустили сценарий на локальном компьютере, поместив полученный файл в текущий каталог на местном компьютере. Затем мы попытались запустить robin
по сценарию и сравнили два файла в начале и после каждого запуска, чтобы проследить разницу в символах. Таким образом мы разобрались с эффектами выбранных опций обработки.
Еще один метод отладки использует преимущества программы stty. Если во время проверки программы вы распознаете ошибку в настройках termios
, можете воспользоваться программой stty для немедленного внесения изменений вместо повторной компиляции своей программы. Если вы работаете на /dev/ttyS0
и хотите установить флаг ECHOCTL
, просто во время работы своей программы запустите следующую команду:
stty echoctl < /dev/ttyS0
Подобным же образом можно отображать текущее состояние используемого в данный момент порта:
stty -а < /dev/ttyS0
Как объяснялось ранее, трудно использовать один tty для запуска отладчика и программы искажения tty, которая отлаживается. Вместо этого следует присоединиться к процессу. Это не сложно. В одном сеансе X-терминала (делайте это под управлением X Window, чтобы одновременно видеть оба tty) запустите программу, которую собираетесь отладить. В случае надобности поместите ее в долгий режим ожидания в точке, где вы собираетесь присоединиться к процессу:
$ ./robin -b 38400 /dev/ttyS1
Теперь с помощью другого сеанса X-терминала найдите идентификатор процесса программы, которую вы пытаетесь отладить, одним из двух способов:
$ ps | grep robin
30483 ? S 0:00 ./robin - b 38400 /dev/ttyS1
30485 ? S 0:00 grep robin
$ pidof robin
30483
Более удобным является pidof
, но он может быть недоступен в системе. Запомните найденный номер (в данном случае 30483) и начните обычный сеанс отладки.
$ gdb robin 30483
GDB is free software...
...
Attaching to program '... /robin', process 30483
Reading symbols from...