mirror of
https://github.com/darlinghq/darling-libkqueue.git
synced 2024-11-26 21:20:38 +00:00
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:
parent
68e94a12eb
commit
cd858d02fd
2
Makefile
2
Makefile
@ -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
|
||||
|
@ -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" \
|
||||
|
@ -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__)
|
||||
|
@ -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() {
|
||||
|
@ -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 *
|
||||
|
146
test/main.c
146
test/main.c
@ -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);
|
||||
}
|
||||
|
29
test/proc.c
29
test/proc.c
@ -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);
|
||||
|
||||
|
283
test/read.c
283
test/read.c
@ -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);
|
||||
}
|
||||
|
107
test/signal.c
107
test/signal.c
@ -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
|
||||
}
|
||||
|
110
test/timer.c
110
test/timer.c
@ -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
|
||||
}
|
||||
|
124
test/user.c
124
test/user.c
@ -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 */
|
||||
}
|
||||
|
160
test/vnode.c
160
test/vnode.c
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user