-1

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?

user18043747
  • 1
  • 1
  • 4
  • `EVFILT_READ | EVFILT_WRITE` is not valid, they need to be in two separate `struct kevent`. You do not need to set filters and collect pending events in the same `kevent` call. – Richard Smith Mar 13 '22 at 09:33
  • @RichardSmith How would i go about using two seperate kevent structs – user18043747 Mar 13 '22 at 14:24

1 Answers1

0

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.

user14063792468
  • 839
  • 12
  • 28