Eliminate the use of global state variables in kqtest to allow the tests

to be run in parallel.

Add two kqtest options: one for iterations, and one for concurrency.

Use -rpath when building kqtest instead of using LD_LIBRARY_PATH



git-svn-id: svn://svn.code.sf.net/p/libkqueue/code/trunk@519 fb4e3144-bc1c-4b72-a658-5bcd248dd7f7
This commit is contained in:
mheily 2011-05-25 02:10:36 +00:00
parent 68e94a12eb
commit cd858d02fd
12 changed files with 569 additions and 468 deletions

View File

@ -41,7 +41,7 @@ $(PROGRAM).so.$(ABI_VERSION): $(OBJS)
$(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(PROGRAM).so
$(PROGRAM)_debug.so:
$(CC) -o $@ -I./include -I./src/common -shared $(CFLAGS) -O0 $(SOURCES) $(LDADD)
$(CC) -o $@ -I./include -I./src/common -shared -rdynamic $(CFLAGS) -g3 -O0 $(SOURCES) $(LDADD)
install: all
$(INSTALL) -d -m 755 $(INCLUDEDIR)/kqueue/sys

View File

@ -24,16 +24,16 @@ lockstat: lockstat.c
$(CC) -o lockstat $(CFLAGS) lockstat.c $(LDADD)
kqtest: $(SOURCES)
$(CC) -o kqtest $(CFLAGS) $(SOURCES) $(LDADD)
$(CC) -rdynamic -o kqtest $(CFLAGS) $(SOURCES) $(LDADD)
static-lib-test: $(SOURCES)
$(CC) -o static-lib-test -DMAKE_STATIC=1 $(CFLAGS) $(SOURCES) ../libkqueue.a -lpthread
check: kqtest
LD_LIBRARY_PATH="..:/usr/sfw/lib/64" PATH="$$PATH:.." ./kqtest
LD_LIBRARY_PATH="..:/usr/sfw/lib/64" PATH="$$PATH:.." ./kqtest $(KQTEST_OPTS)
debug: kqtest
LD_LIBRARY_PATH="..:/usr/sfw/lib/64" PATH="$$PATH:.." gdb ./kqtest
LD_LIBRARY_PATH="..:/usr/sfw/lib/64" PATH="$$PATH:.." gdb ./kqtest $(KQTEST_OPTS)
valgrind: kqtest
LD_LIBRARY_PATH="..:/usr/sfw/lib/64" \

View File

@ -46,6 +46,7 @@
#include <unistd.h>
#include <sys/event.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <poll.h>
#include "config.h"
#else
@ -54,27 +55,48 @@
# define HAVE_EVFILT_USER 1
#endif
struct test_context;
void test_evfilt_read(int);
void test_evfilt_signal(int);
void test_evfilt_vnode(int);
void test_evfilt_timer(int);
void test_evfilt_proc(int);
struct unit_test {
const char *ut_name;
int ut_enabled;
void (*ut_func)(struct test_context *);
};
struct test_context {
struct unit_test tests[50]; //TODO: use MAX_TESTS instead of magic number
int iterations;
int concurrency;
int iteration;
int kqfd;
/* EVFILT_READ and EVFILT_WRITE */
int client_fd;
int server_fd;
/* EVFILT_VNODE */
int vnode_fd;
char testfile[1024];
};
void test_evfilt_read(struct test_context *);
void test_evfilt_signal(struct test_context *);
void test_evfilt_vnode(struct test_context *);
void test_evfilt_timer(struct test_context *);
void test_evfilt_proc(struct test_context *);
#if HAVE_EVFILT_USER
void test_evfilt_user(int);
void test_evfilt_user(struct test_context *);
#endif
#define test(f,...) do { \
#define test(f,ctx,...) do { \
test_begin("test_"#f"()\t"__VA_ARGS__); \
test_##f();\
test_##f(ctx);\
test_end(); \
} while (/*CONSTCOND*/0)
extern const char * kevent_to_str(struct kevent *);
struct kevent * kevent_get(int);
struct kevent * kevent_get_hires(int);
void kevent_get(struct kevent *, int);
void kevent_get_hires(struct kevent *, int);
void kevent_update(int kqfd, struct kevent *kev);
#define kevent_cmp(a,b) _kevent_cmp(a,b, __FILE__, __LINE__)

View File

@ -2,7 +2,7 @@
program=libkqueue-test
version=0.1
cflags="-g -O0 -Wall -Werror"
cflags="-g -O0 -Wall -Werror -Wl,-rpath,.."
sources="main.c kevent.c test.c proc.c read.c signal.c timer.c vnode.c"
pre_configure_hook() {

View File

@ -37,37 +37,35 @@ _test_no_kevents(int kqfd, const char *file, int line)
}
/* Retrieve a single kevent */
struct kevent *
kevent_get(int kqfd)
void
kevent_get(struct kevent *kev, int kqfd)
{
struct kevent buf;
int nfds;
static struct kevent __thread kev;
nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
if (kev == NULL)
kev = &buf;
nfds = kevent(kqfd, NULL, 0, kev, 1, NULL);
if (nfds < 1)
err(1, "kevent(2)");
return (&kev);
}
/* In Linux, a kevent() call with less than 1ms resolution
will perform a pselect() call to obtain the higer resolution.
This test exercises that codepath.
*/
struct kevent *
kevent_get_hires(int kqfd)
void
kevent_get_hires(struct kevent *kev, int kqfd)
{
int nfds;
struct timespec timeo;
static struct kevent __thread kev;
timeo.tv_sec = 0;
timeo.tv_nsec = 500000;
nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
nfds = kevent(kqfd, NULL, 0, kev, 1, &timeo);
if (nfds < 1)
die("kevent(2)");
return (&kev);
}
char *

View File

@ -16,12 +16,8 @@
#include "common.h"
struct unit_test {
const char *ut_name;
int ut_enabled;
void (*ut_func)(int);
};
/* Maximum number of threads that can be created */
#define MAX_THREADS 100
void
test_kqueue_descriptor_is_pollable(void)
@ -59,7 +55,7 @@ test_kqueue_descriptor_is_pollable(void)
* has been closed. This technique is used in kqueue_validate()
*/
static void
test_peer_close_detection(void)
test_peer_close_detection(void *unused)
{
#ifdef _WIN32
return;
@ -90,7 +86,7 @@ test_peer_close_detection(void)
}
void
test_kqueue(void)
test_kqueue(void *unused)
{
int kqfd;
@ -102,7 +98,7 @@ test_kqueue(void)
}
void
test_ev_receipt(void)
test_ev_receipt(void *unused)
{
int kq;
struct kevent kev;
@ -124,14 +120,91 @@ test_ev_receipt(void)
#endif
}
void
run_iteration(struct test_context *ctx)
{
struct unit_test *test;
for (test = &ctx->tests[0]; test->ut_name != NULL; test++) {
if (test->ut_enabled)
test->ut_func(ctx);
}
free(ctx);
}
void
test_harness(struct unit_test tests[], int iterations, int concurrency)
{
int i, j, n, kqfd;
pthread_t tid[MAX_THREADS];
struct test_context *ctx;
int rv;
if (concurrency >= MAX_THREADS)
errx(1, "Too many threads");
printf("Running %d iterations using %d worker threads\n",
iterations, concurrency);
testing_begin();
test(peer_close_detection, NULL);
test(kqueue, NULL);
if ((kqfd = kqueue()) < 0)
die("kqueue()");
test(ev_receipt, NULL);
/* TODO: this fails now, but would be good later
test(kqueue_descriptor_is_pollable);
*/
n = 0;
for (i = 0; i < iterations; i++) {
for (j = 0; j < concurrency; j++) {
/* Create a unique context object for each thread */
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL)
abort();
ctx->iteration = n++;
ctx->kqfd = kqfd;
memcpy(&ctx->tests, tests, sizeof(ctx->tests)); //FIXME: invalid read
ctx->iterations = iterations;
ctx->concurrency = concurrency;
rv = pthread_create(&tid[j], NULL, (void * (*)(void *)) run_iteration, ctx);
if (rv != 0)
err(1, "pthread_create");
}
for (j = 0; j < concurrency; j++) {
pthread_join(tid[j], NULL);
}
}
testing_end();
close(kqfd);
}
void
usage(void)
{
printf("usage:\n"
" -h This message\n"
" -n Number of iterations (default: 1)\n"
" -c Number of threads running concurrently (default: 1)\n"
"\n\n"
);
exit(1);
}
int
main(int argc, char **argv)
{
struct unit_test tests[] = {
{ "socket", 1, test_evfilt_read },
#ifndef _WIN32
{ "signal", 1, test_evfilt_signal },
{ "signal", 0, test_evfilt_signal },
#endif
#if FIXME
{ "proc", 1, test_evfilt_proc },
@ -146,8 +219,9 @@ main(int argc, char **argv)
{ NULL, 0, NULL },
};
struct unit_test *test;
int c, i, concurrency, iterations;
char *arg;
int match, kqfd;
int match;
#ifdef MAKE_STATIC
libkqueue_init();
@ -160,16 +234,33 @@ main(int argc, char **argv)
err(1, "WSAStartup failed");
#endif
iterations = 1;
concurrency = 1;
while ((c = getopt (argc, argv, "hc:n:")) != -1) {
switch (c) {
case 'c':
concurrency = atoi(optarg);
break;
case 'h':
usage();
break;
case 'n':
iterations = atoi(optarg);
break;
default:
usage();
}
}
/* If specific tests are requested, disable all tests by default */
if (argc > 1) {
if (optind < argc) {
for (test = &tests[0]; test->ut_name != NULL; test++) {
test->ut_enabled = 0;
}
}
while (argc > 1) {
for (i = optind; i < argc; i++) {
match = 0;
arg = argv[1];
arg = argv[i];
for (test = &tests[0]; test->ut_name != NULL; test++) {
if (strcmp(arg, test->ut_name) == 0) {
test->ut_enabled = 1;
@ -183,30 +274,9 @@ main(int argc, char **argv)
} else {
printf("enabled test: %s\n", arg);
}
argv++;
argc--;
}
testing_begin();
test(peer_close_detection);
test(kqueue);
if ((kqfd = kqueue()) < 0)
die("kqueue()");
for (test = &tests[0]; test->ut_name != NULL; test++) {
if (test->ut_enabled)
test->ut_func(kqfd);
}
test(ev_receipt);
/* TODO: this fails now, but would be good later
test(kqueue_descriptor_is_pollable);
*/
testing_end();
test_harness(tests, iterations, concurrency);
return (0);
}

View File

@ -27,7 +27,7 @@ sig_handler(int signum)
}
static void
test_kevent_proc_add(void)
test_kevent_proc_add(struct test_context *ctx)
{
struct kevent kev;
@ -37,7 +37,7 @@ test_kevent_proc_add(void)
}
static void
test_kevent_proc_delete(void)
test_kevent_proc_delete(struct test_context *ctx)
{
struct kevent kev;
@ -50,9 +50,9 @@ test_kevent_proc_delete(void)
}
static void
test_kevent_proc_get(void)
test_kevent_proc_get(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, buf;
/* Create a child that waits to be killed and then exits */
pid = fork();
@ -70,13 +70,14 @@ test_kevent_proc_get(void)
printf(" -- killing process %d\n", (int) pid);
if (kill(pid, SIGUSR1) < 0)
die("kill");
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&buf, kqfd);
kevent_cmp(&kev, &buf);
test_no_kevents(kqfd);
}
#ifdef TODO
void
test_kevent_signal_disable(void)
test_kevent_signal_disable(struct test_context *ctx)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)";
struct kevent kev;
@ -102,7 +103,7 @@ test_kevent_signal_disable(void)
}
void
test_kevent_signal_enable(void)
test_kevent_signal_enable(struct test_context *ctx)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)";
struct kevent kev;
@ -139,7 +140,7 @@ test_kevent_signal_enable(void)
}
void
test_kevent_signal_del(void)
test_kevent_signal_del(struct test_context *ctx)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)";
struct kevent kev;
@ -165,7 +166,7 @@ test_kevent_signal_del(void)
}
void
test_kevent_signal_oneshot(void)
test_kevent_signal_oneshot(struct test_context *ctx)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)";
struct kevent kev;
@ -199,10 +200,8 @@ test_kevent_signal_oneshot(void)
#endif
void
test_evfilt_proc(int _kqfd)
test_evfilt_proc(struct test_context *ctx)
{
kqfd = _kqfd;
signal(SIGUSR1, sig_handler);
/* Create a child that waits to be killed and then exits */
@ -213,9 +212,9 @@ test_evfilt_proc(int _kqfd)
}
printf(" -- child created (pid %d)\n", (int) pid);
test(kevent_proc_add);
test(kevent_proc_delete);
test(kevent_proc_get);
test(kevent_proc_add, ctx);
test(kevent_proc_delete, ctx);
test(kevent_proc_get, ctx);
signal(SIGUSR1, SIG_DFL);

View File

@ -17,9 +17,6 @@
#include "common.h"
static int __thread kqfd;
static int __thread client_fd;
static int __thread server_fd;
/*
* Create a connected TCP socket.
@ -41,8 +38,10 @@ create_socket_connection(int *client, int *server, const short port)
if (setsockopt(srvr, SOL_SOCKET, SO_REUSEADDR,
(char *) &one, sizeof(one)) != 0)
err(1, "setsockopt");
if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0)
err(1, "bind");
if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0) {
printf("unable to bind to port %d\n", port);
err(1, "bind-1");
}
if (listen(srvr, 100) < 0)
err(1, "listen");
@ -62,87 +61,88 @@ create_socket_connection(int *client, int *server, const short port)
}
static void
kevent_socket_drain(void)
kevent_socket_drain(struct test_context *ctx)
{
char buf[1];
/* Drain the read buffer, then make sure there are no more events. */
if (recv(client_fd, &buf[0], 1, 0) < 1)
if (recv(ctx->client_fd, &buf[0], 1, 0) < 1)
die("recv(2)");
}
static void
kevent_socket_fill(void)
kevent_socket_fill(struct test_context *ctx)
{
if (send(server_fd, ".", 1, 0) < 1)
if (send(ctx->server_fd, ".", 1, 0) < 1)
die("send(2)");
}
void
test_kevent_socket_add(void)
test_kevent_socket_add(struct test_context *ctx)
{
struct kevent kev;
kevent_add(kqfd, &kev, client_fd, EVFILT_READ, EV_ADD, 0, 0, &client_fd);
kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
}
void
test_kevent_socket_add_without_ev_add(void)
test_kevent_socket_add_without_ev_add(struct test_context *ctx)
{
struct kevent kev;
/* Try to add a kevent without specifying EV_ADD */
EV_SET(&kev, client_fd, EVFILT_READ, 0, 0, 0, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
EV_SET(&kev, ctx->client_fd, EVFILT_READ, 0, 0, 0, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0)
die("kevent should have failed");
kevent_socket_fill();
test_no_kevents(kqfd);
kevent_socket_drain();
kevent_socket_fill(ctx);
test_no_kevents(ctx->kqfd);
kevent_socket_drain(ctx);
/* Try to delete a kevent which does not exist */
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0)
die("kevent should have failed");
}
void
test_kevent_socket_get(void)
test_kevent_socket_get(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
EV_SET(&kev, client_fd, EVFILT_READ, EV_ADD, 0, 0, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent:1");
kevent_socket_fill();
kevent_socket_fill(ctx);
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
kevent_socket_drain();
test_no_kevents(kqfd);
kevent_socket_drain(ctx);
test_no_kevents(ctx->kqfd);
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent:2");
}
void
test_kevent_socket_clear(void)
test_kevent_socket_clear(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
kevent_socket_drain();
test_no_kevents(ctx->kqfd);
kevent_socket_drain(ctx);
EV_SET(&kev, client_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent1");
kevent_socket_fill();
kevent_socket_fill();
kevent_socket_fill(ctx);
kevent_socket_fill(ctx);
/* Solaris does not offer a way to get the amount of data pending */
#if defined(__sun__)
@ -150,88 +150,91 @@ test_kevent_socket_clear(void)
#else
kev.data = 2;
#endif
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* We filled twice, but drain once. Edge-triggered would not generate
additional events.
*/
kevent_socket_drain();
test_no_kevents(kqfd);
kevent_socket_drain(ctx);
test_no_kevents(ctx->kqfd);
kevent_socket_drain();
EV_SET(&kev, client_fd, EVFILT_READ, EV_DELETE, 0, 0, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
kevent_socket_drain(ctx);
EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent2");
}
void
test_kevent_socket_disable_and_enable(void)
test_kevent_socket_disable_and_enable(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
/* Add an event, then disable it. */
EV_SET(&kev, client_fd, EVFILT_READ, EV_ADD, 0, 0, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
EV_SET(&kev, client_fd, EVFILT_READ, EV_DISABLE, 0, 0, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DISABLE, 0, 0, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
kevent_socket_fill();
test_no_kevents(kqfd);
kevent_socket_fill(ctx);
test_no_kevents(ctx->kqfd);
/* Re-enable the knote, then see if an event is generated */
kev.flags = EV_ENABLE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
kev.flags = EV_ADD;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
kevent_socket_drain();
kevent_socket_drain(ctx);
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
}
void
test_kevent_socket_del(void)
test_kevent_socket_del(struct test_context *ctx)
{
struct kevent kev;
EV_SET(&kev, client_fd, EVFILT_READ, EV_DELETE, 0, 0, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
kevent_socket_fill();
test_no_kevents(kqfd);
kevent_socket_drain();
kevent_socket_fill(ctx);
test_no_kevents(ctx->kqfd);
kevent_socket_drain(ctx);
}
void
test_kevent_socket_oneshot(void)
test_kevent_socket_oneshot(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
/* Re-add the watch and make sure no events are pending */
kevent_add(kqfd, &kev, client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &client_fd);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &ctx->client_fd);
test_no_kevents(ctx->kqfd);
kevent_socket_fill();
kevent_socket_fill(ctx);
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Verify that the kernel watch has been deleted */
kevent_socket_fill();
test_no_kevents(kqfd);
kevent_socket_drain();
kevent_socket_fill(ctx);
test_no_kevents(ctx->kqfd);
kevent_socket_drain(ctx);
/* Verify that the kevent structure does not exist. */
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0)
die("kevent() should have failed");
}
@ -240,15 +243,17 @@ test_kevent_socket_oneshot(void)
* a pending connection.
*/
void
test_kevent_socket_listen_backlog(void)
test_kevent_socket_listen_backlog(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
struct sockaddr_in sain;
socklen_t sa_len = sizeof(sain);
int one = 1;
const short port = 14973;
short port;
int clnt, srvr;
port = 14973 + ctx->iteration;
/* Create a passive socket */
memset(&sain, 0, sizeof(sain));
sain.sin_family = AF_INET;
@ -259,14 +264,14 @@ test_kevent_socket_listen_backlog(void)
(char *) &one, sizeof(one)) != 0)
err(1, "setsockopt()");
if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0)
err(1, "bind()");
err(1, "bind-2", port);
if (listen(srvr, 100) < 0)
err(1, "listen()");
/* Watch for events on the socket */
test_no_kevents(kqfd);
kevent_add(kqfd, &kev, srvr, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(ctx->kqfd, &kev, srvr, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL);
test_no_kevents(ctx->kqfd);
/* Simulate a client connecting to the server */
sain.sin_family = AF_INET;
@ -279,45 +284,48 @@ test_kevent_socket_listen_backlog(void)
/* Verify that data=1 */
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
test_no_kevents(kqfd);
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(ctx->kqfd);
}
#if HAVE_EV_DISPATCH
void
test_kevent_socket_dispatch(void)
test_kevent_socket_dispatch(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
/* Re-add the watch and make sure no events are pending */
kevent_add(kqfd, &kev, client_fd, EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &client_fd);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &ctx->client_fd);
test_no_kevents(ctx->kqfd);
/* The event will occur only once, even though EV_CLEAR is not
specified. */
kevent_socket_fill();
kevent_socket_fill(ctx);
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
test_no_kevents(kqfd);
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(ctx->kqfd);
/* Re-enable the kevent */
/* FIXME- is EV_DISPATCH needed when rearming ? */
kevent_add(kqfd, &kev, client_fd, EVFILT_READ, EV_ENABLE | EV_DISPATCH, 0, 0, &client_fd);
kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ENABLE | EV_DISPATCH, 0, 0, &ctx->client_fd);
kev.data = 1;
kev.flags = EV_ADD | EV_DISPATCH; /* FIXME: may not be portable */
kevent_cmp(&kev, kevent_get(kqfd));
test_no_kevents(kqfd);
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(ctx->kqfd);
/* Since the knote is disabled, the EV_DELETE operation succeeds. */
kevent_add(kqfd, &kev, client_fd, EVFILT_READ, EV_DELETE, 0, 0, &client_fd);
kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
kevent_socket_drain();
kevent_socket_drain(ctx);
}
#endif /* HAVE_EV_DISPATCH */
#if BROKEN_ON_LINUX
void
test_kevent_socket_lowat(void)
test_kevent_socket_lowat(struct test_context *ctx)
{
struct kevent kev;
@ -325,54 +333,54 @@ test_kevent_socket_lowat(void)
/* Re-add the watch and make sure no events are pending */
puts("-- re-adding knote, setting low watermark to 2 bytes");
EV_SET(&kev, client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &client_fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &ctx->client_fd);
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("%s", test_id);
test_no_kevents();
puts("-- checking that one byte does not trigger an event..");
kevent_socket_fill();
kevent_socket_fill(ctx);
test_no_kevents();
puts("-- checking that two bytes triggers an event..");
kevent_socket_fill();
if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
kevent_socket_fill(ctx);
if (kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL) != 1)
die("%s", test_id);
KEV_CMP(kev, client_fd, EVFILT_READ, 0);
KEV_CMP(kev, ctx->client_fd, EVFILT_READ, 0);
test_no_kevents();
kevent_socket_drain();
kevent_socket_drain();
kevent_socket_drain(ctx);
kevent_socket_drain(ctx);
}
#endif
void
test_kevent_socket_eof(void)
test_kevent_socket_eof(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
/* Re-add the watch and make sure no events are pending */
kevent_add(kqfd, &kev, client_fd, EVFILT_READ, EV_ADD, 0, 0, &client_fd);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
test_no_kevents(ctx->kqfd);
//if (shutdown(server_fd, SHUT_RDWR) < 0)
//if (shutdown(ctx->server_fd, SHUT_RDWR) < 0)
// die("close(2)");
if (close(server_fd) < 0)
if (close(ctx->server_fd) < 0)
die("close(2)");
kev.flags |= EV_EOF;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Delete the watch */
kevent_add(kqfd, &kev, client_fd, EVFILT_READ, EV_DELETE, 0, 0, &client_fd);
kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
}
/* Test if EVFILT_READ works with regular files */
void
test_kevent_regular_file(void)
test_kevent_regular_file(struct test_context *ctx)
{
struct kevent kev;
struct kevent *kev2;
struct kevent kev, ret;
off_t curpos;
int fd;
@ -381,55 +389,54 @@ test_kevent_regular_file(void)
abort();
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, &fd);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
kev2 = kevent_get(kqfd);
kevent_get(&ret, ctx->kqfd);
/* Set file position to EOF-1 */
kev2->data--;
if ((curpos = lseek(fd, kev2->data, SEEK_SET)) != kev2->data) {
ret.data--;
if ((curpos = lseek(fd, ret.data, SEEK_SET)) != ret.data) {
printf("seek to %u failed with rv=%lu\n",
(unsigned int) kev2->data, curpos);
(unsigned int) ret.data, curpos);
abort();
}
/* Set file position to EOF */
(void) kevent_get(kqfd);
kev2->data = curpos + 1;
if ((curpos = lseek(fd, kev2->data, SEEK_SET)) != kev2->data) {
kevent_get(NULL, ctx->kqfd);
ret.data = curpos + 1;
if ((curpos = lseek(fd, ret.data, SEEK_SET)) != ret.data) {
printf("seek to %u failed with rv=%lu\n",
(unsigned int) kev2->data, curpos);
(unsigned int) ret.data, curpos);
abort();
}
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
close(fd);
}
void
test_evfilt_read(int _kqfd)
test_evfilt_read(struct test_context *ctx)
{
create_socket_connection(&client_fd, &server_fd, 23456);
create_socket_connection(&ctx->client_fd, &ctx->server_fd, ctx->iteration + 23456);
kqfd = _kqfd;
test(kevent_socket_add);
test(kevent_socket_del);
test(kevent_socket_add_without_ev_add);
test(kevent_socket_get);
test(kevent_socket_disable_and_enable);
test(kevent_socket_oneshot);
test(kevent_socket_clear);
test(kevent_socket_add, ctx);
test(kevent_socket_del, ctx);
test(kevent_socket_add_without_ev_add, ctx);
test(kevent_socket_get, ctx);
test(kevent_socket_disable_and_enable, ctx);
test(kevent_socket_oneshot, ctx);
test(kevent_socket_clear, ctx);
#if HAVE_EV_DISPATCH
test(kevent_socket_dispatch);
test(kevent_socket_dispatch, ctx);
#endif
test(kevent_socket_listen_backlog);
test(kevent_socket_eof);
test(kevent_regular_file);
close(client_fd);
close(server_fd);
test(kevent_socket_listen_backlog, ctx);
test(kevent_socket_eof, ctx);
test(kevent_regular_file, ctx);
close(ctx->client_fd);
close(ctx->server_fd);
}

View File

@ -16,50 +16,49 @@
#include "common.h"
static int __thread kqfd;
void
test_kevent_signal_add(void)
test_kevent_signal_add(struct test_context *ctx)
{
struct kevent kev;
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
}
void
test_kevent_signal_get(void)
test_kevent_signal_get(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
kev.flags |= EV_CLEAR;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
}
void
test_kevent_signal_disable(void)
test_kevent_signal_disable(struct test_context *ctx)
{
struct kevent kev;
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
void
test_kevent_signal_enable(void)
test_kevent_signal_enable(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
@ -70,122 +69,126 @@ test_kevent_signal_enable(void)
#else
kev.data = 2; // one extra time from test_kevent_signal_disable()
#endif
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Delete the watch */
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
die("kevent");
}
void
test_kevent_signal_del(void)
test_kevent_signal_del(struct test_context *ctx)
{
struct kevent kev;
/* Delete the kevent */
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
signal(SIGUSR1, SIG_IGN);
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
void
test_kevent_signal_oneshot(void)
test_kevent_signal_oneshot(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
kev.flags |= EV_CLEAR;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Send another one and make sure we get no events */
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
void
test_kevent_signal_modify(void)
test_kevent_signal_modify(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, ((void *)-1));
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, ((void *)-1));
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
kev.flags |= EV_CLEAR;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_kevent_signal_del();
test_kevent_signal_del(ctx);
}
#if HAVE_EV_DISPATCH
void
test_kevent_signal_dispatch(void)
test_kevent_signal_dispatch(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
/* Get one event */
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Confirm that the knote is disabled */
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Enable the knote and make sure no events are pending */
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
test_no_kevents(ctx->kqfd);
/* Get the next event */
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Remove the knote and ensure the event no longer fires */
kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
if (kill(getpid(), SIGUSR1) < 0)
die("kill");
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
#endif /* HAVE_EV_DISPATCH */
void
test_evfilt_signal(int _kqfd)
test_evfilt_signal(struct test_context *ctx)
{
signal(SIGUSR1, SIG_IGN);
kqfd = _kqfd;
test(kevent_signal_add);
test(kevent_signal_del);
test(kevent_signal_get);
test(kevent_signal_disable);
test(kevent_signal_enable);
test(kevent_signal_oneshot);
test(kevent_signal_modify);
test(kevent_signal_add, ctx);
test(kevent_signal_del, ctx);
test(kevent_signal_get, ctx);
test(kevent_signal_disable, ctx);
test(kevent_signal_enable, ctx);
test(kevent_signal_oneshot, ctx);
test(kevent_signal_modify, ctx);
#if HAVE_EV_DISPATCH
test(kevent_signal_dispatch);
test(kevent_signal_dispatch, ctx);
#endif
}

View File

@ -16,151 +16,155 @@
#include "common.h"
static int __thread kqfd;
void
test_kevent_timer_add(void)
test_kevent_timer_add(struct test_context *ctx)
{
struct kevent kev;
kevent_add(kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
}
void
test_kevent_timer_del(void)
test_kevent_timer_del(struct test_context *ctx)
{
struct kevent kev;
kevent_add(kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
void
test_kevent_timer_get(void)
test_kevent_timer_get(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
kevent_add(kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
kev.flags |= EV_CLEAR;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
kevent_add(kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
}
static void
test_kevent_timer_oneshot(void)
test_kevent_timer_oneshot(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
kevent_add(ctx->kqfd, &kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
/* Retrieve the event */
kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Check if the event occurs again */
sleep(3);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
static void
test_kevent_timer_periodic(void)
test_kevent_timer_periodic(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, 3, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
kevent_add(ctx->kqfd, &kev, 3, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
/* Retrieve the event */
kev.flags = EV_ADD | EV_CLEAR;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Check if the event occurs again */
sleep(1);
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Delete the event */
kev.flags = EV_DELETE;
kevent_update(kqfd, &kev);
kevent_update(ctx->kqfd, &kev);
}
static void
test_kevent_timer_disable_and_enable(void)
test_kevent_timer_disable_and_enable(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Add the watch and immediately disable it */
kevent_add(kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
kev.flags = EV_DISABLE;
kevent_update(kqfd, &kev);
test_no_kevents(kqfd);
kevent_update(ctx->kqfd, &kev);
test_no_kevents(ctx->kqfd);
/* Re-enable and check again */
kev.flags = EV_ENABLE;
kevent_update(kqfd, &kev);
kevent_update(ctx->kqfd, &kev);
kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
}
#if HAVE_EV_DISPATCH
void
test_kevent_timer_dispatch(void)
test_kevent_timer_dispatch(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 800, NULL);
kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 800, NULL);
/* Get one event */
kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Confirm that the knote is disabled */
sleep(1);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Enable the knote and make sure no events are pending */
kevent_add(kqfd, &kev, 4, EVFILT_TIMER, EV_ENABLE | EV_DISPATCH, 0, 800, NULL);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ENABLE | EV_DISPATCH, 0, 800, NULL);
test_no_kevents(ctx->kqfd);
/* Get the next event */
sleep(1);
kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Remove the knote and ensure the event no longer fires */
kevent_add(kqfd, &kev, 4, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
sleep(1);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
#endif /* HAVE_EV_DISPATCH */
void
test_evfilt_timer(int _kqfd)
test_evfilt_timer(struct test_context *ctx)
{
kqfd = _kqfd;
test(kevent_timer_add);
test(kevent_timer_del);
test(kevent_timer_get);
test(kevent_timer_oneshot);
test(kevent_timer_periodic);
test(kevent_timer_disable_and_enable);
test(kevent_timer_add, ctx);
test(kevent_timer_del, ctx);
test(kevent_timer_get, ctx);
test(kevent_timer_oneshot, ctx);
test(kevent_timer_periodic, ctx);
test(kevent_timer_disable_and_enable, ctx);
#if HAVE_EV_DISPATCH
test(kevent_timer_dispatch);
test(kevent_timer_dispatch, ctx);
#endif
}

View File

@ -16,153 +16,155 @@
#include "common.h"
static int __thread kqfd;
static void
test_kevent_user_add_and_delete(void)
test_kevent_user_add_and_delete(struct test_context *ctx)
{
struct kevent kev;
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
test_no_kevents(ctx->kqfd);
}
static void
test_kevent_user_get(void)
test_kevent_user_get(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Add the event, and then trigger it */
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kev.fflags &= ~NOTE_FFCTRLMASK;
kev.fflags &= ~NOTE_TRIGGER;
kev.flags = EV_CLEAR;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
static void
test_kevent_user_get_hires(void)
test_kevent_user_get_hires(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Add the event, and then trigger it */
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kev.fflags &= ~NOTE_FFCTRLMASK;
kev.fflags &= ~NOTE_TRIGGER;
kev.flags = EV_CLEAR;
kevent_cmp(&kev, kevent_get_hires(kqfd));
kevent_get(&ret, ctx->kqfd); //FIXME: Shouldn't this be kevent_get_hires() ?
kevent_cmp(&kev, &ret);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
static void
test_kevent_user_disable_and_enable(void)
test_kevent_user_disable_and_enable(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DISABLE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DISABLE, 0, 0, NULL);
/* Trigger the event, but since it is disabled, nothing will happen. */
kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ENABLE, 0, 0, NULL);
kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ENABLE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kev.flags = EV_CLEAR;
kev.fflags &= ~NOTE_FFCTRLMASK;
kev.fflags &= ~NOTE_TRIGGER;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
}
static void
test_kevent_user_oneshot(void)
test_kevent_user_oneshot(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, 2, EVFILT_USER, EV_ADD | EV_ONESHOT, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 2, EVFILT_USER, EV_ADD | EV_ONESHOT, 0, 0, NULL);
puts(" -- event 1");
kevent_add(kqfd, &kev, 2, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kevent_add(ctx->kqfd, &kev, 2, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kev.flags = EV_ONESHOT;
kev.fflags &= ~NOTE_FFCTRLMASK;
kev.fflags &= ~NOTE_TRIGGER;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
#if HAVE_EV_DISPATCH
void
test_kevent_user_dispatch(void)
test_kevent_user_dispatch(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Add the event, and then trigger it */
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
/* Retrieve one event */
kev.fflags &= ~NOTE_FFCTRLMASK;
kev.fflags &= ~NOTE_TRIGGER;
kev.flags = EV_CLEAR;
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
/* Confirm that the knote is disabled automatically */
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Re-enable the kevent */
/* FIXME- is EV_DISPATCH needed when rearming ? */
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ENABLE | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ENABLE | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
test_no_kevents(ctx->kqfd);
/* Trigger the event */
kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
kev.fflags &= ~NOTE_FFCTRLMASK;
kev.fflags &= ~NOTE_TRIGGER;
kev.flags = EV_CLEAR;
kevent_cmp(&kev, kevent_get(kqfd));
test_no_kevents(kqfd);
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(ctx->kqfd);
/* Delete the watch */
kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
test_no_kevents(kqfd);
kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
test_no_kevents(ctx->kqfd);
}
#endif /* HAVE_EV_DISPATCH */
void
test_evfilt_user(int _kqfd)
test_evfilt_user(struct test_context *ctx)
{
kqfd = _kqfd;
test(kevent_user_add_and_delete);
test(kevent_user_get);
test(kevent_user_get_hires);
test(kevent_user_disable_and_enable);
test(kevent_user_oneshot);
test(kevent_user_add_and_delete, ctx);
test(kevent_user_get, ctx);
test(kevent_user_get_hires, ctx);
test(kevent_user_disable_and_enable, ctx);
test(kevent_user_oneshot, ctx);
#if HAVE_EV_DISPATCH
test(kevent_user_dispatch);
test(kevent_user_dispatch, ctx);
#endif
/* TODO: try different fflags operations */
}

View File

@ -16,120 +16,117 @@
#include "common.h"
static int __thread kqfd;
static int __thread vnode_fd;
static char __thread testfile[1024];
/* Create an empty file */
static void
testfile_create(void)
testfile_create(const char *path)
{
int fd;
if ((fd = open(testfile, O_CREAT | O_WRONLY, 0600)) < 0)
if ((fd = open(path, O_CREAT | O_WRONLY, 0600)) < 0)
die("open");
close(fd);
}
static void
testfile_touch(void)
testfile_touch(const char *path)
{
char buf[1024];
snprintf(&buf[0], sizeof(buf), "touch %s", testfile);
snprintf(&buf[0], sizeof(buf), "touch %s", path);
if (system(buf) != 0)
die("system");
}
static void
testfile_write(void)
testfile_write(const char *path)
{
char buf[1024];
snprintf(&buf[0], sizeof(buf), "echo hi >> %s", testfile);
snprintf(&buf[0], sizeof(buf), "echo hi >> %s", path);
if (system(buf) != 0)
die("system");
}
static void
testfile_rename(int step)
testfile_rename(const char *path, int step)
{
char buf[1024];
snprintf(&buf[0], sizeof(buf), "%s.tmp", testfile);
snprintf(&buf[0], sizeof(buf), "%s.tmp", path);
/* XXX-FIXME use of 'step' conceals a major memory corruption
when the file is renamed twice.
To replicate, remove "if step" conditional so
two renames occur in this function.
*/
if (step == 0) {
if (rename(testfile,buf) != 0)
if (rename(path, buf) != 0)
err(1,"rename");
} else {
if (rename(buf, testfile) != 0)
if (rename(buf, path) != 0)
err(1,"rename");
}
}
void
test_kevent_vnode_add(void)
test_kevent_vnode_add(struct test_context *ctx)
{
struct kevent kev;
testfile_create();
testfile_create(ctx->testfile);
vnode_fd = open(testfile, O_RDWR);
if (vnode_fd < 0)
err(1, "open of %s", testfile);
ctx->vnode_fd = open(ctx->testfile, O_RDWR);
if (ctx->vnode_fd < 0)
err(1, "open of %s", ctx->testfile);
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ADD,
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD,
NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
}
void
test_kevent_vnode_note_delete(void)
test_kevent_vnode_note_delete(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
if (unlink(testfile) < 0)
if (unlink(ctx->testfile) < 0)
die("unlink");
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
}
void
test_kevent_vnode_note_write(void)
test_kevent_vnode_note_write(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
testfile_write();
testfile_write(ctx->testfile);
/* BSD kqueue adds NOTE_EXTEND even though it was not requested */
/* BSD kqueue removes EV_ENABLE */
kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
kevent_cmp(&kev, kevent_get(kqfd));
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
}
void
test_kevent_vnode_note_attrib(void)
test_kevent_vnode_note_attrib(struct test_context *ctx)
{
struct kevent kev;
int nfds;
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
testfile_touch();
testfile_touch(ctx->testfile);
nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
if (nfds < 1)
die("kevent");
if (kev.ident != vnode_fd ||
if (kev.ident != ctx->vnode_fd ||
kev.filter != EVFILT_VNODE ||
kev.fflags != NOTE_ATTRIB)
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
@ -137,62 +134,62 @@ test_kevent_vnode_note_attrib(void)
}
void
test_kevent_vnode_note_rename(void)
test_kevent_vnode_note_rename(struct test_context *ctx)
{
struct kevent kev;
int nfds;
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
testfile_rename(0);
testfile_rename(ctx->testfile, 0);
nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
if (nfds < 1)
die("kevent");
if (kev.ident != vnode_fd ||
if (kev.ident != ctx->vnode_fd ||
kev.filter != EVFILT_VNODE ||
kev.fflags != NOTE_RENAME)
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
testfile_rename(1);
testfile_rename(ctx->testfile, 1);
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
}
void
test_kevent_vnode_del(void)
test_kevent_vnode_del(struct test_context *ctx)
{
struct kevent kev;
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
}
void
test_kevent_vnode_disable_and_enable(void)
test_kevent_vnode_disable_and_enable(struct test_context *ctx)
{
struct kevent kev;
int nfds;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
/* Add the watch and immediately disable it */
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
kev.flags = EV_DISABLE;
kevent_update(kqfd, &kev);
kevent_update(ctx->kqfd, &kev);
/* Confirm that the watch is disabled */
testfile_touch();
test_no_kevents(kqfd);
testfile_touch(ctx->testfile);
test_no_kevents(ctx->kqfd);
/* Re-enable and check again */
kev.flags = EV_ENABLE;
kevent_update(kqfd, &kev);
testfile_touch();
nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
kevent_update(ctx->kqfd, &kev);
testfile_touch(ctx->testfile);
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
if (nfds < 1)
die("kevent");
if (kev.ident != vnode_fd ||
if (kev.ident != ctx->vnode_fd ||
kev.filter != EVFILT_VNODE ||
kev.fflags != NOTE_ATTRIB)
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
@ -201,66 +198,65 @@ test_kevent_vnode_disable_and_enable(void)
#if HAVE_EV_DISPATCH
void
test_kevent_vnode_dispatch(void)
test_kevent_vnode_dispatch(struct test_context *ctx)
{
struct kevent kev;
struct kevent kev, ret;
int nfds;
test_no_kevents(kqfd);
test_no_kevents(ctx->kqfd);
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
testfile_touch();
testfile_touch(ctx->testfile);
nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
if (nfds < 1)
die("kevent");
if (kev.ident != vnode_fd ||
if (kev.ident != ctx->vnode_fd ||
kev.filter != EVFILT_VNODE ||
kev.fflags != NOTE_ATTRIB)
err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
/* Confirm that the watch is disabled automatically */
testfile_touch();
test_no_kevents(kqfd);
testfile_touch(ctx->testfile);
test_no_kevents(ctx->kqfd);
/* Re-enable the kevent */
/* FIXME- is EV_DISPATCH needed when rearming ? */
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
kev.flags = EV_ADD | EV_DISPATCH; /* FIXME: may not be portable */
kev.fflags = NOTE_ATTRIB;
testfile_touch();
kevent_cmp(&kev, kevent_get(kqfd));
test_no_kevents(kqfd);
testfile_touch(ctx->testfile);
kevent_get(&ret, ctx->kqfd);
kevent_cmp(&kev, &ret);
test_no_kevents(ctx->kqfd);
/* Delete the watch */
kevent_add(kqfd, &kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
}
#endif /* HAVE_EV_DISPATCH */
void
test_evfilt_vnode(int _kqfd)
test_evfilt_vnode(struct test_context *ctx)
{
#if (defined(__sun) && !defined(HAVE_PORT_SOURCE_FILE))
puts("**NOTE** EVFILT_VNODE is not supported on this version of Solaris");
return;
#endif
snprintf(testfile, sizeof(testfile), "/tmp/kqueue-test%d.tmp",
snprintf(ctx->testfile, sizeof(ctx->testfile), "/tmp/kqueue-test%d.tmp",
testing_make_uid());
kqfd = _kqfd;
test(kevent_vnode_add);
test(kevent_vnode_del);
test(kevent_vnode_disable_and_enable);
test(kevent_vnode_add, ctx);
test(kevent_vnode_del, ctx);
test(kevent_vnode_disable_and_enable, ctx);
#if HAVE_EV_DISPATCH
test(kevent_vnode_dispatch);
test(kevent_vnode_dispatch, ctx);
#endif
test(kevent_vnode_note_write);
test(kevent_vnode_note_attrib);
test(kevent_vnode_note_rename);
test(kevent_vnode_note_delete);
unlink(testfile);
test(kevent_vnode_note_write, ctx);
test(kevent_vnode_note_attrib, ctx);
test(kevent_vnode_note_rename, ctx);
test(kevent_vnode_note_delete, ctx);
unlink(ctx->testfile);
}