Я работаю с многопоточным встроенным приложением, в котором epoll используется для ввода-вывода в одном из потоков. Я полагаюсь на особую функцию epoll, которая указывает, что закрытие файлового дескриптора автоматически удаляет его из набора epoll (вопрос/ответ 6 в man 7 epoll). В этом случае закрытие файлового дескриптора выполняется в том же потоке, в котором вызывается epoll_wait
. В конечном итоге происходит то, что epoll_wait
возвращает событие для дескриптора файла после его закрытия, и программа завершается сбоем, потому что она пытается получить доступ к ресурсам, которые были освобождены при закрытии дескриптора файла. Насколько мне известно, файловый дескриптор нигде не дублируется, хотя я не знаю, как это проверить. Я точно знаю, что нет вызовов fork()
, dup()
, dup2()
или fcntl()
с конкретной опцией дублирования. Этот конкретный дескриптор файла зарегистрирован с EPOLLOUT
, EPOLLIN
, EPOLLERR
и EPOLLHUP
. Он срабатывает по уровню. Есть ли какие-либо предостережения к этой функции, о которых кто-нибудь знает? Страница руководства неверна? Любая полезная информация, которая может помочь мне в дальнейшем отладке проблемы? Я знаю, что могу просто удалить дескриптор файла из набора, но я хотел бы знать, почему это происходит.
Epoll_wait возвращает события для дескриптора закрытого файла
comment
События, которые epoll_wait возвратил для этого файлового дескриптора, были EPOLLIN, EPOLLHUP и EPOLLERR.
- person duffsterlp   schedule 26.11.2013
comment
Вы можете использовать strace, чтобы убедиться, что ваша программа делает то, что вы думаете. Можете ли вы воспроизвести это поведение в простой однопоточной тестовой программе?
- person Craig M. Brandenburg   schedule 26.11.2013
Ответы (1)
Закрытие дескриптора файла, похоже, не удаляет его из epoll. Я попробовал это на очень простом примере на 3.12.2. Я склонен называть справочную страницу неправильной или неточной.
Что я сделал в тесте:
- создал tcp-сокет
- привязал его к локальному хосту: 5555
- настроить его на прослушивание
- создал опрос
- добавил туда сокет с hup, err и in
- немного поспал, поэтому я мог при желании подключиться к с помощью nc
- закрыл сокет
- epoll_wait
- epoll_ctl дел
- убрано
Ожидание работает, даже если сокет был закрыт, независимо от того, подключился я к нему или нет.
Изменить: The epoll_ctl_del
не удалось, если сокет был закрыт. И после прочтения текущих справочных страниц кажется, что они действительно в порядке. Страница epoll указывает на select(2) о закрытии отслеживаемого сокета, и эта страница говорит, что поведение не указано.
person
Tommi Kyntola
schedule
05.12.2013
Для записи, что я делаю на одном из своих серверов, когда соединение должно быть закрыто, я удаляю его из epoll явно (и фактически помечаю epoll для повторного ожидания, если он только что вышел из epoll_wait, который запускается в другом поток), а затем закройте и уничтожьте связанные ресурсы.
- person Tommi Kyntola; 05.12.2013
Тот факт, что epoll_ctl del сработал в вашем примере, вызывает большие подозрения. Розетка либо не закрыта, либо дублирована. Можем ли мы увидеть код?
- person Jean-Bernard Jansen; 17.10.2016
Нашел код. Конечно,
epoll_ctl_del
действительно терпит неудачу. Я сделал флаг doclose в своей тестовой программе, чтобы проверить значения ожидания epoll с закрытием сокета и без него, и я, должно быть, взял del, работающий из запуска без закрытия, когда он, конечно, работает.
- person Tommi Kyntola; 27.10.2016
Это правильно. Вот пример программы с выводом strace, чтобы доказать это: stackoverflow.com/a/51543273/432
- person andrewrk; 26.07.2018
Я думаю, что в момент события, если в epoll_wait() нет потока, это событие добавляется в список готовности (см. idndx.com/2014/09/22/the-implementation-of-epoll-3, где говорится о
rdllink
). Закрытие fd не удаляет событие из списка готовых (?), а только из списка интересов (чтобы новые события не приводили к их добавлению в этот список готовых). Если затем вызвать epoll_wait(), он ищет в этом готовом списке события, которые произошли, когда этот поток не был в epoll_wait().
- person Carlo Wood; 10.07.2019