user14063792468
user14063792468

Reputation: 956

EV_CLEAR flag confusion. What state of an event does it change?

My manual on kqueue says:

EV_CLEAR After the event is retrieved by the user, its state is reset. This is useful for filters which report state transitions instead of the current state. Note that some filters may automatically set this flag internally.

I did a small program that sets a timer with EV_DISPATCH and after first wake-up, enables it.

#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <sys/event.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <yma/yreport.h>

void ykq_kev_pev(struct kevent *ev);

int main()
{
 int           status; 
 struct kevent kev;
 int           kq;

 if((kq = kqueue()) < 0){
  fprintf(stderr, " * kqueue() failed\n errno = %d\n", errno);
  return 1;
 }

 kev.ident  = 1;
 kev.filter = EVFILT_TIMER;
 kev.flags  = EV_ADD | EV_DISPATCH;
 kev.data   = 4;
 kev.fflags = NOTE_SECONDS;

l_reg_ev:
 status = kevent(kq, &kev, 1, NULL, 0, NULL);
 if(status < 0){
  fprintf(stderr, " * kevent() failed\n errno = %d\n", errno);
  return 1;
 }

 for(;;){
  
  status = kevent(kq, NULL, 0, &kev, 1, NULL);
  if(status < 0){
   fprintf(stderr, " * kevent() failed\n errno = %d\n", errno);
   return 1;
  }else if(status > 0){
   if(kev.flags & EV_ERROR){
    ykq_kev_pev(&kev);
    return 1;
   }
   ykq_kev_pev(&kev);
   kev.flags = EV_ENABLE;
   goto l_reg_ev;
  }
 }

 return 0;
}

void ykq_kev_pev(struct kevent *ev)
{
 u_short flags  = ev->flags;
 u_int   fflags = ev->fflags;
 short   filter = ev->filter;
 int64_t data   = ev->data;

 static const char *p_null = "NULL";
 static char const *vf[] = {
 "EV_ADD ",
 "EV_ENABLE ",
 "EV_DISABLE ",
 "EV_DISPATCH ",
 "EV_DELETE ",
 "EV_RECEIPT ",
 "EV_ONESHOT ",
 "EV_CLEAR ",
 "EV_EOF ",
 "EV_ERROR ",
 };
 static char const *vflt[] = {
  "EVFILT_READ",
  "EVFILT_WRITE",
  "EVFILT_EMPTY",
  "EVFILT_AIO",
  "EVFILT_VNODE",
  "EVFILT_PROC",
  "EVFILT_PROCDESC",
  "EVFILT_SIGNAL",
  "EVFILT_TIMER",
  "EVFILT_USER",
 };
 static char const *vsock_s[] = {
 "listen backlog :",
 "bytes avaible read :",
 "bytes avaible write :",
 "# times since last kevent call:",
 "# times timeout has expired since last kevent call:",
 };
 char        s_flags [255] = {0};
 const char *p_filter      = p_null;
 const char *p_data_desc   = p_null;

 /* enable, or disable */
 if(flags & EV_ENABLE){
  strcat(s_flags,vf[1]);
 }else if(flags & EV_DISABLE){
  strcat(s_flags,vf[2]);
 }

 /* possible combination of flags */
 if(flags & EV_ADD)
  strcat(s_flags,vf[0]);
 if(flags & EV_DISPATCH)
  strcat(s_flags,vf[3]);
 if(flags & EV_DELETE)
  strcat(s_flags,vf[4]);
 if(flags & EV_RECEIPT)
  strcat(s_flags,vf[5]);
 if(flags & EV_ONESHOT)
  strcat(s_flags,vf[6]);
 if(flags & EV_CLEAR)
  strcat(s_flags,vf[7]);
 if(flags & EV_EOF)
  strcat(s_flags,vf[8]);
 if(flags & EV_ERROR)
  strcat(s_flags,vf[9]);

 /* filter and fflags */
 switch(filter){
 case EVFILT_READ :    p_filter = vflt[0]; break;
 case EVFILT_WRITE:    p_filter = vflt[1]; break;
 case EVFILT_EMPTY:    p_filter = vflt[2]; break;
 case EVFILT_AIO:      p_filter = vflt[3]; break;
 case EVFILT_VNODE:    p_filter = vflt[4]; break;
 case EVFILT_PROC:     p_filter = vflt[5]; break;
 case EVFILT_PROCDESC: p_filter = vflt[6]; break;
 case EVFILT_SIGNAL:   p_filter = vflt[7]; break;
 case EVFILT_TIMER:    p_filter = vflt[8]; break;
 case EVFILT_USER:     p_filter = vflt[9]; break;
 default: break;
 }
 

 if('\0' == *s_flags){
  strcpy(s_flags, p_null);
 }

 /* signals */
 switch(filter){
 case EVFILT_SIGNAL :
  p_data_desc = vsock_s[3];
  break;
 case EVFILT_TIMER : 
  p_data_desc = vsock_s[4];
 default: break;
 }

 printf(" \t\t@ event:\n"
        "\tid      :  %lu\n",
        ev->ident        
 );
 if(*s_flags){
  printf("\tflags   :  %s\n",
         s_flags
  );
 }
 printf("\tfilter  :  %s\n"
        "\tdata    :  %s %ld\n",
        p_filter,
        p_data_desc, data
 );
 if(flags & EV_EOF){
  printf("\terror   :  %s\n",
         errnonm(fflags)
  );
 }else if((flags & EV_ERROR) && (0 != data)){
  printf("\terror   :  %s\n",
         errnonm(data)
  );
 }

}

The code originates from my efforts to understand socket programming. At some point I got confused with the state of the event flags. The above prints a series of:

@ event:
id : 1
flags : EV_DISPATCH EV_CLEAR
filter : EVFILT_TIMER
data : # times timeout has expired since last kevent call: 1

What is expected, is that, after first goto, the EV_DISPATCH flag will get cleared. As per manual. What exactly are those "state", that the manual talks about. More specifically, what does EV_CLEAR do to event, and when?

I can not understand the source code for the all procedure at its full. That is why the only thing I can do, is to wait for clarification.

P.S The OS is FreeBSD 13.1.

Upvotes: 0

Views: 198

Answers (0)

Related Questions