kqueue

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 21:26, 29 ноября 2016.

kqueue — это масштабируемый интерфейс уведомления о событиях. Впервые появился во FreeBSD 4.1[1], также поддерживается в NetBSD, OpenBSD, DragonflyBSD, и Mac OS X. Kqueue позволяет пользователям оперативно получать уведомления о событиях в системе.

Принцип работы

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);
</console>
Как потом получать события:
<syntaxhighlight lang="bash">
while(1)
        if ( kevent(kq, NULL, 0, &ke, 1, NULL) != -1 )
                printf("A write occurred on the file.\n");

Функция kevent() в данном случае блокирует процесс до тех пор пока не наступит событие. (причём если мы задали несколько фильтров, можно по возвращенной структуре ke определить - какое именно событие произошло)[2].

Полный пример программы:

#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;
}

Примечания

  1. Kqueue: A generic and scalable event notification facility [Электронный ресурс] : Материал из http://people.freebsd.org/: — Режим доступа: http://people.freebsd.org/~jlemon/papers/kqueue.pdf
  2. Краткое введение в kqueue/kevent [Электронный ресурс] : Материал из http://www.opennet.ru/: — Режим доступа: http://www.opennet.ru/base/dev/kqueue_overview.txt.html