Ключевые слова:freebsd, kqueue, select, (найти похожие документы)
From: Илья Воронин <http://www.ivoronin.pp.ru/>
Date: Mon, 28 Feb 2005 18:21:07 +0000 (UTC)
Subject: Краткое введение в kqueue/kevent.
Оригинал: http://www.zlug.pp.ru/book/view/164
kqueue предоставляет механизм уведомления процесса о некоторых
событиях, произошедших в системе. Впервые этот интерфейс появился в
FreeBSD 4.1 и на данный момент присутствует практически во всех BSD
системах. (в Linux есть его аналог - epoll()).
Как это работает: процесс с помощью вызова kqueue() получает
дескриптор очереди сообщений ядра (в случае ошибки процесс
завершается):
if ( ( kq = kqueue() ) == -1 )
exit(1);
затем с помощью kevent() устанавливает, сообщения о каких именно
событиях он желает получать. Например, мы хотим знать когда файл
(которому соотвествкует дескриптор fd) изменится:
/*
* Здесь:
* ke - структура kevent. (EV_SET это просто макрос, который заполянет
* её элементы.
* fd - дескриптор файла, за изменениями которого мы хотим наблюдать.
* EVFILT_VNODE - тип фильтра - в данном случае мы следим за vnode.
* EV_ADD, EV_CLEAR - флаги, EV_ADD - добавить событие, EV_CLEAR - не
* удалять событие из очереди, после первого его возникновения.
* NOTE_WRITE - аргументы фильтра. Следить за записями в файл.
* 0 - Какие-то дополнительные данные Smiling )
* NULL - тут можно указать любой указатель, ядро просто вернет его при
* получении события. Как это можно использовать: допустим мы
* следим за измением нескольких файлов, и перечитываем их при
* надобности, - можно поместить сюда указатель наструктуру вида:
* struct {
* int fd;
* char * pathname;
* } kqfile;
* и тогда при получении события, мы сможем быстро узнать -
* какой именно файл изменился и тут же его перечитывать.
*/
EV_SET(&ke, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);
/*
* Собственно сама регистрация события.
*/
if ( kevent(kq, &ke, 1, NULL, 0, NULL) == -1 )
exit(1);
Как потом получать события:
while(1)
if ( kevent(kq, NULL, 0, &ke, 1, NULL) != -1 )
printf("A write occurred on the file.\n");
Функция kevent() в данном случае блокирует процесс до тех пор пока не
наступит событие. (причём если мы задали несколько фильтров, можно по
возвращенной структуре ke определить - какое именно событие
произошло).
Полный пример программы:
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/event.h>
extern char * __progname;
int main(int argc, char * argv[]){
int fd, kq;
struct kevent ke;
if ( argc < 2 )
errx(1,"usage: %s file",__progname);
if ( ( fd = open(argv[1], O_RDONLY, NULL) ) == NULL )
err(1,"%s:%i",__FILE__,__LINE__);
if ( ( kq = kqueue() ) == -1 )
err(1,"%s:%i",__FILE__,__LINE__);
bzero(&ke,sizeof(ke));
EV_SET(&ke, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);
if ( kevent(kq, &ke, 1, NULL, 0, NULL) == -1 )
err(1,"%s:%i",__FILE__,__LINE__);
bzero(&ke,sizeof(ke));
while(1)
if ( kevent(kq, NULL, 0, &ke, 1, NULL) != -1 )
printf("A write occurred on the file.\n");
return 0;
}
Прошу прощения за сумбурность изложения =),
Много информации можно найти в man kqueue.
Сравнение BSD's kqueue() и Linux's epoll() -
http://www.opennet.dev/base/dev/kqueue_vs_epoll.txt.html