kevent has bug?

From: Kohji Okuno <okuno.kohji_at_jp.panasonic.com>
Date: Wed, 02 Apr 2014 11:45:16 +0900 (JST)
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);
}
Received on Wed Apr 02 2014 - 00:45:40 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:48 UTC