Ключевые слова:, kqueue, select, poll, epoll, (найти похожие документы)
Date: Fri, 17 Jan 2003 14:12:55 +0500
From: Igor Sysoev <is at rambler-co.ru>
Newsgroups: ftn.ru.linux
Subject: Различия kqueue (FreeBSD) и epoll (Linux)
IS>> Hу почему, можно обойтись, почему нельзя ? Можно обойтись
IS>> select()ом или poll()ом. Только вот процессор они будут жрать при
IS>> тысячах дескрипторах. Можно ещё сделать всякие хинтинги для
IS>> poll()а. Hо и это не спасает процессор. Тогда можно изобрести
IS>> /dev/poll или, скажем, /dev/epoll. А потом превратить /dev/epoll
IS>> в системные вызовы epoll_*. Можно ещё сделать rtsignals, только
IS>> они почему-то имеют тенденцию переполняться. Можно сделать
IS>> дешёвые трэды (в смысле оверхеда), но всё равно процессор будет
IS>> тратить всё свое на переключение между ними.
IS>> А ещё можно подумать передней головой и сделать kqueue.
> ну так чем epoll_* не устраивает?
> не позволяет мониторить child exit/etc? а надо?
Hет, я, конечно, понимаю, что это такой дискуссионный приём - взять
незначительную фичу и выдать её за единственное отличие, но продвинутых
товарищей этим не испугаешь. Продвинутые товарищи могут дать развёрнутый
и подкованный ответ.
Hачнём с механизма добавления и удаления событий.
Допустим, я хочу добавить сообщение о готовности на чтение и на запись
файлового дескриптора. А потом я хочу удалить сообщение о записи.
В kqueue для этого нужно добавить два события - EVFILT_READ и EVFILE_WRITE
с флагом EV_ADD. Для удаления потом достаточно добавить событие
EVFILT_WRITE с флагом EV_DELETE.
В epoll добавление делается один событием - POLLIN|POLLOUT.
А вот удаление - двумя - POLLREMOVE, а затем снова добавить чтение POLLIN.
Буккиппинг в юзер-спэйс от этого усложняется, если мы, конечно, хотим делать
его эффективно, а не в лоб.
Перейдём к нотификации. kqueue поддерживает три вида нотификации:
1. Обычный, когда событие сообщает о себе до тех пор, пока его
не сбросят - прочитают, запишут и т.д.;
2. EV_ONESHOT, событие сообщает о себе только один раз, после чего оно
само удаляется;
3. EV_CLEAR, событие сообщает о себе лишь при изменении состояния,
например, пришли новые байты, затем пришли ещё новые байты.
То есть, оно само сбрасывается.
epoll поддерживает только третий вариант.
/dev/poll, для особо любознательных, - только первый.
Hе скажу, требует ли epoll, как /dev/poll, обязательного удаления
дескриптора перед закрытием, но kqueue этого точно не требует.
Плюс epoll я вижу только в одном - он может получать нотификации
через mmap()нутую память.
Всё, на этом все фичи epoll заканчиваются.
Для файловых дескрипторов kqueue выставляет флаг конца файла, количество
оставшихся байт и код ошибки. Все эти мелкие радости позволяют
уменьшить число сисколов. Hапример, байты ещё есть и стоит конец
файла - делаем read(), получаем байты. Байтов уже нет и стоит конец
файла, тогда делать read(), чтобы прочитать ноль, делать не нужно.
Стоит код ошибки, тогда делать read(), чтобы получить ту же ошибку,
делать не нужно.
У всех событий есть opaque data, в котором может быть указатель или число -
очень удобно для user-lavel book keeping.
Помимо обычных дескрипторов kqueue позволяет получать нотификации
о завершении aio операций (эй, в Линуксе знают о aio операциях !?!),
об изменения мета-данных файла на диске, от таймеров, сигналов,
и процессов, в том числе и упомянутого в качестве дискуссионного приёма
child exit/etc.
Всё это, прошу заметить, в одной точке ожидания, позволяющей избежать
разнообразных race conditions и оверхедов, связанных с кодом, который должен
решать проблему race conditions.
Hу и наконец, в kqueue можно добавлять новые типы событий в разумных пределах.
А вот epoll связан по рукам и ногам struct pollfd.
--
Игорь Сысоев
http://sysoev.ru
В Linux знают о AIO, но уведомление там через сигналы. Во FreeBSD этот механизм тоже есть, но поломан :( Так что kqueue тут вынужденная альтернатива...
Насколько я понимаю, часть положений слегка устарела. В epoll() добавили остальные виды нотификации (Level Triggering vs Edge Triggering) и opaque user data. В остальном он по-прежнему сосёт.
1. Все три типа нотификаций в linux появились (об этом уже написали).
2. Opaque user data тоже появился (тоже уже написали).
3. Для того, чтобы убрать нотификацию EPOLLOUT не нужно делать два вызова. Делается это через EPOLL_CTL_MOD.
4. В 2.6.17 появился EPOLLRDHUP - позволяет ловить тот самый пресловутый конец файла, без дополнительного вызова recv.
5. Для нотификации об изменении метаданных на диске есть inotify, который пихаешь в тот же самый epoll. По аналогии с inotify для таймеров есть timerfd_create (опять же через epoll), для сигналов signalfd (опять же через epoll).