kqueue使用

网上搜了下关于kqueue的使用,感觉都不如意,自己翻译了一下,放在git上。

 

英文手册: https://www.freebsd.org/cgi/man.cgi?query=kqueue&apropos=0&sektion=0&manpath=FreeBSD+12.2-RELEASE+and+Ports&arch=default&format=html

 

三个接口:

int kqueue(void);

kqueue()创建一个新的内核事件队列,返回一个文件描述符。如果有错误,将返回-1,并设置error。

 

int kevent(
    int    kq, 
    const struct kevent    *changelist, 
    int nchanges,
    struct    kevent *eventlist, 
    int nevents,
    const struct timespec *timeout
);

参数changlist、eventlist都是指向kevent结构的指针,changelist是要监听的事件,如果事件发生,会放在eventlist里。

函数返回放在eventlist里事件的数量,即放了多少个事件到eventlist。

其中有个比较重要的设定,如果nevents值是0,那kevent()会立即返回;如果nevents不为0,且timeout指针为空,那么kevent()会永久阻塞,直到事件发生。

 

EV_SET(kev, ident, filter, flags, fflags, data, udata);

// kevent结构
struct kevent {
         uintptr_t    ident;         /*    identifier for this event */
         short     filter;         /*    filter for event */
         u_short   flags;         /*    action flags for kqueue    */
         u_int     fflags;         /*    filter flag value */
         int64_t   data;         /*    filter data value */
         void      *udata;         /*    opaque user data identifier */
         uint64_t  ext[4];         /*    extensions */
 };

 宏EV_SE用来初始化kevent结构体。

ident:一般是文件描述符,比如socket、文件等。

filter:不知道怎么翻译,过滤器?

flags:对这个kevent,对kqueue进行怎样操作,是添加到kqueue队列里监听,还是从kqueue队列里移除,需要指明。

fflags:filter-flags,不同的filter有不同的fflags定义,得看是用的哪个filter。

其他的参数用的时候再查。

 

手册的kqueue例子

#include <sys/event.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv) {
     struct    kevent event;     /* Event we want to monitor */
     struct    kevent tevent;     /* Event triggered */
     int kq, fd, ret;

     if (argc != 2)
         err(EXIT_FAILURE, "Usage: %s path\n", argv[0]);

     // 打开文件,拿到文件描述符
     fd = open(argv[1], O_RDONLY);
     if (fd    == -1)
         err(EXIT_FAILURE, "Failed to open '%s'", argv[1]);

     /* Create kqueue. */
     // 创建kqueue队列,返回描述符
     kq = kqueue();
     if (kq    == -1)
         err(EXIT_FAILURE, "kqueue() failed");
  
  // EV_SET(kev, ident,    filter,    flags, fflags, data, udata);
  /*
     初始化kevent结构体
     ident:为文件描述符
     EVFILE_VNODE: 用这个filter
     EV_ADD:添加到kqueue
     EV_CLEAR:每次事件被取走,状态重置
     NOTE_WRITE:每当ident指向的文件描述符有写入时返回
     不用太纠结为什么要用EVFILE_VNODE这个filter,按照官网来说,这个filter就是要用监听文件变化的。
   */
     EV_SET(&event,    fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0,    NULL);
/* Attach event to the kqueue. */ // 还记得前面的设定么?nevents为0,立即返回,返回的值是kqueue放到eventlist里的事件数量,这里eventlist为NULL,所以返回的ret是0。 // 所以这个语句的作用是向kqueue注册要监听的事件,仅此而已 ret = kevent(kq, &event, 1, NULL, 0, NULL);
if (ret == -1) // 注册失败会返回-1 err(EXIT_FAILURE, "kevent register");
if (event.flags & EV_ERROR) // 有其他错误,会置flags的EV_RROR位为1,错误数据放在data字段 errx(EXIT_FAILURE, "Event error: %s", strerror(event.data)); // 开启循环 for (;;) { /* Sleep until something happens. */ // 这里nevents不为0,eventlist为这NULL,且timeout为空指针,那会永久阻塞,直到有事件产生 ret = kevent(kq, NULL, 0, &tevent, 1, NULL);
if (ret == -1) { err(EXIT_FAILURE, "kevent wait");
}
else if (ret > 0) {
// 每当有东西写到文件里了,就会触发事件 printf("Something was written in '%s'\n", argv[1]); } } }


保存为test.c文件,编译:
gcc test.c o test

 

新建一个文件:

touch 1.txt

执行一下:
./test 1.txt

 

测试一下往1.txt写点东西:

echo "ewfwf " > 1.txt 

 

会看打印 Something was written in '1.txt'。

 

 

posted on 2021-04-22 15:54  留校察看  阅读(630)  评论(0编辑  收藏  举报

导航