I'm having a problem that I'm not sure if the behavior is expected from kqueue or if this is something I am doing wrong.
I need to set separate events using kqueue for a single socket file descriptor. Separate events - one for (sockfd, EVFILT_READ) and (sockfd, EVFILT_WRITE). However, when I pull events from kqueue, I get two events from kqueue, but both events contain (event.filter and EVFILT_READ) and (event.filter and EVFILT_WRITE).
I need them to be separate, otherwise I donβt know what event is really ready to read or write?
Here is an example of the code that I put together to illustrate the problem. Please keep in mind that this is just a test code to understand why I get both filter flags in each case.
int main(int argc, char ** argv) { //listening_sockfd = setup listening socket //setup kqueue and vars int kq = kqueue(); int res = 0; int bufres = 0; struct timespec ts = {0}; struct timespec * tsp = &ts; struct kevent ke2[2]; //install read for listening socket struct kevent ke1; bzero(&ke1,sizeof(ke1)); ke1.ident = listening_sockfd; ke1.flags = EV_ADD; ke1.filter = EVFILT_READ; res = kevent(kq,&ke1,1,NULL,0,tsp); while(1) { new_client: //wait for a client to connect res = kevent(kq,NULL,0,&ke1,1,NULL); if(res < 0) printf("%s\n", strerror(errno)); if(res > 0) { //accept the client int clientfd = accept(skinfo.sockfd,NULL,NULL); //install read events for client bzero(&ke1,sizeof(ke1)); ke1.ident = clientfd; ke1.flags = EV_ADD; ke1.filter = EVFILT_READ; res = kevent(kq,&ke1,1,NULL,0,tsp); if(res < 0) printf("%s\n",strerror(errno)); while(1) { //wait for readable content from the client bzero(&ke1,sizeof(ke1)); res = kevent(kq,NULL,0,&ke1,1,NULL); if(res < 0) printf("%s\n",strerror(errno)); if(res > 0) { //check for client disconnect if(ke1.flags & EV_EOF) { close(clientfd); goto new_client; } //now install write events for client bzero(&ke1,sizeof(ke1)); ke1.ident = clientfd; ke1.flags = EV_ADD; ke1.filter = EVFILT_WRITE; res = kevent(kq,&ke1,1,NULL,0,tsp); if(res < 0) printf("%s\n",strerror(errno)); //now wait for it to be writable - this will return //immediately because the socket is writable. res = kevent(kq,NULL,0,ke2,2,NULL); if(res < 0) printf("%s\n",strerror(errno)); if(res >= 0) { char buf[128]; printf("res: %i\n",res); //we have two events from kqueue because I installed //two (ident,filter) pairs. int i = 0; for(i; i<2; i++) { printf("ident: %i\n",ke2[i].ident); printf("filter[%i] %lu\n",i,ke2[i].filter); printf("data: %lu\n",ke2[i].data); //QUESTION: Why does EVFILT_READ && EVFILT_WRITE come //back in the same event when I installed two seperate //(ident,filter) pairs? if(ke2[i].filter & EVFILT_READ) printf("EVFILT_READ\n"); if(ke2[i].filter & EVFILT_WRITE) printf("EVFILT_WRITE\n"); if(ke2[i].filter & EVFILT_READ) { printf("readable!\n"); bufres = read(clientfd,buf,128); } if(ke2[i].filter & EVFILT_WRITE) { printf("writable\n"); //shut off write events to stop infinite loop //because the socket is writable bzero(&ke1,sizeof(ke1)); ke1.ident = clientfd; ke1.flags = EV_DELETE; ke1.filter = EVFILT_WRITE; res = kevent(kq,&ke1,1,NULL,0,tsp); write(clientfd,buf,bufres); } } } } } } } }
I could not figure it out. Why does every kqueue event contain EVFILT_READ and EVFILT_WRITE when I set individual events?
The real problem for me is that since these events always report EVFILT_READ, it has side effects of the code, always thinking that reading is available, but not really, so the call to read () will fail and have other consequences. Please note that this code does not show these consequences, this is just an example of the problem I wrote, so I understand this and continue my real code.
Any ideas?
PS Here is the output from printf:
res: 2 ident: 5 filter[0] 4294967295 data: 5 EVFILT_READ EVFILT_WRITE readable! writable ident: 5 filter[1] 4294967294 data: 146988 EVFILT_READ EVFILT_WRITE readable! writable