当事件向kqueue
注册与该事件相关的ID时
提供类型;例如,文件描述符用于标识文件
观看
int kq;
struct kevent ke;
kq = kqueue();
fd = open(argv[1], O_RDONLY);
EV_SET(&ke, fd, EVFILT_VNODE, EV_ADD, NOTE_DELETE | NOTE_RENAME, 0, NULL);
kevent(kq, &ke, 1, NULL, 0, NULL);
while (1) {
kevent(kq, NULL, 0, &ke, 1, NULL);
/* respond to file system event */
}
现在,如果我还需要响应其他事件类型这样的信号,我们需要一个新的
kqueue的实例,以避免与ident
参数的冲突
kevent()
。
kq_sig = kqueue();
struct kevent ke_sig;
/* set the handler and ignore SIGINT */
signal(SIGINT, SIG_IGN);
EV_SET(&ke_sig, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
kevent(kq_sig, &ke_sig, 1, NULL, 0, NULL);
while (1) {
kevent(kq_sig, NULL, 0, &ke_sig, 1, NULL);
/* respond signals */
}
观看多个事件类型似乎需要多个线程 在共享状态上执行操作(接收信号可能会关闭文件描述符 例子)。
是否有更通用的机制,用于将消息从一个线程发送到另一个线程 KQUEUE?在某些情况下,我可以设想启用和禁用过滤器作为 边缘触发另一个kevent的手段。
答案 0 :(得分:7)
kevent结构实际上提供了有关发生的事件的信息:
struct kevent {
uintptr_t ident; /* identifier for this event */
int16_t filter; /* filter for event */
uint16_t flags; /* general flags */
uint32_t fflags; /* filter-specific flags */
intptr_t data; /* filter-specific data */
void *udata; /* opaque user data identifier */
};
您必须对以下内容感兴趣:
ident
在您的情况下返回fd
或SIGINT
; filter
(仍在您的情况下)返回EVFILT_VNODE
或EVFILT_SIGNAL
; fflag
EVFILT_VNODE
中的NOTE_DELETE
会告诉您文件描述符事件是NOTE_RENAME
还是#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
int
main(int argc, char** argv)
{
/* A single kqueue */
int kq = kqueue();
/* Two kevent structs */
struct kevent *ke = malloc(sizeof(struct kevent) * 2);
/* Initialise one struct for the file descriptor, and one for SIGINT */
int fd = open(argv[1], O_RDONLY);
EV_SET(ke, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_RENAME, 0, NULL);
signal(SIGINT, SIG_IGN);
EV_SET(ke + 1, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
/* Register for the events */
if(kevent(kq, ke, 2, NULL, 0, NULL) < 0)
perror("kevent");
while(1) {
memset(ke, 0x00, sizeof(struct kevent));
if(kevent(kq, NULL, 0, ke, 1, NULL) < 0)
perror("kevent");
switch(ke->filter)
{
/* File descriptor event: let's examine what happened to the file */
case EVFILT_VNODE:
printf("Events %d on file descriptor %d\n", ke->fflags, (int) ke->ident);
if(ke->fflags & NOTE_DELETE)
printf("The unlink() system call was called on the file referenced by the descriptor.\n");
if(ke->fflags & NOTE_WRITE)
printf("A write occurred on the file referenced by the descriptor.\n");
if(ke->fflags & NOTE_EXTEND)
printf("The file referenced by the descriptor was extended.\n");
if(ke->fflags & NOTE_ATTRIB)
printf("The file referenced by the descriptor had its attributes changed.\n");
if(ke->fflags & NOTE_LINK)
printf("The link count on the file changed.\n");
if(ke->fflags & NOTE_RENAME)
printf("The file referenced by the descriptor was renamed.\n");
if(ke->fflags & NOTE_REVOKE)
printf("Access to the file was revoked via revoke(2) or the underlying fileystem was unmounted.");
break;
/* Signal event */
case EVFILT_SIGNAL:
printf("Received %s\n", strsignal(ke->ident));
exit(42);
break;
/* This should never happen */
default:
printf("Unknown filter\n");
}
}
}
。您可以将两个kevent结构注册到单个队列,然后使用这些结构成员来确定事件是否与文件描述符或信号相关。
以下是演示如何执行此操作的完整示例:
{{1}}
请注意,这里我们使用单个线程,这样效率更高,并且不需要在用户空间中进一步同步。