kevent has bug?
Kohji Okuno
okuno.kohji at jp.panasonic.com
Wed Apr 2 02:45:40 UTC 2014
Hi,
I think, kevent() has a bug.
I tested sample programs by attached sources.
This sample tests about EVFILT_SIGNAL.
I build sample programs by the following commands.
% gcc -O2 -o child child.c
% gcc -O2 -o parent parent.c
The expected result is the following.
% ./parent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
OK
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
OK
But, sometimes the result was the following.
% ./parent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
This result means the number of times the signal has occured was
incorrect.
In case of EVFILT_SIGNAL, according to `man kevent', `data' retuns the
number of times the signal has occurred since the last call to
kevent(). This `data' is recorded by filt_signal() (This is f_event in
struct filterops).
The system call kevent()'s events are processed by kqueue_scan() in
kern_event.c. In kqueue_scan(), kn->kn_fop->f_event() is allways
called after KN_INFLUX is set to kn->kn_status.
On the other hand, kernel events are occured by knote() in
kern_event.c. (In EVFILT_SIGNAL, knote() is called from tdsendsignal()
in kern_sig.c.) In knote(), kn->kn_fop->f_event() is called only when
KN_INFLUX is not set in kn->kn_status.
In race condition between kqueue_scan() and knote(),
kn->kn_fop->f_event() from knote() may not be called, I think.
In knote(), because the context holds knlist's lock, the context can
not sleep. So, KN_INFLUX should not be set on calling
kn->kn_fop->f_event() in kqueue_scan(), I think.
What do you think about this issue?
Best regards,
Kohji Okuno
-------------- next part --------------
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main()
{
sleep(1);
exit(0);
}
-------------- next part --------------
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/event.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#define NUM_CHILDREN 20
int
main()
{
int i;
pid_t pid;
char *argv[2] = {"child", NULL};
struct kevent kev;
int kqfd = kqueue();
int count;
int err;
int status;
EV_SET(&kev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
kevent(kqfd, &kev, 1, NULL, 0, NULL);
while (1) {
count = 0;
for (i = 0; i < NUM_CHILDREN; i++) {
pid = fork();
if (pid == 0) {
execve("./child", argv, NULL);
}
}
while (1) {
err = kevent(kqfd, NULL, 0, &kev, 1, NULL);
if (err > 0 && kev.ident == SIGCHLD) {
for (i = 0; i < kev.data; i++) {
pid = waitpid(-1, &status, WNOHANG);
if (pid > 0) {
count++;
printf("%d ", count);
fflush(stdout);
if (count == NUM_CHILDREN) {
printf("\nOK\n");
goto next;
}
}
}
}
}
next:
;
}
exit(0);
}
More information about the freebsd-current
mailing list