summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2015-10-05 03:26:51 +0000
committerngie <ngie@FreeBSD.org>2015-10-05 03:26:51 +0000
commite1dd16d965b177f109afb771e59432e36f335d0a (patch)
tree15db092a5401cf329f1bff9d3bf700d1fde0f121 /tests
parent115d008392113efc6f844baa7cc407e9eaae63db (diff)
downloadFreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.zip
FreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.tar.gz
Revert r288682
I meant to do this on ^/user/ngie/more-tests Pointyhat to: ngie (use svn info next time...)
Diffstat (limited to 'tests')
-rw-r--r--tests/sys/kern/execve/Makefile39
-rw-r--r--tests/sys/kern/execve/bad_interp_len4
-rw-r--r--tests/sys/kern/execve/dev_null_script4
-rw-r--r--tests/sys/kern/execve/execve_helper.c54
-rw-r--r--tests/sys/kern/execve/execve_test.sh115
-rw-r--r--tests/sys/kern/execve/good_aout.c45
-rw-r--r--tests/sys/kern/execve/good_script4
-rw-r--r--tests/sys/kern/execve/non_exist_shell4
-rw-r--r--tests/sys/kern/execve/script_arg4
-rw-r--r--tests/sys/kern/execve/script_arg_nospace4
-rw-r--r--tests/sys/kqueue/Makefile26
-rw-r--r--tests/sys/kqueue/common.h78
-rw-r--r--tests/sys/kqueue/config.h13
-rwxr-xr-xtests/sys/kqueue/kqueue_test.sh17
-rw-r--r--tests/sys/kqueue/main.c284
-rw-r--r--tests/sys/kqueue/proc.c255
-rw-r--r--tests/sys/kqueue/read.c324
-rw-r--r--tests/sys/kqueue/signal.c199
-rw-r--r--tests/sys/kqueue/timer.c178
-rw-r--r--tests/sys/kqueue/user.c129
-rw-r--r--tests/sys/kqueue/vnode.c266
21 files changed, 2046 insertions, 0 deletions
diff --git a/tests/sys/kern/execve/Makefile b/tests/sys/kern/execve/Makefile
new file mode 100644
index 0000000..82c5d4b
--- /dev/null
+++ b/tests/sys/kern/execve/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/kern/execve
+
+BINDIR= ${TESTSDIR}
+
+MAN=
+
+ATF_TESTS_SH+= execve_test
+
+PROGS+= good_aout
+PROGS+= execve_helper
+
+LDFLAGS.goodaout+= -static
+
+CLEANFILES+= empty
+CLEANFILES+= sparse_aout
+CLEANFILES+= trunc_aout
+
+SCRIPTS+= bad_interp_len
+SCRIPTS+= dev_null_script
+SCRIPTS+= empty
+SCRIPTS+= good_script
+SCRIPTS+= non_exist_shell
+SCRIPTS+= script_arg
+SCRIPTS+= script_arg_nospace
+SCRIPTS+= sparse_aout
+SCRIPTS+= trunc_aout
+
+empty:
+ @touch $@
+
+sparse_aout:
+ @truncate -s 20480 $@
+
+trunc_aout:
+ @truncate -s 16 $@
+
+.include <bsd.test.mk>
diff --git a/tests/sys/kern/execve/bad_interp_len b/tests/sys/kern/execve/bad_interp_len
new file mode 100644
index 0000000..96c049f
--- /dev/null
+++ b/tests/sys/kern/execve/bad_interp_len
@@ -0,0 +1,4 @@
+#! 456789012345678 0123456789012345 789012345678 012345678901234 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/dev_null_script b/tests/sys/kern/execve/dev_null_script
new file mode 100644
index 0000000..73b1020
--- /dev/null
+++ b/tests/sys/kern/execve/dev_null_script
@@ -0,0 +1,4 @@
+#! /dev/null
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/execve_helper.c b/tests/sys/kern/execve/execve_helper.c
new file mode 100644
index 0000000..164a8f3
--- /dev/null
+++ b/tests/sys/kern/execve/execve_helper.c
@@ -0,0 +1,54 @@
+/* $NetBSD: doexec.c,v 1.8 2003/07/26 19:38:48 salo Exp $ */
+
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <progname>\n", argv[0]);
+ exit(2);
+ }
+
+ execve(argv[1], &argv[1], NULL);
+ err(1, "");
+}
diff --git a/tests/sys/kern/execve/execve_test.sh b/tests/sys/kern/execve/execve_test.sh
new file mode 100644
index 0000000..ef803a1
--- /dev/null
+++ b/tests/sys/kern/execve/execve_test.sh
@@ -0,0 +1,115 @@
+
+bad_interp_len_head()
+{
+ atf_set "descr" "Bad interpreter length"
+}
+bad_interp_len_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper bad_interp_len"
+}
+
+empty_head()
+{
+ atf_set "descr" "Empty file"
+}
+empty_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper empty"
+}
+
+good_aout_head()
+{
+ atf_set "descr" "Good a.out"
+}
+good_aout_body()
+{
+ atf_check -s exit:0 -e empty -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper ./good_aout"
+}
+
+good_script_head()
+{
+ atf_set "descr" "Good script"
+}
+good_script_body()
+{
+ atf_check -s exit:0 -e empty -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper good_script"
+}
+
+non_exist_head()
+{
+ atf_set "descr" "Non-existent file"
+}
+non_exist_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper non_exist"
+}
+
+non_exist_shell_head()
+{
+ atf_set "descr" "Non-existent shell"
+}
+non_exist_shell_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper non_exist_shell"
+}
+
+script_arg_head()
+{
+ atf_set "descr" "-x in the shebang"
+}
+script_arg_body()
+{
+ atf_check -s exit:0 -e 'match:\+ echo succeeded' -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper script_arg"
+}
+
+script_arg_nospace_head()
+{
+ atf_set "descr" '-x in the shebang; no space between #! and /bin/sh'
+}
+script_arg_nospace_body()
+{
+ atf_check -s exit:0 -e 'match:\+ echo succeeded' -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper script_arg_nospace"
+}
+
+sparse_aout_head()
+{
+ atf_set "descr" 'Sparse file'
+}
+sparse_aout_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper sparse_aout"
+}
+
+trunc_aout_head()
+{
+ atf_set "descr" 'Truncated file'
+}
+trunc_aout_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper trunc_aout"
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case bad_interp_len
+ atf_add_test_case empty
+ atf_add_test_case good_aout
+ atf_add_test_case good_script
+ atf_add_test_case non_exist
+ atf_add_test_case non_exist_shell
+ atf_add_test_case script_arg
+ atf_add_test_case script_arg_nospace
+ atf_add_test_case sparse_aout
+ atf_add_test_case trunc_aout
+
+}
diff --git a/tests/sys/kern/execve/good_aout.c b/tests/sys/kern/execve/good_aout.c
new file mode 100644
index 0000000..39e9867
--- /dev/null
+++ b/tests/sys/kern/execve/good_aout.c
@@ -0,0 +1,45 @@
+/* $NetBSD: goodaout.c,v 1.8 2003/07/26 19:38:49 salo Exp $ */
+
+/*-
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(void)
+{
+ printf("succeeded\n");
+ exit(0);
+}
diff --git a/tests/sys/kern/execve/good_script b/tests/sys/kern/execve/good_script
new file mode 100644
index 0000000..11c7689
--- /dev/null
+++ b/tests/sys/kern/execve/good_script
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/non_exist_shell b/tests/sys/kern/execve/non_exist_shell
new file mode 100644
index 0000000..f9ee705
--- /dev/null
+++ b/tests/sys/kern/execve/non_exist_shell
@@ -0,0 +1,4 @@
+#! /foo/bar/baz
+# $FreeBSD$
+
+echo foo
diff --git a/tests/sys/kern/execve/script_arg b/tests/sys/kern/execve/script_arg
new file mode 100644
index 0000000..2700f1c
--- /dev/null
+++ b/tests/sys/kern/execve/script_arg
@@ -0,0 +1,4 @@
+#! /bin/sh -x
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/script_arg_nospace b/tests/sys/kern/execve/script_arg_nospace
new file mode 100644
index 0000000..6731ad5
--- /dev/null
+++ b/tests/sys/kern/execve/script_arg_nospace
@@ -0,0 +1,4 @@
+#!/bin/sh -x
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kqueue/Makefile b/tests/sys/kqueue/Makefile
new file mode 100644
index 0000000..43277ca
--- /dev/null
+++ b/tests/sys/kqueue/Makefile
@@ -0,0 +1,26 @@
+# $FreeBSD$
+#
+# svn://mark.heily.com/libkqueue/trunk/test
+# Last update: r114
+#
+# libkqueue and test suite by Mark Heily <mark@heily.com>
+#
+
+TAP_TESTS_SH= kqueue_test
+
+TESTSDIR= ${TESTSBASE}/sys/kqueue
+BINDIR= ${TESTSDIR}
+
+PROGS= kqtest
+
+SRCS.kqtest= \
+ main.c \
+ read.c \
+ timer.c \
+ vnode.c \
+ proc.c \
+ signal.c \
+ user.c
+WARNS?= 2
+
+.include <bsd.test.mk>
diff --git a/tests/sys/kqueue/common.h b/tests/sys/kqueue/common.h
new file mode 100644
index 0000000..aada778
--- /dev/null
+++ b/tests/sys/kqueue/common.h
@@ -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 */
diff --git a/tests/sys/kqueue/config.h b/tests/sys/kqueue/config.h
new file mode 100644
index 0000000..a204092
--- /dev/null
+++ b/tests/sys/kqueue/config.h
@@ -0,0 +1,13 @@
+/* $FreeBSD$ */
+
+#define HAVE_ERR_H 1
+#define HAVE_SYS_EVENT_H 1
+#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"
diff --git a/tests/sys/kqueue/kqueue_test.sh b/tests/sys/kqueue/kqueue_test.sh
new file mode 100755
index 0000000..62a7e23
--- /dev/null
+++ b/tests/sys/kqueue/kqueue_test.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+cd $(dirname $0)
+i=1
+./kqtest | while read line; do
+ echo $line | grep -q passed
+ if [ $? -eq 0 ]; then
+ echo "ok - $i $line"
+ : $(( i += 1 ))
+ fi
+
+ echo $line | grep -q 'tests completed'
+ if [ $? -eq 0 ]; then
+ echo -n "1.."
+ echo $line | cut -d' ' -f3
+ fi
+done
diff --git a/tests/sys/kqueue/main.c b/tests/sys/kqueue/main.c
new file mode 100644
index 0000000..f76c4e2
--- /dev/null
+++ b/tests/sys/kqueue/main.c
@@ -0,0 +1,284 @@
+/*
+ * 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 "config.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 = 1;
+ int test_socket = 1;
+ int test_signal = 1;
+ int test_vnode = 1;
+ int test_timer = 1;
+#ifdef __FreeBSD__
+ int test_user = 1;
+#else
+ /* XXX-FIXME temporary */
+ int test_user = 0;
+#endif
+
+ 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);
+}
diff --git a/tests/sys/kqueue/proc.c b/tests/sys/kqueue/proc.c
new file mode 100644
index 0000000..6288ee6
--- /dev/null
+++ b/tests/sys/kqueue/proc.c
@@ -0,0 +1,255 @@
+/*
+ * 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/stat.h>
+
+#include <err.h>
+
+#include "config.h"
+#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) {
+ struct stat s;
+ if (fstat(kqfd, &s) != -1)
+ errx(1, "kqueue inherited across fork! (%s() at %s:%d)",
+ __func__, __FILE__, __LINE__);
+
+ 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)");
+
+ sleep(1);
+ 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();
+
+}
+
+#ifdef TODO
+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();
+}
+
+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();
+
+#if TODO
+ event_trigger();
+#endif
+
+ 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);
+}
diff --git a/tests/sys/kqueue/read.c b/tests/sys/kqueue/read.c
new file mode 100644
index 0000000..cc65427
--- /dev/null
+++ b/tests/sys/kqueue/read.c
@@ -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);
+}
diff --git a/tests/sys/kqueue/signal.c b/tests/sys/kqueue/signal.c
new file mode 100644
index 0000000..14e751d
--- /dev/null
+++ b/tests/sys/kqueue/signal.c
@@ -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)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ADD)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_signal_get(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, wait)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 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));
+
+ success();
+}
+
+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(), SIGUSR1) < 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();
+}
+
+void
+test_evfilt_signal()
+{
+ kqfd = kqueue();
+ test_kevent_signal_add();
+ test_kevent_signal_del();
+ test_kevent_signal_get();
+ test_kevent_signal_disable();
+ test_kevent_signal_enable();
+ test_kevent_signal_oneshot();
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/timer.c b/tests/sys/kqueue/timer.c
new file mode 100644
index 0000000..766125d
--- /dev/null
+++ b/tests/sys/kqueue/timer.c
@@ -0,0 +1,178 @@
+/*
+ * 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_timer_add(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_timer_del(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_kevent_timer_get(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, wait)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kev.flags |= EV_CLEAR;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+static void
+test_oneshot(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Retrieve the event */
+ kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Check if the event occurs again */
+ sleep(3);
+ test_no_kevents();
+
+
+ success();
+}
+
+static void
+test_periodic(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, periodic)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Retrieve the event */
+ kev.flags = EV_ADD | EV_CLEAR;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Check if the event occurs again */
+ sleep(1);
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Delete the event */
+ kev.flags = EV_DELETE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+static void
+disable_and_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ /* Add the watch and immediately disable it */
+ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ kev.flags = EV_DISABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ test_no_kevents();
+
+ /* Re-enable and check again */
+ kev.flags = EV_ENABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ success();
+}
+
+void
+test_evfilt_timer()
+{
+ kqfd = kqueue();
+ test_kevent_timer_add();
+ test_kevent_timer_del();
+ test_kevent_timer_get();
+ test_oneshot();
+ test_periodic();
+ disable_and_enable();
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/user.c b/tests/sys/kqueue/user.c
new file mode 100644
index 0000000..9ba25f9
--- /dev/null
+++ b/tests/sys/kqueue/user.c
@@ -0,0 +1,129 @@
+/*
+ * 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;
+
+static void
+add_and_delete(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, EV_ADD and EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
+ test_no_kevents();
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
+ test_no_kevents();
+
+ success();
+}
+
+static void
+event_wait(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, wait)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ /* 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);
+
+ kev.fflags &= ~NOTE_FFCTRLMASK;
+ kev.fflags &= ~NOTE_TRIGGER;
+ kev.flags = EV_CLEAR;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ test_no_kevents();
+
+ success();
+}
+
+static void
+disable_and_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, EV_DISABLE and EV_ENABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
+ kevent_add(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();
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ENABLE, 0, 0, NULL);
+ kevent_add(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));
+
+ success();
+}
+
+static void
+oneshot(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, EV_ONESHOT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ kevent_add(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);
+
+ kev.flags = EV_ONESHOT;
+ kev.fflags &= ~NOTE_FFCTRLMASK;
+ kev.fflags &= ~NOTE_TRIGGER;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_evfilt_user()
+{
+ kqfd = kqueue();
+
+ add_and_delete();
+ event_wait();
+ disable_and_enable();
+ oneshot();
+ /* TODO: try different fflags operations */
+
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/vnode.c b/tests/sys/kqueue/vnode.c
new file mode 100644
index 0000000..dfa0b5e
--- /dev/null
+++ b/tests/sys/kqueue/vnode.c
@@ -0,0 +1,266 @@
+/*
+ * 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 vnode_fd;
+
+void
+test_kevent_vnode_add(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)";
+ const char *testfile = "/tmp/kqueue-test.tmp";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ system("touch /tmp/kqueue-test.tmp");
+ vnode_fd = open(testfile, O_RDONLY);
+ if (vnode_fd < 0)
+ err(1, "open of %s", testfile);
+ else
+ printf("vnode_fd = %d\n", vnode_fd);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD,
+ NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_vnode_note_delete(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (unlink("/tmp/kqueue-test.tmp") < 0)
+ err(1, "unlink");
+
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ success();
+}
+
+void
+test_kevent_vnode_note_write(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("echo hello >> /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ /* 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));
+
+ success();
+}
+
+void
+test_kevent_vnode_note_attrib(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != 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);
+
+ success();
+}
+
+void
+test_kevent_vnode_note_rename(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("mv /tmp/kqueue-test.tmp /tmp/kqueue-test2.tmp") < 0)
+ err(1, "system");
+
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != 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);
+
+ if (system("mv /tmp/kqueue-test2.tmp /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ success();
+}
+
+void
+test_kevent_vnode_del(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_vnode_disable_and_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ /* Add the watch and immediately disable it */
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ kev.flags = EV_DISABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Confirm that the watch is disabled */
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+ test_no_kevents();
+
+ /* Re-enable and check again */
+ kev.flags = EV_ENABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != 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);
+
+ success();
+}
+
+#if HAVE_EV_DISPATCH
+void
+test_kevent_vnode_dispatch(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != 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 */
+ puts("-- checking that watch is disabled");
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+ test_no_kevents();
+
+ /* Delete the watch */
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "remove watch failed: %s", test_id);
+
+ success();
+}
+#endif /* HAVE_EV_DISPATCH */
+
+void
+test_evfilt_vnode()
+{
+ kqfd = kqueue();
+ test_kevent_vnode_add();
+ test_kevent_vnode_del();
+ test_kevent_vnode_disable_and_enable();
+#if HAVE_EV_DISPATCH
+ test_kevent_vnode_dispatch();
+#endif
+ test_kevent_vnode_note_write();
+ test_kevent_vnode_note_attrib();
+ test_kevent_vnode_note_rename();
+ test_kevent_vnode_note_delete();
+ close(kqfd);
+}
OpenPOWER on IntegriCloud