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

2019-06-19 01:33发布

问题:

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.

回答1:

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.



回答2:

What you do normally, is use libevent, which takes care of all the details for you, and also means that you can move your program on to another OS which has a different scheme (e.g. Linux and epoll) for doing something similar.