Use kqueue to respond to more than one event type -
when event registered kqueue
id relating event type supplied; example file descriptor used identify file watch
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 file system event */ }
now if need respond other event types such signals need new instance of kqueue avoid conflict ident
argument of kevent()
.
kq_sig = kqueue(); struct kevent ke_sig; /* set handler , 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 */ }
watching more 1 event type appears necessitate multiple threads act on shared state (receiving signal close file descriptor example).
is there more general mechanism sending message 1 thread using kqueue? in cases can conceive of enabling , disabling filter means of edge-triggering kevent.
the kevent struct provides info event occured:
struct kevent { uintptr_t ident; /* identifier event */ int16_t filter; /* filter event */ uint16_t flags; /* general flags */ uint32_t fflags; /* filter-specific flags */ intptr_t data; /* filter-specific data */ void *udata; /* opaque user data identifier */ };
you must interested in:
ident
in case returns eitherfd
orsigint
;filter
(still in case) returns eitherevfilt_vnode
orevfilt_signal
;fflag
inevfilt_vnode
tell if file descriptor eventnote_delete
ornote_rename
.
you can register 2 kevent structures single queue , use these structure members determine if event related file descriptor or signal.
here complete example demonstrates how this:
#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) { /* single kqueue */ int kq = kqueue(); /* 2 kevent structs */ struct kevent *ke = malloc(sizeof(struct kevent) * 2); /* initialise 1 struct file descriptor, , 1 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 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 happened 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 called on file referenced descriptor.\n"); if(ke->fflags & note_write) printf("a write occurred on file referenced descriptor.\n"); if(ke->fflags & note_extend) printf("the file referenced descriptor extended.\n"); if(ke->fflags & note_attrib) printf("the file referenced descriptor had attributes changed.\n"); if(ke->fflags & note_link) printf("the link count on file changed.\n"); if(ke->fflags & note_rename) printf("the file referenced descriptor renamed.\n"); if(ke->fflags & note_revoke) printf("access file revoked via revoke(2) or underlying fileystem unmounted."); break; /* signal event */ case evfilt_signal: printf("received %s\n", strsignal(ke->ident)); exit(42); break; /* should never happen */ default: printf("unknown filter\n"); } } }
note here use single thread, way more efficient , requires no further synchronization in user space.
Comments
Post a Comment