Как работат select()?

Я бы хотел узнать, что в нем происходит. Видел исходники, но разобраться в них мне крайне сложно. Просто суть хочу узнать. Есть набор файловых дескрипторов, пусть мы их все проверяем на готовность к чтению. У select есть бесконечный цикл, там, он, по всей видимости, пробегается по всем дескрипторам и... И что дальше? какую информацию в себе хранит файловый дескриптор, что ему говорит, что файл готов к чтению?

https://elixir.bootlin.com/linux/latest/source/fs/select.c


Ответы (3 шт):

Автор решения: KoVadim

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

То есть, как именно внутри реализован select - это детали конкретной операционной системы (скажу больше в windows и linux они только визуально похожи, а внутри совершенно по разному устроены).

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

Что же такое "файловый дескриптор"? считайте это просто неким номерком, по которому операционная система внутри себя сопоставляет с реальным объектом.

→ Ссылка
Автор решения: Sergey

У select есть бесконечный цикл

В ядре ОС нет никакого цикла. Иначе бы Ваш вызов select подвесил всю систему. Всё построено на прерываниях.

какую информацию в себе хранит файловый дескриптор

Это совершенно не важно. Тем боле, что в разных ОС - разную. Просто с точки зрения ОС, ваш сокет - это почти обычный файл. А все файлы описываются соответствующими дескрипторами и имеют свой номер в таблице дескрипторов.

Вызывая select() Вы просто говорите ОС, что вы ожидаете прихода прерывания от любого из перечисленных в наборе сокетов (файлов).

что ему говорит, что файл готов к чтению?

Предположим, что Вы пытаетесь отправить на печать строку текста. А принтер не готов. Что произойдёт? Функция вывода (например - printf()) повиснет на ожидании готовности. Вы нажимаете на принтере кнопочку "Вкл", принтер начинавет работать и посылает прерывание ОС. Ядро ОС забирает буфер из printf() и отправляет его на устройство.

Аналогично происходит и с сокетами. Передавая select() наборы сокетов, Вы говорите ОС, что Вас интересует возможность прочитать или записать данные в сокеты, которые заданы их парами IP/Port. Когда драйвер сетевой карточки получает пакет данных с соответствующей парой IP/Port он посылает прерывание сетевой подсистеме ядра ОС. Та снимает с ожидания Вашу программу и сообщает ей, какой конкретно сокет готов к передаче данных. Вы их забираете, обрабатывает и опять повисаете на srlrct()...

→ Ссылка
Автор решения: avp

Если разобрать фунцию do_select(), то можно выяснить следующее.

В структуре связанной с файловым дескриптором (продолжение тут и тут) есть указатель на специфичную для каждого типа файловых дестрипторов (сокет, терминал, plain file и т.д.) функцию poll, которая вызывается вот тут mask = vfs_poll(f.file, wait); в "бесконечном цикле" в do_select().

Именно она определяет, есть ли готовые для чтения данные или готов ли дескриптор в данный момент для записи данных или есть ли в данный момент прочие события, связанные с дескриптором.

Если такие (заданные в передаваемой в select маске) дескрипторы обнаружены, то мы возвращаемся (также возвращаемся при получении сигнала и истечении таймаута). Если готовых дескрипторов нет, то ожидаем, передавая управление в scheduler, тем самым возобновляя какой-то из других процессов OS, готовых к исполнению.

→ Ссылка