#include <pthread.h>
#include <stdio.h>
#include <err.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/event.h>
#include <sys/stat.h>
#include <sys/socket.h>

static int kq;
static int debug = 0;

static void
add(int fd)
{
	struct timespec tout = { 0, 500000 };
	int i = 0;

	struct kevent ev, rev;
	EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
           NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|
           NOTE_RENAME|NOTE_REVOKE, 0, 0);
	while (kevent(kq, &ev, 1, &rev, 1, &tout) != -1) {
		if (i++ == 10)
			return;
	}

	if (debug) warn("kevent");
}

static void
del(int fd)
{
	struct kevent ev;
	EV_SET(&ev, fd, EVFILT_VNODE, EV_DELETE, 0, 0, 0);
	if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1)
		if (debug) warn("kevent");
}

static int
mkfd(int fd)
{
	struct stat st;

	if (fstat(fd, &st) == -1) {
		if ((fd = open("xxx1", O_RDWR|O_CREAT, 0600)) == -1)
			if (debug) warn("open");
		return fd;
	}
	write(fd, &st, 1);
	return fd;
}

static void *
worker(void *p)
{
	for (;;) {
		long r = random();
		int fd = (r % 100) + 3;
//		printf("fd %d r %d\n", fd, r);
		switch (r & 3) {
		case 0:
			add(mkfd(fd));
			break;
		case 1:
			del(mkfd(fd));
			break;
		case 2:
			close(fd);
			break;
		case 3:
			mkfd(fd);
			break;
		default:
			abort();
		}
	}
}


int
main(void)
{
	pthread_t pt[20];
	int e;

	if ((kq = kqueue()) == -1)
		err(EXIT_FAILURE, "kqueue");

	for (size_t i = 0; i < __arraycount(pt); i++)
		if ((e = pthread_create(&pt[i], NULL, worker, &i)) != 0)
			errc(EXIT_FAILURE, e, "pthread_create");
	sleep(10000);
}