LINUX.ORG.RU

Linux, tty, select() - некорректное поведение при наличии данных в буффере


0

2

имеется некий демон, который общается с ком-портом и отправляет/забирает данные; + к тому он общается по сети. Ожидание событий (поступление данных в буффер tty либо соединение с сокетом) реализовано через select() Итого имеем такой кусочек кода:

    if (FD_ISSET(tty.fd, &sdsetrd))
      logw(5, "conn_loop(): select(): tty.fd is present");
    rc = select(max_sd + 1, &sdsetrd, &sdsetwr, NULL, &t_out);
    ioctl(tty.fd, FIONREAD, &i);
    logw(5, "conn_loop(): select(): %d descriptors ready, there are %d bytes in buffer", rc, i);

И этот кусочек кода при наличии в буфере всего 1 байта выдает парадоксальный результат:

1312484897:018074 conn_loop(): select(): tty.fd is present
1312484897:109351 conn_loop(): select(): 0 descriptors ready, there are 1 bytes in buffer

Т.е. - select() считает буфер tty, содержащий 1 байт, пустым. При наличии в буффере 2 байт (или более) - все прекрасно работает.

Багу выловил на ядре 3.0, но в 2.6.35.13, если не ошибаюсь, она тоже присутствовала. От системных библиотек (glibc/uclibc) не зависит. GCC 4.4.5. Собссно вопрос: это баг или я чего-то не понял из мануала? :)

P.S. max_sd - заведомо больше номера дескриптора tty, так что собака не здесь порылась.

★★★★★

Последнее исправление: NiTr0 (всего исправлений: 1)

код ошибки от ioctl не проверен...

и да, помнится такой баг для UDP-сокетов - когда пришёл пакет с битой контрольной суммой - селект говорит ОК! данные есть. начинаешь читать - а их нет!

mmarkk
()
Ответ на: комментарий от NiTr0

вообще говоря, селект может вернуть ноль только по таймауту...если предположить, что внутри структуры, описывающей таймаут - нули - то поведение селекта при таком таймауте непредсказуемо - может дескрипторы опросить - а может сразу ноль дать.

mmarkk
()
Ответ на: комментарий от mmarkk

ioctl вставил для наглядности. Данные в буфере точно есть т.к. 1) софтина, что их засылает туда по нуль-модему пакетом, работает в соседнем терминале и 2) при последующем чтении вместо 9 байт читается 10, и 1й байт - из предыдущего пакета. Т.е. вопрос «есть ли данные в буфере» не стоит; данные 100% есть. А вот почему select пучит и как/где его лечить - хотелось бы мне знать...

NiTr0 ★★★★★
() автор топика
Ответ на: комментарий от mmarkk

Возвращает-то ноль да, по тайм-ауту, через 100+ мсек. При наличии данных в буффере. Выше постом про тайм-аут нечетко выразился.

NiTr0 ★★★★★
() автор топика
Ответ на: комментарий от NiTr0

Есть подозрение, что байт там есть, а прочитать его нельзя )) ну типа не дошёл какой-нибудь стоповый бит. попробуй для теста сразу после селекта сделать read() на один байт. проверь таймаут - поставь одну секунду. если таки прочитает - видимо, жук в ведре.

Возможно, он у тебя читает 10 байт именно потому что пришли 9 дополнительных. а если бы они не пришли - то возможно один байт оно бы и не смогло прочитать. надо проверить.

mmarkk
()
Ответ на: комментарий от mmarkk

Вызов read() - прекрасно читает оставшийся байт. + если бы байт не дошел, он бы в буфере никак не появился. Кроме всего прочего, судя по логам, байты выгребаются парами - что при скорости 9600 и шустром проце наводит на мысль о баге где-то.

P.S. Переписать на нормальный полл будет проблематично, поллинг tcp сессий и т.д.... на любителя в общем. Слишком уж переписывать логики много надо будет

NiTr0 ★★★★★
() автор топика
Ответ на: комментарий от mmarkk

> а что, полл в этой ситуации лучше?

poll всегда лучше - во-первых, он яснее, во-вторых, select давно уже deprecated, в-третьих, и select, и poll всё равно реализуются методом ->poll драйвера.

tailgunner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.