Удалить fd из ожидающего набора pollfd одновременно с запущенным poll()

Я слежу за списком файловых сокетов и жду событий POLLIN.

Сначала я добавляю fds в массив и запускаю poll() для этого массива. Далее, в некоторых случаях я хочу удалить fd из этого массива (без закрытия). А иногда это может происходить одновременно с запущенным poll().

Как я понял при запуске poll(), ядро ​​кеширует массив с ожидающими опросами, поэтому он не может знать, что я немедленно удаляю fd, верно?

Я обнаружил, что мы можем реализовать механизм пробуждения с помощью eventfd() и использовать его для пробуждения нашего потока и удаления fd из массива, а после продолжения запустить poll() с новым массивом.

Сначала я хочу спросить, правильно ли это, что poll() не будет знать сразу, если мы просто удалим fd из массива pollfds одновременно с запущенным poll()? И это больше для пояснения, может быть, есть какой-то другой механизм для удаления fd из массива pollfds ожидания (исключая механизм пробуждения), что poll() будет немедленно прерван?

1 ответ

В pollsyscall сначала копирует предоставленный пользователем список файловых дескрипторов в буферы ядра, прежде чем начнет проверку обновлений этих файлов. Вкратце, это означает, что вы не сможете изменить список файловых дескрипторов из параллельного потока, и что системный вызов, ожидающий в этом списке, не проснется немедленно, если вы напишете в аргумент pollfds множество.

Соответствующий код для этого системного вызова находится в do_sys_pollфункция (https://elixir.bootlin.com/linux/v5.11/source/fs/select.c#L970). Это список буферов ядра, содержащий копию предоставленного пользователем списка файловых ресурсов. Во время цикла for в строках 987-1008 ядро ​​постепенно копирует массив файлов fds из. Любая одновременная запись из потоков до или во время этого состояния может изменить значения в walk. После копирования ядро ​​вызывает do_pollкоторый фактически выполняет работу системного вызова, проверяя наличие обновлений для этих файловых систем. Любой одновременно с ufdsв этот период обновляет буфер пользовательского пространства, но не версию ядра. Ядро никогда не увидит эти обновления и, следовательно, никогда не будет игнорировать любые fd, которые вы «удаляете» из этого списка (при условии, что вы имеете в виду, что вы установили для fd отрицательное значение).

Другие вопросы по тегам