Nektarios Nektarios - 7 days ago 4
C Question

How do I replace select() with kevent() for higher performance?

From the Kqueue Wikipedia Page:

Kqueue provides efficient input and output event pipelines between the kernel and userland. Thus, it is possible to modify event filters as well as receive pending events while using only a single system call to kevent(2) per main event loop iteration. This contrasts with older traditional polling system calls such as poll(2) and select(2) which are less efficient, especially when polling for events on a large number of file descriptors

That sounds great. I target FreeBSD for my server, and I'm handling a significant amount of network socket fd's - using a select() on them all and figuring out who to read data from. I'd rather use kevent() calls to get higher performance, since that's what it's there for!

I've read the man page for kevent on FreeBSD here but it's cryptic to me and I'm not finding good resources that explain it. An example of using kevent to replace select would solve my problem, and would also help me get a better idea of how kevent() is used.

Answer

First, create new kqueue:

int kq=kqueue();

Now register your fd in kq:

struct kevent kev;
kev.ident=your_fd;
kev.flags=EV_ADD | EV_CLEAR;
kev.filter=EVFILT_READ;
kev.fflags=0;
kev.data=0;
kev.udata=&your_data;

int res=kevent(kq,&kev,1,0,0,0);

Finally, wait for data to arrive into your socket:

struct kevent res_kevs[5];
int res=kevent(kq,0,0,res_kevs,5,0);

After return, res_kevs[i].ident will contain your socket's descriptor, res_kevs[i].data - number of bytes ready to be read.

See man kevent for more details and features.