Friday, February 26, 2021

[OpenBSD -current] Change event timer in main loop with kqueue

Hello everyone!

I've been trying to use kqueue for the last couple of day but I keep
having an issue with EVFILT_TIMER filter. (I'm running Openbsd
-current)

Right now, I'm trying to do the following:
1) Initilialize a timer event @ 200ms, periodically.
2) Inside the main event loop => If this event is retrieved, print
elapsed time since last one
3) After 2 iterations, MODIFY the timer event to 1000ms and continue the loop
4) Code stops after 4 iterations as pb arise after the first timer
change @ iteration 2.

Reading the manpages kqueue(2), one sees that:
** ) An event is uniquely defined by the pair (ident, filter) ==>
in the example below (TIMER1, EVFILT_TIMER)
**) "" Re-adding an existing event will modify the parameters of
the original event, and not result in a duplicate entry. "" => So
re-adding the event (TIMER1, EVFILT_TIMER) with a modified field
'data' should update the timer from 200ms to 1000ms.

=> Apparently, timer is updated, but not in the way I expected. See
below an example.

Here is the C program. I removed every 'error-checker' intentionally
as this is just a basic test:

#include <stdio.h>
#include <stdlib.h>
#include <sys/event.h>
#include <sys/time.h>
#define TIMER1 202

int main(){
int kq=0, nev=0;
struct kevent evlist, chlist;
struct timespec start, stop, elapsed;

/* Initialize the queue */
kq = kqueue();
/* Register event to the queue */
EV_SET(&chlist, TIMER1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 200, 0);
kevent(kq, &chlist, 1, NULL, 0, NULL);

for (int i=0; i<4; i++){
clock_gettitme(CLOCK_MONOTONIC, &start);
nev = kevent(kq, NULL, 0, &evlist, 1, NULL);
printf("Iteration %d => nb events=%d\n", i+1, nev);
if (evlist.ident == TIMER1){
clock_gettime(CLOCK_MONOTONIC, &stop);
timespecsub(&stop, &start, &elapsed);
printf("Time elapsed since previous iteration: %lld.%09lds\n",
(long long) elapsed.tv_sec, (long long)
elapsed.tv_nsec);

/* ====> MODIFY TIMER <====== */
if( (i+1)%2 == 0){
printf("Adjusting timer event ...\n");
EV_SET(&chlist, TIMER1, EVFILT_TIMER, EV_ADD |
EV_ENABLE, 0, 1000, 0);
/* I also tried this: chlist.data = 1000; but same
problem arise*/
/* Register modification within the queue */
kevent(kq, &chlist, 1, NULL, 0, NULL);
printf("Next event should happen %dms later", chlist.data);
} /* End i%4 == 0

} /* End evlist.ident == TIMER1 */

} /* End for loop */

return EXIT_SUCCESS;
}

*** Compiled with gcc-8.4.0
# egcc -o test_kqueue test_kqueue.c

*** OUTPUT of above program
Iteration 1 => nb events=1
Time elapsed since previous event:0.203417468s
==================================

Iteration 2 => nb events=1
Time elapsed since previous event:0.199534100s
Adjusting timer event ....
Next event in 1000ms << ===
This is where TIMER is changed

<< === and kqueue is updated
==================================

Iteration 3 => nb events=1
Time elapsed since previous event:0.199848328 << === Problem here:

<< It should be ~1s not 0.2s (initial timer)
==================================

Iteration 4 => nb events=1
Time elapsed since previous event:0.999884957s << === Now it's OK
Adjusting timer event ....
Next event in 1000ms
==================================
*** END OF OUTPUT

So what I expected from my program was that Iteration 3 would be
retrieved 1second after iteration 2. But here, it is retrieved 0.2s
after only. This is AS IF the change wasn't taken into account yet
...? The expected behaviour is seen at iteration 4.

I'm pretty sure I'm not understanding correctly what happens but I
cannot figure out where I'm wrong in my example.

I did another test modifying the event timer (line 31 in program) in loop with:
TEST 1::::: (Added EV_ONESHOT)
EV_SET(&chlist, TIMER1, EVFILT_TIMER, EV_ADD | EV_ENABLE |
EV_ONESHOT, 0, 1000, 0); ===>> ONESHOT does not seem to be taken
into account as the event keeps beeing retrieved 1s apart. (the
expected behavior would that that only one event should be triggered
after this modification)

TEST 2:::: (Disabling event to see if it happens instantly or if it is
"delayed" as in the previous examples)
The ONLY change that work as expected is EV_DISABLE, which stops
events from being retrieved after iteration 2.

Could any one help me figure out what I'm doing wrong and how I can
manage modifying an existing timer event?

Thanks a lot!

PS: This is not a copy/paste program as I'm not sending the message
from the same PC. I hope I didn't do any typos rewritting
everything...

No comments:

Post a Comment