Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 13 Dec 2009 20:27:46 +0000 (UTC)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r200483 - head/tools/regression/kqueue
Message-ID:  <200912132027.nBDKRkhM096316@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rwatson
Date: Sun Dec 13 20:27:46 2009
New Revision: 200483
URL: http://svn.freebsd.org/changeset/base/200483

Log:
  Add Mark Heily's libkqueue test suite as a general kqueue test suite to
  tools/regression.  It tests a number of aspects of kqueue behavior,
  although not all currently pass (possibly bugs in the test suite?).
  
  Submitted by:	Mark Heily <mark at heily.com>
  Obtained from:	svn://mark.heily.com/libkqueue/trunk/test (r114)

Added:
  head/tools/regression/kqueue/
  head/tools/regression/kqueue/Makefile   (contents, props changed)
  head/tools/regression/kqueue/common.h   (contents, props changed)
  head/tools/regression/kqueue/config.h   (contents, props changed)
  head/tools/regression/kqueue/main.c   (contents, props changed)
  head/tools/regression/kqueue/proc.c   (contents, props changed)
  head/tools/regression/kqueue/read.c   (contents, props changed)
  head/tools/regression/kqueue/signal.c   (contents, props changed)
  head/tools/regression/kqueue/timer.c   (contents, props changed)
  head/tools/regression/kqueue/user.c   (contents, props changed)
  head/tools/regression/kqueue/vnode.c   (contents, props changed)

Added: head/tools/regression/kqueue/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/kqueue/Makefile	Sun Dec 13 20:27:46 2009	(r200483)
@@ -0,0 +1,21 @@
+# $FreeBSD$
+#
+# svn://mark.heily.com/libkqueue/trunk/test
+# Last update: r114
+#
+# libkqueue and test suite by Mark Heily <mark@heily.com>
+#
+
+PROG=kqtest
+SRCS=			\
+	main.c		\
+	read.c		\
+	timer.c		\
+	vnode.c		\
+	proc.c		\
+	signal.c	\
+	user.c
+NO_MAN=
+WARNS=2
+
+.include "bsd.prog.mk"

Added: head/tools/regression/kqueue/common.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/kqueue/common.h	Sun Dec 13 20:27:46 2009	(r200483)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+
+#if HAVE_ERR_H
+# include <err.h>
+#else
+# define err(rc,msg,...) do { perror(msg); exit(rc); } while (0)
+# define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0)
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sys/event.h>
+
+#include "config.h"
+
+extern char *cur_test_id;
+int vnode_fd;
+
+extern const char * kevent_to_str(struct kevent *);
+struct kevent * kevent_get(int);
+
+
+void kevent_cmp(struct kevent *, struct kevent *);
+
+void
+kevent_add(int kqfd, struct kevent *kev, 
+        uintptr_t ident,
+        short     filter,
+        u_short   flags,
+        u_int     fflags,
+        intptr_t  data,
+        void      *udata);
+
+/* DEPRECATED: */
+#define KEV_CMP(kev,_ident,_filter,_flags) do {                 \
+    if (kev.ident != (_ident) ||                                \
+            kev.filter != (_filter) ||                          \
+            kev.flags != (_flags)) \
+        err(1, "kevent mismatch: got [%d,%d,%d] but expecting [%d,%d,%d]", \
+                (int)_ident, (int)_filter, (int)_flags,\
+                (int)kev.ident, kev.filter, kev.flags);\
+} while (0);
+
+/* Checks if any events are pending, which is an error. */
+extern void test_no_kevents(void);
+
+extern void test_begin(const char *);
+extern void success(void);
+
+#endif  /* _COMMON_H */

Added: head/tools/regression/kqueue/config.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/kqueue/config.h	Sun Dec 13 20:27:46 2009	(r200483)
@@ -0,0 +1,12 @@
+/* AUTOMATICALLY GENERATED -- DO NOT EDIT */
+/* $FreeBSD$ */
+#define HAVE_SYS_EVENT_H
+#define HAVE_EV_DISPATCH 1
+#define HAVE_EV_RECEIPT 1
+#undef HAVE_NOTE_TRUNCATE
+#define HAVE_EVFILT_TIMER 1
+#define HAVE_EVFILT_USER 1
+#define PROGRAM "libkqueue-test"
+#define VERSION "0.1"
+#define TARGET "freebsd"
+#define CFLAGS "-g -O0 -Wall -Werror"

Added: head/tools/regression/kqueue/main.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/kqueue/main.c	Sun Dec 13 20:27:46 2009	(r200483)
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include "common.h"
+
+int testnum = 1;
+char *cur_test_id = NULL;
+int kqfd;
+
+extern void test_evfilt_read();
+extern void test_evfilt_signal();
+extern void test_evfilt_vnode();
+extern void test_evfilt_timer();
+extern void test_evfilt_proc();
+#if HAVE_EVFILT_USER
+extern void test_evfilt_user();
+#endif
+
+/* Checks if any events are pending, which is an error. */
+void 
+test_no_kevents(void)
+{
+    int nfds;
+    struct timespec timeo;
+    struct kevent kev;
+
+    puts("confirming that there are no events pending");
+    memset(&timeo, 0, sizeof(timeo));
+    nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
+    if (nfds != 0) {
+        puts("\nUnexpected event:");
+        puts(kevent_to_str(&kev));
+        errx(1, "%d event(s) pending, but none expected:", nfds);
+    }
+}
+
+/* Retrieve a single kevent */
+struct kevent *
+kevent_get(int kqfd)
+{
+    int nfds;
+    struct kevent *kev;
+
+    if ((kev = calloc(1, sizeof(*kev))) == NULL)
+	err(1, "out of memory");
+    
+    nfds = kevent(kqfd, NULL, 0, kev, 1, NULL);
+    if (nfds < 1)
+        err(1, "kevent(2)");
+
+    return (kev);
+}
+
+char *
+kevent_fflags_dump(struct kevent *kev)
+{
+    char *buf;
+
+#define KEVFFL_DUMP(attrib) \
+    if (kev->fflags & attrib) \
+	strncat(buf, #attrib" ", 64);
+
+    if ((buf = calloc(1, 1024)) == NULL)
+	abort();
+
+    /* Not every filter has meaningful fflags */
+    if (kev->filter != EVFILT_VNODE) {
+    	snprintf(buf, 1024, "fflags = %d", kev->fflags);
+	return (buf);
+    }
+
+    snprintf(buf, 1024, "fflags = %d (", kev->fflags);
+    KEVFFL_DUMP(NOTE_DELETE);
+    KEVFFL_DUMP(NOTE_WRITE);
+    KEVFFL_DUMP(NOTE_EXTEND);
+#if HAVE_NOTE_TRUNCATE
+    KEVFFL_DUMP(NOTE_TRUNCATE);
+#endif
+    KEVFFL_DUMP(NOTE_ATTRIB);
+    KEVFFL_DUMP(NOTE_LINK);
+    KEVFFL_DUMP(NOTE_RENAME);
+#if HAVE_NOTE_REVOKE
+    KEVFFL_DUMP(NOTE_REVOKE);
+#endif
+    buf[strlen(buf) - 1] = ')';
+
+    return (buf);
+}
+
+char *
+kevent_flags_dump(struct kevent *kev)
+{
+    char *buf;
+
+#define KEVFL_DUMP(attrib) \
+    if (kev->flags & attrib) \
+	strncat(buf, #attrib" ", 64);
+
+    if ((buf = calloc(1, 1024)) == NULL)
+	abort();
+
+    snprintf(buf, 1024, "flags = %d (", kev->flags);
+    KEVFL_DUMP(EV_ADD);
+    KEVFL_DUMP(EV_ENABLE);
+    KEVFL_DUMP(EV_DISABLE);
+    KEVFL_DUMP(EV_DELETE);
+    KEVFL_DUMP(EV_ONESHOT);
+    KEVFL_DUMP(EV_CLEAR);
+    KEVFL_DUMP(EV_EOF);
+    KEVFL_DUMP(EV_ERROR);
+#if HAVE_EV_DISPATCH
+    KEVFL_DUMP(EV_DISPATCH);
+#endif
+#if HAVE_EV_RECEIPT
+    KEVFL_DUMP(EV_RECEIPT);
+#endif
+    buf[strlen(buf) - 1] = ')';
+
+    return (buf);
+}
+
+/* Copied from ../kevent.c kevent_dump() and improved */
+const char *
+kevent_to_str(struct kevent *kev)
+{
+    char buf[512];
+
+    snprintf(&buf[0], sizeof(buf), 
+            "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]",
+            (u_int) kev->ident,
+            kev->filter,
+            kevent_flags_dump(kev),
+            kevent_fflags_dump(kev),
+            (int) kev->data,
+            kev->udata);
+
+    return (strdup(buf));
+}
+
+void
+kevent_add(int kqfd, struct kevent *kev, 
+        uintptr_t ident,
+        short     filter,
+        u_short   flags,
+        u_int     fflags,
+        intptr_t  data,
+        void      *udata)
+{
+    EV_SET(kev, ident, filter, flags, fflags, data, NULL);    
+    if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) {
+        printf("Unable to add the following kevent:\n%s\n",
+                kevent_to_str(kev));
+        err(1, "kevent(): %s", strerror(errno));
+    }
+}
+
+void
+kevent_cmp(struct kevent *k1, struct kevent *k2)
+{
+/* XXX-
+   Workaround for inconsistent implementation of kevent(2) 
+ */
+#ifdef __FreeBSD__
+    if (k1->flags & EV_ADD)
+        k2->flags |= EV_ADD;
+#endif
+    if (memcmp(k1, k2, sizeof(*k1)) != 0) {
+        printf("kevent_cmp: mismatch:\n  %s !=\n  %s\n", 
+              kevent_to_str(k1), kevent_to_str(k2));
+        abort();
+    }
+}
+
+void
+test_begin(const char *func)
+{
+    if (cur_test_id)
+        free(cur_test_id);
+    cur_test_id = strdup(func);
+    if (!cur_test_id)
+        err(1, "strdup failed");
+
+    printf("\n\nTest %d: %s\n", testnum++, func);
+}
+
+void
+success(void)
+{
+    printf("%-70s %s\n", cur_test_id, "passed");
+    free(cur_test_id);
+    cur_test_id = NULL;
+}
+
+void
+test_kqueue(void)
+{
+    test_begin("kqueue()");
+    if ((kqfd = kqueue()) < 0)
+        err(1, "kqueue()");
+    test_no_kevents();
+    success();
+}
+
+void
+test_kqueue_close(void)
+{
+    test_begin("close(kq)");
+    if (close(kqfd) < 0)
+        err(1, "close()");
+    success();
+}
+
+int 
+main(int argc, char **argv)
+{
+    int test_proc = 0;  /* XXX-FIXME */
+    int test_socket = 1;
+    int test_signal = 1;
+    int test_vnode = 1;
+    int test_timer = 1;
+    int test_user = 1;
+
+    while (argc) {
+        if (strcmp(argv[0], "--no-proc") == 0)
+            test_proc = 0;
+        if (strcmp(argv[0], "--no-socket") == 0)
+            test_socket = 0;
+        if (strcmp(argv[0], "--no-timer") == 0)
+            test_timer = 0;
+        if (strcmp(argv[0], "--no-signal") == 0)
+            test_signal = 0;
+        if (strcmp(argv[0], "--no-vnode") == 0)
+            test_vnode = 0;
+        if (strcmp(argv[0], "--no-user") == 0)
+            test_user = 0;
+        argv++;
+        argc--;
+    }
+
+    test_kqueue();
+    test_kqueue_close();
+
+    if (test_socket) 
+        test_evfilt_read();
+    if (test_signal) 
+        test_evfilt_signal();
+    if (test_vnode) 
+        test_evfilt_vnode();
+#if HAVE_EVFILT_USER
+    if (test_user) 
+        test_evfilt_user();
+#endif
+    if (test_timer) 
+        test_evfilt_timer();
+    if (test_proc) 
+        test_evfilt_proc();
+
+    printf("\n---\n"
+            "+OK All %d tests completed.\n", testnum - 1);
+    return (0);
+}

Added: head/tools/regression/kqueue/proc.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/kqueue/proc.c	Sun Dec 13 20:27:46 2009	(r200483)
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+static int sigusr1_caught = 0;
+
+int kqfd;
+
+static void
+sig_handler(int signum)
+{
+    sigusr1_caught = 1;
+}
+
+static void
+add_and_delete(void)
+{
+    struct kevent kev;
+    pid_t pid;
+
+    /* Create a child that waits to be killed and then exits */
+    pid = fork();
+    if (pid == 0) {
+        pause();
+        exit(2);
+    }
+    printf(" -- child created (pid %d)\n", (int) pid);
+
+    test_begin("kevent(EVFILT_PROC, EV_ADD)");
+
+    test_no_kevents();
+    kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
+    test_no_kevents();
+
+    success();
+
+    test_begin("kevent(EVFILT_PROC, EV_DELETE)");
+
+    test_no_kevents();
+    kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
+    if (kill(pid, SIGKILL) < 0)
+        err(1, "kill");
+    sleep(1);
+    test_no_kevents();
+
+    success();
+
+}
+
+static void
+event_trigger(void)
+{
+    struct kevent kev;
+    pid_t pid;
+
+    test_begin("kevent(EVFILT_PROC, wait)");
+
+    /* Create a child that waits to be killed and then exits */
+    pid = fork();
+    if (pid == 0) {
+        pause();
+        printf(" -- child caught signal, exiting\n");
+        exit(2);
+    }
+    printf(" -- child created (pid %d)\n", (int) pid);
+
+    test_no_kevents();
+    kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
+
+    /* Cause the child to exit, then retrieve the event */
+    printf(" -- killing process %d\n", (int) pid);
+    if (kill(pid, SIGUSR1) < 0)
+        err(1, "kill");
+    kevent_cmp(&kev, kevent_get(kqfd));
+    test_no_kevents();
+
+    success();
+}
+
+#ifdef TODO
+void
+test_kevent_signal_disable(void)
+{
+    const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Block SIGUSR1, then send it to ourselves */
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR1);
+    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+        err(1, "sigprocmask");
+    if (kill(getpid(), SIGKILL) < 0)
+        err(1, "kill");
+
+    test_no_kevents();
+
+    success();
+}
+
+void
+test_kevent_signal_enable(void)
+{
+    const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Block SIGUSR1, then send it to ourselves */
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR1);
+    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+        err(1, "sigprocmask");
+    if (kill(getpid(), SIGUSR1) < 0)
+        err(1, "kill");
+
+    kev.flags = EV_ADD | EV_CLEAR;
+#if LIBKQUEUE
+    kev.data = 1; /* WORKAROUND */
+#else
+    kev.data = 2; // one extra time from test_kevent_signal_disable()
+#endif
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Delete the watch */
+    kev.flags = EV_DELETE;
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    success();
+}
+
+void
+test_kevent_signal_del(void)
+{
+    const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    /* Delete the kevent */
+    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Block SIGUSR1, then send it to ourselves */
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR1);
+    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+        err(1, "sigprocmask");
+    if (kill(getpid(), SIGUSR1) < 0)
+        err(1, "kill");
+
+    test_no_kevents();
+    success();
+}
+
+void
+test_kevent_signal_oneshot(void)
+{
+    const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Block SIGUSR1, then send it to ourselves */
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGUSR1);
+    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+        err(1, "sigprocmask");
+    if (kill(getpid(), SIGUSR1) < 0)
+        err(1, "kill");
+
+    kev.flags |= EV_CLEAR;
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Send another one and make sure we get no events */
+    if (kill(getpid(), SIGUSR1) < 0)
+        err(1, "kill");
+    test_no_kevents();
+
+    success();
+}
+#endif
+
+void
+test_evfilt_proc()
+{
+    kqfd = kqueue();
+
+    signal(SIGUSR1, sig_handler);
+
+    add_and_delete();
+    event_trigger();
+
+    signal(SIGUSR1, SIG_DFL);
+
+#if TODO
+    test_kevent_signal_add();
+    test_kevent_signal_del();
+    test_kevent_signal_get();
+    test_kevent_signal_disable();
+    test_kevent_signal_enable();
+    test_kevent_signal_oneshot();
+#endif
+    close(kqfd);
+}

Added: head/tools/regression/kqueue/read.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/kqueue/read.c	Sun Dec 13 20:27:46 2009	(r200483)
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+int kqfd;
+int sockfd[2];
+
+static void
+kevent_socket_drain(void)
+{
+    char buf[1];
+
+    /* Drain the read buffer, then make sure there are no more events. */
+    puts("draining the read buffer");
+    if (read(sockfd[0], &buf[0], 1) < 1)
+        err(1, "read(2)");
+}
+
+static void
+kevent_socket_fill(void)
+{
+  puts("filling the read buffer");
+    if (write(sockfd[1], ".", 1) < 1)
+        err(1, "write(2)");
+}
+
+
+void
+test_kevent_socket_add(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, EV_ADD)";
+    struct kevent kev;
+
+    test_begin(test_id);
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    success();
+}
+
+void
+test_kevent_socket_get(void)
+{
+    const char *test_id = "kevent(EVFILT_READ) wait";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    kevent_socket_fill();
+
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    kevent_socket_drain();
+    test_no_kevents();
+
+    kev.flags = EV_DELETE;
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    success();
+}
+
+void
+test_kevent_socket_clear(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, EV_CLEAR)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    test_no_kevents();
+
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    kevent_socket_fill();
+    kevent_socket_fill();
+
+    kev.data = 2;
+    kevent_cmp(&kev, kevent_get(kqfd)); 
+
+    /* We filled twice, but drain once. Edge-triggered would not generate
+       additional events.
+     */
+    kevent_socket_drain();
+    test_no_kevents();
+
+    kevent_socket_drain();
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    success();
+}
+
+void
+test_kevent_socket_disable_and_enable(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, EV_DISABLE)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    /* Add an event, then disable it. */
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DISABLE, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    kevent_socket_fill();
+    test_no_kevents();
+
+    /* Re-enable the knote, then see if an event is generated */
+    kev.flags = EV_ENABLE;
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    kev.flags = EV_ADD;
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    kevent_socket_drain();
+
+    kev.flags = EV_DELETE;
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    success();
+}
+
+void
+test_kevent_socket_del(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, EV_DELETE)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    kevent_socket_fill();
+    test_no_kevents();
+    kevent_socket_drain();
+
+    success();
+}
+
+void
+test_kevent_socket_oneshot(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    /* Re-add the watch and make sure no events are pending */
+    puts("-- re-adding knote");
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    test_no_kevents();
+
+    puts("-- getting one event");
+    kevent_socket_fill();
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    puts("-- checking knote disabled");
+    test_no_kevents();
+
+    /* Try to delete the knote, it should already be deleted */
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
+        err(1, "%s", test_id);
+
+    kevent_socket_drain();
+
+    success();
+}
+
+
+#if HAVE_EV_DISPATCH
+void
+test_kevent_socket_dispatch(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)";
+
+    test_begin(test_id);
+
+    struct kevent kev;
+
+    /* Re-add the watch and make sure no events are pending */
+    puts("-- re-adding knote");
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    test_no_kevents();
+
+    /* The event will occur only once, even though EV_CLEAR is not
+       specified. */
+    kevent_socket_fill();
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+    test_no_kevents();
+
+    /* Since the knote is disabled, the EV_DELETE operation succeeds. */
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    kevent_socket_drain();
+
+    success();
+}
+#endif  /* HAVE_EV_DISPATCH */
+
+#if BROKEN
+void
+test_kevent_socket_lowat(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    /* Re-add the watch and make sure no events are pending */
+    puts("-- re-adding knote, setting low watermark to 2 bytes");
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    test_no_kevents();
+
+    puts("-- checking that one byte does not trigger an event..");
+    kevent_socket_fill();
+    test_no_kevents();
+
+    puts("-- checking that two bytes triggers an event..");
+    kevent_socket_fill();
+    if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
+        err(1, "%s", test_id);
+    KEV_CMP(kev, sockfd[0], EVFILT_READ, 0);
+    test_no_kevents();
+
+    kevent_socket_drain();
+    kevent_socket_drain();
+
+    success();
+}
+#endif
+
+void
+test_kevent_socket_eof(void)
+{
+    const char *test_id = "kevent(EVFILT_READ, EV_EOF)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    /* Re-add the watch and make sure no events are pending */
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    test_no_kevents();
+
+    if (close(sockfd[1]) < 0)
+        err(1, "close(2)");
+
+    kev.flags |= EV_EOF;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Delete the watch */
+    EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    success();
+}
+
+void
+test_evfilt_read()
+{
+    /* Create a connected pair of full-duplex sockets for testing socket events */
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) 
+        abort();
+
+    kqfd = kqueue();
+    test_kevent_socket_add();
+    test_kevent_socket_del();
+    test_kevent_socket_get();
+    test_kevent_socket_disable_and_enable();
+    test_kevent_socket_oneshot();
+    test_kevent_socket_clear();
+#if HAVE_EV_DISPATCH
+    test_kevent_socket_dispatch();
+#endif
+    test_kevent_socket_eof();
+    close(kqfd);
+}

Added: head/tools/regression/kqueue/signal.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/kqueue/signal.c	Sun Dec 13 20:27:46 2009	(r200483)
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+int kqfd;
+
+void
+test_kevent_signal_add(void)
+{

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912132027.nBDKRkhM096316>