读书人

调用 kqueue 接口的示范代码

发布时间: 2012-10-24 14:15:58 作者: rapoo

调用 kqueue 接口的示例代码

了解一个接口,最好的方式莫过于亲手去测试,所以直接上示例代码:

代码来自?kqueue - NetBSD System Calls Manual

这段代码的主要功能是,监控一个指定文件,并打印出收到的事件消息。(文件由程序的第一个运行参数指定)

?

?

monitor.h

?

#include <sys/types.h>#include <sys/event.h>#include <sys/time.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#include <err.h>int main(int argc, char *argv[]){  int fd, kq, nev;  struct kevent ev;  static const struct timespec tout = { 1, 0 };  if ((fd = open(argv[1], O_RDONLY)) == -1)    err(1, "Cannot open `%s'", argv[1]);  if ((kq = kqueue()) == -1)    err(1, "Cannot create kqueue");  EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK| NOTE_RENAME|NOTE_REVOKE, 0, 0);  if (kevent(kq, &ev, 1, NULL, 0, &tout) == -1)    err(1, "kevent");  for (;;) {    nev = kevent(kq, NULL, 0, &ev, 1, &tout);    if (nev == -1)      err(1, "kevent");    if (nev == 0)      continue;    if (ev.fflags & NOTE_DELETE) {      printf("deleted ");      ev.fflags &= ~NOTE_DELETE;    }    if (ev.fflags & NOTE_WRITE) {      printf("written ");      ev.fflags &= ~NOTE_WRITE;    }    if (ev.fflags & NOTE_EXTEND) {      printf("extended ");      ev.fflags &= ~NOTE_EXTEND;    }    if (ev.fflags & NOTE_ATTRIB) {      printf("chmod/chown/utimes ");      ev.fflags &= ~NOTE_ATTRIB;    }    if (ev.fflags & NOTE_LINK) {      printf("hardlinked ");      ev.fflags &= ~NOTE_LINK;    }    if (ev.fflags & NOTE_RENAME) {      printf("renamed ");      ev.fflags &= ~NOTE_RENAME;    }    if (ev.fflags & NOTE_REVOKE) {      printf("revoked ");      ev.fflags &= ~NOTE_REVOKE;    }    printf("\n");    if (ev.fflags)      warnx("unknown event 0x%x\n", ev.fflags);  }}

?

编译,并生成一个用于测试的待监控文件, 然后运行程序。

?

?

cc monitor.c -o monitortouch zhongwei.log./monitor zhongwei.log

?

对该文件进行各种操作,观察输出:

?

?

echo "Hello kqueue" >> zhongwei.log# 输出为:# extended # written touch zhongwei.log# 输出为:# chmod/chown/utimesmv zhongwei.log zhongwei2.log# 输出为:# renamed rm zhongwei2.log # 输出为:# deleted hardlinked
?

监控效果很好,很强大。看一下代码:

?

?

struct kevent ev;
?

在该示例中,结构体 kevent 用来描述待监测文件(例如,对应的 file descriptor, 需要监控的事件)。

?

?

struct kevent {             uintptr_t ident;        /* identifier for this event */             uint32_t  filter;       /* filter for event */             uint32_t  flags;        /* action flags for kqueue */             uint32_t  fflags;       /* filter flag value */             int64_t   data;         /* filter data value */             intptr_t  udata;        /* opaque user data identifier */     };

?

结构体初始化操作呢?原来在这里:

?

?

EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK| NOTE_RENAME|NOTE_REVOKE, 0, 0);
?

EV_SET 是一个宏定义,用于简化 kevent 结构体的初始化代码。

在 event.h 中可以看到 EV_SET ?的定义,这个文件位于 (系统:Mac OS X 10.6.8)

?

$ find /System/ -name event.h/System//Library/Frameworks/Kernel.framework/Versions/A/Headers/sys/event.h
??
#define EV_SET(kevp, a, b, c, d, e, f) do { \    struct kevent *__kevp__ = (kevp);   \    __kevp__->ident = (a);          \    __kevp__->filter = (b);         \    __kevp__->flags = (c);          \    __kevp__->fflags = (d);         \    __kevp__->data = (e);           \    __kevp__->udata = (f);          \} while(0)
?

现在需要仔细看一下,结构体 kevent 各成员的含义 (括号内为示例代码中传入的实际参数):

ident (fd)

事件的标识,通常使用 file descriptor 来标识。

其他值还有 EVFILT_AIO, EVFILT_SIGNAL 等。

?

filter (EVFILT_VNODE)

指定用来处理该事件的 kernel filter. 通常是系统预定义的 kernel filter.

EVFILT_VNODE 说明要监控一个文件,具体需要监控的事件类型在 fflags 中指定。

?

flags ?(EV_ADD | EV_ENABLE | EV_CLEAR)

Actions to perform on the event.

例如:EV_ADD 是将该事件加入 kqueue;

EV_ENABLE 是允许 kevent() 函数返回该事件,当其触发时。

?

?

fflags (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|NOTE_RENAME|NOTE_REVOKE)

Filter-specific flags.

?

data ?(0)

Filter-specific data value.

?

udata ?(0)

Opaque user-defined value passed through the kernel unchanged.

?

详细信息查看 man kqueue 就行。

?

?

参考文档:

1。kqueue - NetBSD System Calls Manual

?

读书人网 >编程

热点推荐