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
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int
main()
{
        sleep(1);
        exit(0);
}
#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);
}
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to