FreeBSD, 07 лекция (от 13 октября)
Материал из eSyr's wiki.
Сегодня про файловые дескрипторы, как это выглядит со стороны ядра.
Два интерфейса -- один старый, один новый, оба достаточно успешны.
Что такое вообще дескриптор?
Есть несколько разных способов получить дескриптор из разных областей, при этом порождаются сущности, у которых много общего. Немножко ооп, открытый файл рассматриваем как некоторую сущность и неважно, что лежит за ней.
дескриптор некая сущность открытая в ядре для нашего процесса, которую мы можем адресовать числом.
Почти все дескрипторы поддерживают рид-райт. Почти все могут дуплицироваться. Разница между дупфд и открыть еще раз? Будут разные указатели сиг. При форке наследуются дескрипторы, при екзеке по умлочанию тоже, если не указан на дескрипторе специальный флаг.
Хак -- один процесс может передать другому дескриптор.
Мы делаем запись в сокет не сенд, а сендмсг с специальной дополнительной информацией, и принимающая сторона имеет уже готовый дескриптор.
Например, форкается вебсервер, и хочет определенные типы соединений отдавать определенному типы детей. Есть и еще варианты применения.
Что такое дескриптор изнутри ядра?
У процесса есть циферка, она сопоставлена стракт внутри ядра.
filedesc.h
Как происходит ассоциация?
У каждого процесса есть указатель на таблицу дескрипторов. Можете обратить внимание, что дескрипторы выдаются последовательно. Это оптимизация, чтобы номером дескриптора сразу адресоваться в массиве, в котором они хранятся.
На самом деле, после фрибсд9 появилась промежуточная структура, и таблица строится из нее, а в ней уже указатель на struct file.
Зачем?
Представим, что процесс открыл несколько дескрипторов.
Некоторым достаточно два дескриптора, вход и выход. Программа может закрыть для себя возможность создавтаь любые другие дескрипторы. capability mode. Программа становится внезапно безопасной. capsicum в фрибсд9, и интегрирована в фрибсд10.
Капабилити -- расширенное понятие дескриптора. Не только указатель на стракт файл, но и маска что с этим можно делать.
Если дескриптор указывает не на файл а на девайс, то строго ограниченный список того как можно иоктл к нему обратиться.
Маску можно только ужесточать.
Итак, это промежуточная структура получает дополнительное поле struct filecaps fde_caps.
В ней хранится 64 битная маска, man cap_enter.
Дальше указатель на вектор ioctl. Если делаем на дескриптор иоктл, он должен быть из этого массива. И аналогично fcntls.
Давайте обсудим вопрос того, как можно мультиплексировать работу с множеством открытых файлов, сокетов.
Типичная работа приложения -- реакция на множество событий -- появились данные считали, появилось место записали.
Старое апи select.
Есть макрос FD_SET, которые представляет собой битовый массив, и мы поднимаем те биты, которые соответствуют номерам дескрипторов которые нас интересуют.
Можем передать до трех фдсетов, для ожидания разных событий.
Другой интерфейс из sysV -- poll. Тоже самое вид сбоку -- структура с номером дескриптора, списком событий, которую мы передаем и ждем.
О недостатках.
Реализованы они очень похоже (kern_descrip.c)
Идет проход по всем дескрипторам и смотрится можно ли с ним что-то сделать. Если ничего не нашлось, то на каждом нижележащем объекте выставляется флажок, что его кто-то ждет, и уходим в сон. Потом одно из вышеуказанных событий нас будит, и мы все ресканируем.
Полл реализован точно так же, только идем не по битам, а по массиву структур.
Проблемы.
Сложность о от количества открытых дексрипторов, а не активных. Если приложение открывает кучу айдл дескрипторов, этот вызов очень сильно нагружается.
Мы можем передать мало дескрипторов.
Каждый раз будем передавать все открытые дескрипторы.
В случае селекта передаем всегда 1024 бита.
Чтобы изменить лимит в 1024 надо перекомпилить либс, ядро и ...
С поллом мы передаем в 64 раза больше.
Как только дескрипторов больше 16, селект становится выгодней.
c10k problem
С апачом была проблема. Его пытались делать многопоточным, перекомпилировать, но это не решало основной проблемы -- полл практически сразу возвращался ради 1-3 дескрипторов, и его приходилось перевызывать передавая обратно все 10000.
whatsapp держит на одной фрибсд машине 2 000 000 соединений.
Появился новый интерфейс.
Какие к нему требования?
1. ядро должно помнить, что хотело приложение, чтобы приложение не засылало каждый раз весь массив. 2. было бы здорово, если бы он не зацикливался на дескрипторах, а был более общим. На момент написания были еще сигналы. Было бы здорово все события туннелировать в один интерфейс. О судьбе детей, об асинхронном ио. Максимально общий и бесконечно расширяемый. 3. Было бы здорово, если бы мы могли сделать несколько таких сущностей в одном процессе.
Еще хотелось бы, чтобы был выбор между двумя типами понятия евента. Когда в сокете появляется место или всегда когда в сокете есть место.
Называется kevent
kqueue возвращает дескриптор.
kevent собственно мультиплексор, который позволяет добавлять события.
Структура
1. идентификатор события. В простейшем случае номер дескриптора. 1. фильтр -- чтения, записи, то и то. 1. флаги что делать с событием -- добавить, убрать. 1. фильтроспецифичные флаги 1. фильтроспецифичные данные 1. указатель на юзерспейс адрес, который будет возвращен приложению для опознавания ивента. Ядро гарнатирует его неприкосновенность.
Со стороны ядра это выглядит как очереди. Ключевая структура knote -- событие.
Когда мы в kevent закидываем событие, они у нас попадают в массив событий, в которых приложение заинтересовано. Когда событие происходит нижняя часть ядра кладет в другой список -- список событий, которые стали активны. Список активных является подмножеством списка наблюдаемых. Возвращается только список активных.
Соответственно на каждой сущности, которую отображает файловый дескриптор, у нее тоже есть список knotes -- список тех, кто заинтересован в активности на этом объекте.
Примеров программирования на кевент со стороны приложения очень много.
Со стороны ядра может быть попробуем на практикуме.
Что будет, если рейс кондишн на евентах? Сами виноваты. Это штатная ситуация, приложение дизайнится с учетом этого.
В inotify есть возможность ставить нотифай на директории, есть здесь такое?
Да, конечно.
Само ядро может модифицировать kqueue?
Пример задачи на капабилити -- заизолировать пинг, чтобы у него было только три стандартных дескриптора и ро сокет.
Для чего нужна передача дескрипторов через локальный сокет?
Мастер процесс, который открывает дескриптор сам и передает детям.
В фрибсд11 разрабтывается общий мастерпроцесс, раздающий капабилити всем мелким демонам -- casper.
Пока закапабиличен tcpdump.
Для домашнего изучения рекомендуется попробовать capsicum и kevent. Потом на каком-нибудь практикуме попробуем посмотреть на kevent со строны ядра.
15 декабря в яндексе будет конференция по бсд. Они не спешат делать публичный анонс. На конференцию приедут опенбсдшники во главе со своим главарем.
В следующий раз про efs и реальные файловые системы.
Дизайн и реализация ОС FreeBSD
01 02 03 04 05 06 07 08 09 10 11 12
Календарь
Октябрь
| 02 | 09 | 16 | 23 | 30 |
Ноябрь
| 06 | 13 | 20 | 27 | |
Декабрь
| 04 | 11 | 18 |