using EVFILT_READ at the same time as EVFILT_WRITE

500 views Asked by At

i am writing a TCP client with kqueue. The events i would like to subscribe to are EVFILT_READ and EVFILT_WRITE. From freebsd, '''Combinations may be made by OR'ing the desired values. For instance, EV_ADD | EV_ENABLE | EV_ONESHOT would translate to "Add the event, enable it and return only the first occurrence of the filter being triggered. After the user retrieves the event from the kqueue, delete it."''' (http://wiki.netbsd.org/tutorials/kqueue_tutorial/). This to me, makes EVFILT_READ| EVFILT_WRITE valid kqueue code. This doesn't seem to be the case as kevent hangs indefinitely when i use both at the same time. However, using one in a seperate thread (EVFILT_READ in one thread and EVFILT_WRITE) in another works fine. This defeats the purpose of using kqueue though... Most examples (limited) are server examples which means it is ideal to only subscribe to EVFILT_READ then when a socket is accepted then needs to be written to itll call EVFILT_WRITE. This is not ideal for me since i would be doing both with no real wait time. The kqueue code, while not able to be compiled, looks like this


        struct kevent ev[socketAmount];

        struct kevent actionlist[socketAmount];

        for (uint16_t x = 0; x < socketAmount; ++x) {

            EV_SET(&ev[x], socketRelationArr[x].sock, EVFILT_READ | EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
kq = kqueue();

there will be x sockets that will be sending/recieving then i add them all to the kqueue by calling EV_SET with the events mentioned above (EV_ADD implies EV_ENABLE but for clarity i have it added)

            int numberEV = kevent(kq, ev, socketAmount, actionlist, socketAmount, NULL);

Again, this makes kevent hang indefintely, so my question is: Is it possible to add EVFILT_READ and EVFILT_WRITE at the same time to the same socket and make it not hang? Is it normal behavior to hang?

1

There are 1 answers

0
user14063792468 On

Read a man of kevent. If nevents is zero, the function will return immediately. If you wish only to register some sockets for read/write, then do a below:

int soc[] = {4,5,6,7}; /* actual sockets shall here */
int nsoc  = 4; /* # of sockets */
int nev   = nsoc * 2; /* (read + write) x (# of sockets) */
struct kevent chlist[nev]; 

/* register events */
/*                 */

/* fill in structs */
for(i = 0; i < nev; i += 2){
 EV_SET(&chlist[i]  , soc[i/2], EVFILT_READ , EV_ADD, 0, 0, 0);
 EV_SET(&chlist[i+1], soc[i/2], EVFILT_WRITE, EV_ADD, 0, 0, 0);
}

/* add records */
n = kevent(kq, chlist, nev, NULL, 0, NULL);
if(n < 0){ /* error */
 exit(-1);
}

Note last arguments. The function will not wait for events and will return. To do actual wait:

n = kevent(kq, NULL, NULL, evlist, size_of_ev_list, timeout);

You can both register and wait for events. Guess how ;) The man kevent tells us that you can pass same array for chlist and evlist. But you are not obligated to do so.

then needs to be written to itll call EVFILT_WRITE

EVFILT_WRITE - is an indication that socket buffer has free storage to write to. When socket "needs to be writen to", you just write to it. In the case of incomplete write, you will wait for EVFILT_WRITE filter flag. Note, that if you register event for a socket with EVFILT_WRITE filter, the event will be avaible as soon as some data could be written to it.