Reputation: 956
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