Как я могу определить, когда кто-то открывает подчиненную сторону pty (псевдотерминала) в Linux? - PullRequest
10 голосов
/ 15 августа 2010

Наличие более одного процесса, считываемого с последовательного устройства (/ dev / ttyXX), делает так, что оба процесса не могут получить все данные - данные каким-то образом будут разделены между ними.Я хотел бы написать программу, которая читает с последовательного устройства, создает несколько пар pty master / slave, а затем позволяет программам, которые были созданы для чтения с последовательного устройства, вместо этого читать с ptys, чтобы все процессы чтения получали данныеот последовательного устройства и заставить ptys действовать как последовательное устройство в том смысле, что когда они начинают читать из pty, они получают только самые последние данные.Другими словами, вы не получите никаких данных, которые были записаны до того, как вы начали читать (по моему опыту, именно так работают устройства / dev / ttyXX или, по крайней мере, анемометр RS-232, с которого я читаю).Именованные каналы могут имитировать эту семантику, перехватывая SIGPIPE, чтобы определить, что читателя нет, и, следовательно, мы можем не записывать в этот конкретный именованный канал.Однако некоторые двоичные файлы, которые были написаны для использования терминалов, могут давать сбой при обращении к именованным каналам, так как проверка isatty () и условие errno для вызовов, таких как tcsetattr (), могут вызвать сбойные условия.Ключевым моментом здесь является возможность использовать существующие двоичные файлы, которые были написаны для терминала.

Итак, если я могу определить, когда подчиненная сторона pty открыта для чтения, это должно дать мне примерно ту же семантикупоскольку в случае именованного канала не было SIGPIPE.Я заметил, что HP-UX имеет команду TIOCTRAP в качестве команды ioctl (), которая, кажется, выполняет именно то, что я хочу, но, к сожалению, она недоступна в Linux.

Я читал ссылки в течение нескольких дней и количестваВарианты для такого типа вещей просто поражают.Ответ может заключаться в настройках терминала, блокировании / неблокировании, установке размеров буфера где-либо, условиях, о которых сообщается в poll () / select (), или некоторой комбинации.Кажется, я ничего не могу найти.Я задаюсь вопросом, возможно ли, что мне нужно написать свой собственный драйвер устройства, но кажется, что я должен быть в состоянии сделать это, не заходя так далеко.

Итак, для пояснения:
- Вопросявляется: Как я могу определить, когда кто-то открывает ведомую сторону pty (псевдотерминала) в Linux?
- я хочу, чтобы читатель, открывающий ведомую сторону pty, получал данные, записанные строго после того, как считыватель открыл pty (если мой процесс многократной записи просто записывает данные на некоторое время, прежде чем считыватель открывает ведомую сторону, данные буферизируются, и в конечном итоге записывающее устройство блокируется, и ведомое считывающее устройство при открытии немедленно получает все буферизованные данные - этоне желательно, так как я хочу, чтобы он получал только данные, сгенерированные в непосредственной близости от времени)
- Это должно быть pty, а не именованным каналом, сокетом и т. д., как isatty () и tcsetattr ()и т.д. должны быть в порядке, чтобы существующие двоичные файлы работали

Ответы [ 2 ]

11 голосов
/ 16 августа 2010

Причина, по которой вы не можете найти это, заключается в том, что нет задокументированного интерфейса, который бы позволял это делать.Однако есть хитрость, которая позволяет вам сделать это.После открытия мастера псевдотерминала (в данном случае это дескриптор файла ptm), вы открываете и немедленно закрываете подчиненную сторону:

close(open(ptsname(ptm), O_RDWR | O_NOCTTY));

Это устанавливает флаг HUP на мастере tty.Теперь вы регулярно опрашиваете флаг HUP с помощью poll() (скажем, всякий раз, когда данные поступают из вашего источника данных):

struct pollfd pfd = { .fd = ptm, .events = POLLHUP };
poll(&pfd, 1, 10 /* or other small timeout */);

if (!(pfd.revents & POLLHUP))
{
    /* There is now a reader on the slave side */
}

Если читатель когда-либо отключается, POLLHUP будет установлен снова.*

В вашем случае вам, вероятно, даже не нужно запоминать из одного цикла в другой, есть ли у данного pty читатель - просто заблокируйте read() в вашем источнике данных, затем, когда данные доступны, одновременно poll() все ваши мастер-тты и отправьте данные любому из них, для которого не установлен POLLHUP.

3 голосов
/ 23 апреля 2011

Добавьте часы inotify на подчиненного pty и опросите его.Вы можете получить событие inotify на открытии.Затем вы можете опросить дескриптор файла inotify и дескриптор главного файла pty.Вы можете получить событие inotify для открытия (IN_OPEN).Это разблокирует опрос при открытии ведомой стороны.

...