svn commit: r305467 - in head: . etc/mtree tests/sys/kqueue tests/sys/kqueue/libkqueue

Ngie Cooper ngie at FreeBSD.org
Tue Sep 6 08:45:32 UTC 2016


Author: ngie
Date: Tue Sep  6 08:45:29 2016
New Revision: 305467
URL: https://svnweb.freebsd.org/changeset/base/305467

Log:
  Move tests/sys/kqueue/... to tests/sys/kqueue/libkqueue/...
  
  This is being done to clearly distinguish the libkqueue tests
  from the (soon to be imported) NetBSD tests.
  
  MFC after:	58 days
  Sponsored by:	EMC / Isilon Storage Division

Added:
  head/tests/sys/kqueue/libkqueue/
  head/tests/sys/kqueue/libkqueue/Makefile
     - copied, changed from r305466, head/tests/sys/kqueue/Makefile
  head/tests/sys/kqueue/libkqueue/Makefile.depend
     - copied unchanged from r305466, head/tests/sys/kqueue/Makefile.depend
  head/tests/sys/kqueue/libkqueue/common.h
     - copied unchanged from r305466, head/tests/sys/kqueue/common.h
  head/tests/sys/kqueue/libkqueue/config.h
     - copied unchanged from r305466, head/tests/sys/kqueue/config.h
  head/tests/sys/kqueue/libkqueue/kqueue_test.sh
     - copied unchanged from r305466, head/tests/sys/kqueue/kqueue_test.sh
  head/tests/sys/kqueue/libkqueue/main.c
     - copied unchanged from r305466, head/tests/sys/kqueue/main.c
  head/tests/sys/kqueue/libkqueue/proc.c
     - copied unchanged from r305466, head/tests/sys/kqueue/proc.c
  head/tests/sys/kqueue/libkqueue/read.c
     - copied unchanged from r305466, head/tests/sys/kqueue/read.c
  head/tests/sys/kqueue/libkqueue/signal.c
     - copied unchanged from r305466, head/tests/sys/kqueue/signal.c
  head/tests/sys/kqueue/libkqueue/timer.c
     - copied unchanged from r305466, head/tests/sys/kqueue/timer.c
  head/tests/sys/kqueue/libkqueue/user.c
     - copied unchanged from r305466, head/tests/sys/kqueue/user.c
  head/tests/sys/kqueue/libkqueue/vnode.c
     - copied unchanged from r305466, head/tests/sys/kqueue/vnode.c
Replaced:
  head/tests/sys/kqueue/Makefile   (contents, props changed)
Deleted:
  head/tests/sys/kqueue/Makefile.depend
  head/tests/sys/kqueue/common.h
  head/tests/sys/kqueue/config.h
  head/tests/sys/kqueue/kqueue_test.sh
  head/tests/sys/kqueue/main.c
  head/tests/sys/kqueue/proc.c
  head/tests/sys/kqueue/read.c
  head/tests/sys/kqueue/signal.c
  head/tests/sys/kqueue/timer.c
  head/tests/sys/kqueue/user.c
  head/tests/sys/kqueue/vnode.c
Modified:
  head/ObsoleteFiles.inc
  head/etc/mtree/BSD.tests.dist

Modified: head/ObsoleteFiles.inc
==============================================================================
--- head/ObsoleteFiles.inc	Tue Sep  6 08:14:56 2016	(r305466)
+++ head/ObsoleteFiles.inc	Tue Sep  6 08:45:29 2016	(r305467)
@@ -38,6 +38,9 @@
 #   xargs -n1 | sort | uniq -d;
 # done
 
+# 20160906: libkqueue tests moved to /usr/tests/sys/kqueue/libkqueue
+OLD_FILES+=usr/tests/sys/kqueue/kqtest
+OLD_FILES+=usr/tests/sys/kqueue/kqueue_test
 # 20160901: Remove digi(4)
 OLD_FILES+=usr/share/man/man4/digi.4.gz
 # 20160819: Remove ie(4)

Modified: head/etc/mtree/BSD.tests.dist
==============================================================================
--- head/etc/mtree/BSD.tests.dist	Tue Sep  6 08:14:56 2016	(r305466)
+++ head/etc/mtree/BSD.tests.dist	Tue Sep  6 08:45:29 2016	(r305467)
@@ -419,6 +419,8 @@
             ..
         ..
         kqueue
+            libkqueue
+            ..
         ..
         mac
             bsdextended

Added: head/tests/sys/kqueue/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/Makefile	Tue Sep  6 08:45:29 2016	(r305467)
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+TESTSDIR=	${TESTSBASE}/sys/kqueue
+BINDIR=		${TESTSDIR}
+
+TESTS_SUBDIRS+=	libkqueue
+
+.include <bsd.test.mk>

Copied and modified: head/tests/sys/kqueue/libkqueue/Makefile (from r305466, head/tests/sys/kqueue/Makefile)
==============================================================================
--- head/tests/sys/kqueue/Makefile	Tue Sep  6 08:14:56 2016	(r305466, copy source)
+++ head/tests/sys/kqueue/libkqueue/Makefile	Tue Sep  6 08:45:29 2016	(r305467)
@@ -1,16 +1,11 @@
 # $FreeBSD$
-#
-# svn://mark.heily.com/libkqueue/trunk/test
-# Last update: r114
-#
-# libkqueue and test suite by Mark Heily <mark at heily.com>
-#
-
-TAP_TESTS_SH=	kqueue_test
 
-TESTSDIR=	${TESTSBASE}/sys/kqueue
+TESTSDIR=	${TESTSBASE}/sys/kqueue/libkqueue
 BINDIR=		${TESTSDIR}
 
+# libkqueue and test suite by Mark Heily <mark at heily.com>
+TAP_TESTS_SH=	kqueue_test
+
 PROGS=	kqtest
 
 SRCS.kqtest=		\

Copied: head/tests/sys/kqueue/libkqueue/Makefile.depend (from r305466, head/tests/sys/kqueue/Makefile.depend)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/libkqueue/Makefile.depend	Tue Sep  6 08:45:29 2016	(r305467, copy of r305466, head/tests/sys/kqueue/Makefile.depend)
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+	gnu/lib/csu \
+	gnu/lib/libgcc \
+	include \
+	include/xlocale \
+	lib/${CSU_DIR} \
+	lib/libc \
+	lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif

Copied: head/tests/sys/kqueue/libkqueue/common.h (from r305466, head/tests/sys/kqueue/common.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/libkqueue/common.h	Tue Sep  6 08:45:29 2016	(r305467, copy of r305466, head/tests/sys/kqueue/common.h)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark at 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);
+struct kevent * kevent_get_timeout(int, 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 */

Copied: head/tests/sys/kqueue/libkqueue/config.h (from r305466, head/tests/sys/kqueue/config.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/libkqueue/config.h	Tue Sep  6 08:45:29 2016	(r305467, copy of r305466, head/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"

Copied: head/tests/sys/kqueue/libkqueue/kqueue_test.sh (from r305466, head/tests/sys/kqueue/kqueue_test.sh)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/libkqueue/kqueue_test.sh	Tue Sep  6 08:45:29 2016	(r305467, copy of r305466, head/tests/sys/kqueue/kqueue_test.sh)
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+i=1
+"$(dirname $0)/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

Copied: head/tests/sys/kqueue/libkqueue/main.c (from r305466, head/tests/sys/kqueue/main.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/libkqueue/main.c	Tue Sep  6 08:45:29 2016	(r305467, copy of r305466, head/tests/sys/kqueue/main.c)
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark at 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);
+}
+
+/* Retrieve a single kevent, specifying a maximum time to wait for it. */
+struct kevent *
+kevent_get_timeout(int kqfd, int seconds)
+{
+    int nfds;
+    struct kevent *kev;
+    struct timespec timeout = {seconds, 0};
+
+    if ((kev = calloc(1, sizeof(*kev))) == NULL)
+	err(1, "out of memory");
+    
+    nfds = kevent(kqfd, NULL, 0, kev, 1, &timeout);
+    if (nfds < 0) {
+        err(1, "kevent(2)");
+    } else if (nfds == 0) {
+        free(kev);
+        kev = NULL;
+    }
+
+    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_PROC) {
+        snprintf(buf, 1024, "fflags = %x (", kev->fflags);
+        KEVFFL_DUMP(NOTE_EXIT);
+        KEVFFL_DUMP(NOTE_FORK);
+        KEVFFL_DUMP(NOTE_EXEC);
+        KEVFFL_DUMP(NOTE_CHILD);
+        KEVFFL_DUMP(NOTE_TRACKERR);
+        KEVFFL_DUMP(NOTE_TRACK);
+        buf[strlen(buf) - 1] = ')';
+    } else if (kev->filter == EVFILT_PROCDESC) {
+        snprintf(buf, 1024, "fflags = %x (", kev->fflags);
+        KEVFFL_DUMP(NOTE_EXIT);
+        KEVFFL_DUMP(NOTE_FORK);
+        KEVFFL_DUMP(NOTE_EXEC);
+        buf[strlen(buf) - 1] = ')';
+    } else if (kev->filter == EVFILT_VNODE) {
+        snprintf(buf, 1024, "fflags = %x (", 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] = ')';
+    } else {
+    	snprintf(buf, 1024, "fflags = %x", kev->fflags);
+    }
+
+    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--;
+    }
+
+    /*
+     * Some tests fork.  If output is fully buffered,
+     * the children inherit some buffered data and flush
+     * it when they exit, causing some data to be printed twice.
+     * Use line buffering to avoid this problem.
+     */
+    setlinebuf(stdout);
+    setlinebuf(stderr);
+
+    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);
+}

Copied: head/tests/sys/kqueue/libkqueue/proc.c (from r305466, head/tests/sys/kqueue/proc.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/libkqueue/proc.c	Tue Sep  6 08:45:29 2016	(r305467, copy of r305466, head/tests/sys/kqueue/proc.c)
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark at 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();
+
+}
+
+static void
+proc_track(int sleep_time)
+{
+    char test_id[64];
+    struct kevent kev;
+    pid_t pid;
+    int pipe_fd[2];
+    ssize_t result;
+
+    snprintf(test_id, sizeof(test_id),
+             "kevent(EVFILT_PROC, NOTE_TRACK); sleep %d", sleep_time);
+    test_begin(test_id);
+    test_no_kevents();
+
+    if (pipe(pipe_fd)) {
+        err(1, "pipe (parent) failed! (%s() at %s:%d)",
+            __func__, __FILE__, __LINE__);
+    }
+
+    /* Create a child to track. */
+    pid = fork();
+    if (pid == 0) { /* Child */
+        pid_t grandchild = -1;
+
+        /*
+         * Give the parent a chance to start tracking us.
+         */
+        result = read(pipe_fd[1], test_id, 1);
+        if (result != 1) {
+            err(1, "read from pipe in child failed! (ret %zd) (%s() at %s:%d)",
+                result, __func__, __FILE__, __LINE__);
+        }
+
+        /*
+         * Spawn a grandchild that will immediately exit. If the kernel has bug
+         * 180385, the parent will see a kevent with both NOTE_CHILD and
+         * NOTE_EXIT. If that bug is fixed, it will see two separate kevents
+         * for those notes. Note that this triggers the conditions for
+         * detecting the bug quite reliably on a 1 CPU system (or if the test
+         * process is restricted to a single CPU), but may not trigger it on a
+         * multi-CPU system.
+         */
+        grandchild = fork();
+        if (grandchild == 0) { /* Grandchild */
+            if (sleep_time) sleep(sleep_time);
+            exit(1);
+        } else if (grandchild == -1) { /* Error */
+            err(1, "fork (grandchild) failed! (%s() at %s:%d)",
+                __func__, __FILE__, __LINE__);
+        } else { /* Child (Grandchild Parent) */
+            printf(" -- grandchild created (pid %d)\n", (int) grandchild);
+        }
+        if (sleep_time) sleep(sleep_time);
+        exit(0);
+    } else if (pid == -1) { /* Error */
+        err(1, "fork (child) failed! (%s() at %s:%d)",
+            __func__, __FILE__, __LINE__);
+    }
+    
+    printf(" -- child created (pid %d)\n", (int) pid);
+
+    kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD | EV_ENABLE,
+               NOTE_TRACK | NOTE_EXEC | NOTE_EXIT | NOTE_FORK,
+               0, NULL);
+
+    printf(" -- tracking child (pid %d)\n", (int) pid);
+
+    /* Now that we're tracking the child, tell it to proceed. */
+    result = write(pipe_fd[0], test_id, 1);
+    if (result != 1) {
+        err(1, "write to pipe in parent failed! (ret %zd) (%s() at %s:%d)",
+            result, __func__, __FILE__, __LINE__);
+    }
+
+    /*
+     * Several events should be received:
+     *  - NOTE_FORK (from child)
+     *  - NOTE_CHILD (from grandchild)
+     *  - NOTE_EXIT (from grandchild)
+     *  - NOTE_EXIT (from child)
+     *
+     * The NOTE_FORK and NOTE_EXIT from the child could be combined into a
+     * single event, but the NOTE_CHILD and NOTE_EXIT from the grandchild must
+     * not be combined.
+     *
+     * The loop continues until no events are received within a 5 second
+     * period, at which point it is assumed that no more will be coming. The
+     * loop is deliberately designed to attempt to get events even after all
+     * the expected ones are received in case some spurious events are
+     * generated as well as the expected ones.
+     */
+    {
+        int child_exit = 0;
+        int child_fork = 0;
+        int gchild_exit = 0;
+        int gchild_note = 0;
+        pid_t gchild_pid = -1;
+        int done = 0;
+        
+        while (!done)
+        {
+            int handled = 0;
+            struct kevent *kevp;
+
+            kevp = kevent_get_timeout(kqfd, 5);
+            if (kevp == NULL) {
+                done = 1;
+            } else {
+                printf(" -- Received kevent: %s\n", kevent_to_str(kevp));
+            
+                if ((kevp->fflags & NOTE_CHILD) && (kevp->fflags & NOTE_EXIT)) {
+                    errx(1, "NOTE_CHILD and NOTE_EXIT in same kevent: %s", kevent_to_str(kevp));
+                }
+            
+                if (kevp->fflags & NOTE_CHILD) {
+                    if (kevp->data == pid) {
+                        if (!gchild_note) {
+                            ++gchild_note;
+                            gchild_pid = kevp->ident;
+                            ++handled;
+                        } else {
+                            errx(1, "Spurious NOTE_CHILD: %s", kevent_to_str(kevp));
+                        }
+                    }
+                }
+
+                if (kevp->fflags & NOTE_EXIT) {
+                    if ((kevp->ident == pid) && (!child_exit)) {
+                        ++child_exit;
+                        ++handled;
+                    } else if ((kevp->ident == gchild_pid) && (!gchild_exit)) {
+                        ++gchild_exit;
+                        ++handled;
+                    } else {
+                        errx(1, "Spurious NOTE_EXIT: %s", kevent_to_str(kevp));
+                    }
+                }
+
+                if (kevp->fflags & NOTE_FORK) {
+                    if ((kevp->ident == pid) && (!child_fork)) {
+                        ++child_fork;
+                        ++handled;
+                    } else {
+                        errx(1, "Spurious NOTE_FORK: %s", kevent_to_str(kevp));
+                    }
+                }
+
+                if (!handled) {
+                    errx(1, "Spurious kevent: %s", kevent_to_str(kevp));
+                }
+
+                free(kevp);
+            }
+        }
+        
+        /* Make sure all expected events were received. */
+        if (child_exit && child_fork && gchild_exit && gchild_note) {
+            printf(" -- Received all expected events.\n");
+        } else {
+            errx(1, "Did not receive all expected events.");
+        }
+    }
+
+    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();
+    proc_track(0); /* Run without sleeping before children exit. */
+    proc_track(1); /* Sleep a bit in the children before exiting. */
+
+#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);
+}

Copied: head/tests/sys/kqueue/libkqueue/read.c (from r305466, head/tests/sys/kqueue/read.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/kqueue/libkqueue/read.c	Tue Sep  6 08:45:29 2016	(r305467, copy of r305466, head/tests/sys/kqueue/read.c)
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark at 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)");
+}
+
+

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


More information about the svn-src-head mailing list