调用 kqueue 接口的示例代码

57 篇文章 0 订阅

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

代码来自 kqueue - NetBSD System Calls Manual

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

 

 

monitor.h

 

C代码   收藏代码
  1. #include <sys/types.h>  
  2. #include <sys/event.h>  
  3. #include <sys/time.h>  
  4. #include <stdio.h>  
  5. #include <unistd.h>  
  6. #include <stdlib.h>  
  7. #include <fcntl.h>  
  8. #include <err.h>  
  9.   
  10. int main(int argc, char *argv[])  
  11. {  
  12.   int fd, kq, nev;  
  13.   struct kevent ev;  
  14.   static const struct timespec tout = { 1, 0 };  
  15.   
  16.   if ((fd = open(argv[1], O_RDONLY)) == -1)  
  17.     err(1, "Cannot open `%s'", argv[1]);  
  18.   
  19.   if ((kq = kqueue()) == -1)  
  20.     err(1, "Cannot create kqueue");  
  21.   
  22.   EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,  
  23.      NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|  
  24.      NOTE_RENAME|NOTE_REVOKE, 0, 0);  
  25.   
  26.   if (kevent(kq, &ev, 1, NULL, 0, &tout) == -1)  
  27.     err(1, "kevent");  
  28.   
  29.   for (;;) {  
  30.     nev = kevent(kq, NULL, 0, &ev, 1, &tout);  
  31.     if (nev == -1)  
  32.       err(1, "kevent");  
  33.     if (nev == 0)  
  34.       continue;  
  35.     if (ev.fflags & NOTE_DELETE) {  
  36.       printf("deleted ");  
  37.       ev.fflags &= ~NOTE_DELETE;  
  38.     }  
  39.     if (ev.fflags & NOTE_WRITE) {  
  40.       printf("written ");  
  41.       ev.fflags &= ~NOTE_WRITE;  
  42.     }  
  43.     if (ev.fflags & NOTE_EXTEND) {  
  44.       printf("extended ");  
  45.       ev.fflags &= ~NOTE_EXTEND;  
  46.     }  
  47.     if (ev.fflags & NOTE_ATTRIB) {  
  48.       printf("chmod/chown/utimes ");  
  49.       ev.fflags &= ~NOTE_ATTRIB;  
  50.     }  
  51.     if (ev.fflags & NOTE_LINK) {  
  52.       printf("hardlinked ");  
  53.       ev.fflags &= ~NOTE_LINK;  
  54.     }  
  55.     if (ev.fflags & NOTE_RENAME) {  
  56.       printf("renamed ");  
  57.       ev.fflags &= ~NOTE_RENAME;  
  58.     }  
  59.     if (ev.fflags & NOTE_REVOKE) {  
  60.       printf("revoked ");  
  61.       ev.fflags &= ~NOTE_REVOKE;  
  62.     }  
  63.     printf("\n");  
  64.     if (ev.fflags)  
  65.       warnx("unknown event 0x%x\n", ev.fflags);  
  66.   }  
  67. }  

 

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

 

 

Shell代码   收藏代码
  1. cc monitor.c -o monitor  
  2. touch zhongwei.log  
  3. ./monitor zhongwei.log  

 

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

 

 

Shell代码   收藏代码
  1. echo "Hello kqueue" >> zhongwei.log  
  2. # 输出为:  
  3. # extended   
  4. # written   
  5.   
  6. touch zhongwei.log  
  7. # 输出为:  
  8. # chmod/chown/utimes  
  9.   
  10. mv zhongwei.log zhongwei2.log  
  11. # 输出为:  
  12. # renamed   
  13.   
  14. rm zhongwei2.log   
  15. # 输出为:  
  16. # deleted hardlinked  
 

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

 

 

C代码   收藏代码
  1. struct kevent ev;  
 

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

 

 

C代码   收藏代码
  1. struct kevent {  
  2.              uintptr_t ident;        /* identifier for this event */  
  3.              uint32_t  filter;       /* filter for event */  
  4.              uint32_t  flags;        /* action flags for kqueue */  
  5.              uint32_t  fflags;       /* filter flag value */  
  6.              int64_t   data;         /* filter data value */  
  7.              intptr_t  udata;        /* opaque user data identifier */  
  8.      };  

 

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

 

 

C代码   收藏代码
  1. EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,  
  2.      NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|  
  3.      NOTE_RENAME|NOTE_REVOKE, 0, 0);  
 

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

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

 

Shell代码   收藏代码
  1. $ find /System/ -name event.h  
  2. /System//Library/Frameworks/Kernel.framework/Versions/A/Headers/sys/event.h  
  
C代码   收藏代码
  1. #define EV_SET(kevp, a, b, c, d, e, f) do { \  
  2.     struct kevent *__kevp__ = (kevp);   \  
  3.     __kevp__->ident = (a);          \  
  4.     __kevp__->filter = (b);         \  
  5.     __kevp__->flags = (c);          \  
  6.     __kevp__->fflags = (d);         \  
  7.     __kevp__->data = (e);           \  
  8.     __kevp__->udata = (f);          \  
  9. 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值