调用 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 monitor
touch zhongwei.log
./monitor zhongwei.log

 

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

 

 

echo "Hello kqueue" >> zhongwei.log
# 输出为:
# extended 
# written 

touch zhongwei.log
# 输出为:
# chmod/chown/utimes

mv 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

 

你可能感兴趣的:(Queue)