Use kqueue to respond to several types of events

When an event is logged with a kqueue identifier, the type associated with this event is supplied; for example a file descriptor is used to identify the file to look

 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 */ } 

Now, if I also need to respond to other types of events, such signals, we need a new instance of kqueue to avoid conflict with the ident kevent() argument.

 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 */ } 

Observing several types of events requires several threads that act in general condition (receiving a signal may close the file descriptor for example).

Is there a more general mechanism for sending messages from one thread to another using Kqueue? In some cases, I can imagine turning the filter on and off as a means to trigger the edge of another cement.

+6
source share
1 answer

The kevent structure actually provides information about the event that occurred:

 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 */ }; 

You must be interested in:

  • ident , which in your case returns either fd or SIGINT ;
  • filter , which (still in your case) returns either EVFILT_VNODE or EVFILT_SIGNAL ;
  • fflag , that EVFILT_VNODE will indicate whether a file descriptor event was NOTE_DELETE or NOTE_RENAME .

You can register two event structures in one queue, and then use these structure elements to determine if the event is associated with a file descriptor or signal.

Here is a complete example demonstrating how to do 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) { /* 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 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"); } } } 

Please note that here we use one stream, which is more efficient and does not require further synchronization in user space.

+7
source

All Articles