Module Name:    src
Committed By:   yamaguchi
Date:           Thu Sep 30 02:00:20 UTC 2021

Modified Files:
        src/distrib/sets/lists/base: shl.mi
        src/distrib/sets/lists/comp: mi
        src/distrib/sets/lists/debug: mi shl.mi
        src/distrib/sets/lists/tests: mi
        src/sys/rump/kern: Makefile.rumpkerncomp
        src/tests/kernel: Makefile
Added Files:
        src/sys/rump/kern/lib/libsimplehook_tester: Makefile
            simplehook_tester.c
        src/tests/kernel: t_simplehook.sh

Log Message:
Added tests for the linear hook APIs


To generate a diff of this commit:
cvs rdiff -u -r1.927 -r1.928 src/distrib/sets/lists/base/shl.mi
cvs rdiff -u -r1.2394 -r1.2395 src/distrib/sets/lists/comp/mi
cvs rdiff -u -r1.361 -r1.362 src/distrib/sets/lists/debug/mi
cvs rdiff -u -r1.284 -r1.285 src/distrib/sets/lists/debug/shl.mi
cvs rdiff -u -r1.1130 -r1.1131 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.13 -r1.14 src/sys/rump/kern/Makefile.rumpkerncomp
cvs rdiff -u -r0 -r1.1 src/sys/rump/kern/lib/libsimplehook_tester/Makefile \
    src/sys/rump/kern/lib/libsimplehook_tester/simplehook_tester.c
cvs rdiff -u -r1.68 -r1.69 src/tests/kernel/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/kernel/t_simplehook.sh

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/base/shl.mi
diff -u src/distrib/sets/lists/base/shl.mi:1.927 src/distrib/sets/lists/base/shl.mi:1.928
--- src/distrib/sets/lists/base/shl.mi:1.927	Fri Sep 24 13:13:07 2021
+++ src/distrib/sets/lists/base/shl.mi	Thu Sep 30 02:00:19 2021
@@ -1,4 +1,4 @@
-# $NetBSD: shl.mi,v 1.927 2021/09/24 13:13:07 christos Exp $
+# $NetBSD: shl.mi,v 1.928 2021/09/30 02:00:19 yamaguchi Exp $
 #
 # Note:	Don't delete entries from here - mark them as "obsolete" instead,
 #	unless otherwise stated below.
@@ -741,6 +741,9 @@
 ./usr/lib/librumpkern_nv.so			base-rump-shlib		rump
 ./usr/lib/librumpkern_nv.so.0			base-rump-shlib		rump
 ./usr/lib/librumpkern_nv.so.0.0			base-rump-shlib		rump
+./usr/lib/librumpkern_simplehook_tester.so	base-rump-shlib		rump
+./usr/lib/librumpkern_simplehook_tester.so.0	base-rump-shlib		rump
+./usr/lib/librumpkern_simplehook_tester.so.0.0	base-rump-shlib		rump
 ./usr/lib/librumpkern_sljit.so			base-rump-shlib		rump,sljit
 ./usr/lib/librumpkern_sljit.so.0		base-rump-shlib		rump,sljit
 ./usr/lib/librumpkern_sljit.so.0.0		base-rump-shlib		rump,sljit

Index: src/distrib/sets/lists/comp/mi
diff -u src/distrib/sets/lists/comp/mi:1.2394 src/distrib/sets/lists/comp/mi:1.2395
--- src/distrib/sets/lists/comp/mi:1.2394	Thu Sep 30 01:26:07 2021
+++ src/distrib/sets/lists/comp/mi	Thu Sep 30 02:00:19 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: mi,v 1.2394 2021/09/30 01:26:07 yamaguchi Exp $
+#	$NetBSD: mi,v 1.2395 2021/09/30 02:00:19 yamaguchi Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 ./etc/mtree/set.comp				comp-sys-root
@@ -4062,6 +4062,8 @@
 ./usr/lib/librumpkern_ksem_p.a			comp-obsolete		obsolete
 ./usr/lib/librumpkern_nv.a			comp-c-lib		rump
 ./usr/lib/librumpkern_nv_p.a			comp-c-proflib		rump,profile
+./usr/lib/librumpkern_simplehook_tester.a	comp-c-lib		rump
+./usr/lib/librumpkern_simplehook_tester_p.a	comp-c-proflib		rump,profile
 ./usr/lib/librumpkern_sljit.a			comp-c-lib		rump,sljit
 ./usr/lib/librumpkern_sljit_p.a			comp-c-proflib		rump,sljit,profile
 ./usr/lib/librumpkern_solaris.a			comp-c-lib		rump,zfs

Index: src/distrib/sets/lists/debug/mi
diff -u src/distrib/sets/lists/debug/mi:1.361 src/distrib/sets/lists/debug/mi:1.362
--- src/distrib/sets/lists/debug/mi:1.361	Sun Sep 19 15:51:28 2021
+++ src/distrib/sets/lists/debug/mi	Thu Sep 30 02:00:19 2021
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.361 2021/09/19 15:51:28 thorpej Exp $
+# $NetBSD: mi,v 1.362 2021/09/30 02:00:19 yamaguchi Exp $
 ./etc/mtree/set.debug                           comp-sys-root
 ./usr/lib					comp-sys-usr		compatdir
 ./usr/lib/i18n/libBIG5_g.a			comp-c-debuglib		debuglib,compatfile
@@ -208,6 +208,7 @@
 ./usr/lib/librumpkern_crypto_g.a		comp-c-debuglib		debuglib,rump
 ./usr/lib/librumpkern_ksem_g.a			comp-obsolete		obsolete,compatfile
 ./usr/lib/librumpkern_nv_g.a			comp-c-debuglib		debuglib,rump
+./usr/lib/librumpkern_simplehook_tester_g.a	comp-c-debuglib		debuglib,rump
 ./usr/lib/librumpkern_sljit_g.a			comp-c-debuglib		debuglib,rump,sljit
 ./usr/lib/librumpkern_solaris_g.a		comp-c-debuglib		debuglib,rump,zfs
 ./usr/lib/librumpkern_sysproxy_g.a		comp-c-debuglib		debuglib,rump

Index: src/distrib/sets/lists/debug/shl.mi
diff -u src/distrib/sets/lists/debug/shl.mi:1.284 src/distrib/sets/lists/debug/shl.mi:1.285
--- src/distrib/sets/lists/debug/shl.mi:1.284	Fri Sep 24 13:13:07 2021
+++ src/distrib/sets/lists/debug/shl.mi	Thu Sep 30 02:00:19 2021
@@ -1,4 +1,4 @@
-# $NetBSD: shl.mi,v 1.284 2021/09/24 13:13:07 christos Exp $
+# $NetBSD: shl.mi,v 1.285 2021/09/30 02:00:19 yamaguchi Exp $
 ./usr/lib/libbfd_g.a						comp-c-debuglib	debuglib,compatfile,binutils
 ./usr/libdata/debug/lib						base-sys-usr	debug,dynamicroot,compatdir
 ./usr/libdata/debug/lib/libavl.so.0.0.debug			comp-zfs-debug	debug,dynamicroot,zfs
@@ -261,6 +261,7 @@
 ./usr/libdata/debug/usr/lib/librumpkern_crypto.so.0.0.debug	comp-rump-debug	debug,rump
 ./usr/libdata/debug/usr/lib/librumpkern_ksem.so.0.0.debug	comp-obsolete	obsolete,compatfile
 ./usr/libdata/debug/usr/lib/librumpkern_nv.so.0.0.debug		comp-rump-debug	debug,rump
+./usr/libdata/debug/usr/lib/librumpkern_simplehook_tester.so.0.0.debug	comp-rump-debug	debug,rump
 ./usr/libdata/debug/usr/lib/librumpkern_sljit.so.0.0.debug	comp-rump-debug	debug,rump,sljit
 ./usr/libdata/debug/usr/lib/librumpkern_solaris.so.0.0.debug	comp-rump-debug	debug,rump,zfs
 ./usr/libdata/debug/usr/lib/librumpkern_sysproxy.so.0.0.debug	comp-rump-debug	debug,rump

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.1130 src/distrib/sets/lists/tests/mi:1.1131
--- src/distrib/sets/lists/tests/mi:1.1130	Sun Sep 26 03:17:59 2021
+++ src/distrib/sets/lists/tests/mi	Thu Sep 30 02:00:19 2021
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1130 2021/09/26 03:17:59 rillig Exp $
+# $NetBSD: mi,v 1.1131 2021/09/30 02:00:19 yamaguchi Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -2237,6 +2237,7 @@
 ./usr/tests/kernel/t_pty				tests-kernel-tests	compattestfile,atf
 ./usr/tests/kernel/t_rnd				tests-kernel-tests	atf,rump
 ./usr/tests/kernel/t_sigaction				tests-obsolete		obsolete
+./usr/tests/kernel/t_simplehook				tests-kernel-tests	atf,rump
 ./usr/tests/kernel/t_subr_prf				tests-kernel-tests	compattestfile,atf
 ./usr/tests/kernel/t_sysctl				tests-kernel-tests	compattestfile,atf
 ./usr/tests/kernel/t_sysv				tests-kernel-tests	compattestfile,atf

Index: src/sys/rump/kern/Makefile.rumpkerncomp
diff -u src/sys/rump/kern/Makefile.rumpkerncomp:1.13 src/sys/rump/kern/Makefile.rumpkerncomp:1.14
--- src/sys/rump/kern/Makefile.rumpkerncomp:1.13	Sat Sep 22 12:54:34 2018
+++ src/sys/rump/kern/Makefile.rumpkerncomp	Thu Sep 30 02:00:20 2021
@@ -1,9 +1,9 @@
-#	$NetBSD: Makefile.rumpkerncomp,v 1.13 2018/09/22 12:54:34 rmind Exp $
+#	$NetBSD: Makefile.rumpkerncomp,v 1.14 2021/09/30 02:00:20 yamaguchi Exp $
 #
 
 .include <bsd.own.mk>
 
-RUMPKERNCOMPS=	crypto nv sysproxy tty z
+RUMPKERNCOMPS=	crypto nv sysproxy tty z simplehook_tester
 RUMPSYSEMUS=	sys_cygwin sys_linux sys_sunos
 
 .if make(rumpdescribe)

Index: src/tests/kernel/Makefile
diff -u src/tests/kernel/Makefile:1.68 src/tests/kernel/Makefile:1.69
--- src/tests/kernel/Makefile:1.68	Wed Jul  1 13:49:26 2020
+++ src/tests/kernel/Makefile	Thu Sep 30 02:00:20 2021
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.68 2020/07/01 13:49:26 jruoho Exp $
+# $NetBSD: Makefile,v 1.69 2021/09/30 02:00:20 yamaguchi Exp $
 
 NOMAN=		# defined
 
@@ -32,6 +32,7 @@ TESTS_SH+=	t_origin
 TESTS_SH+=	t_procpath
 TESTS_SH+=	t_fexecve
 TESTS_SH+=	t_fpufork
+TESTS_SH+=	t_simplehook
 
 BINDIR=		${TESTSDIR}
 PROGS=		h_fexecve

Added files:

Index: src/sys/rump/kern/lib/libsimplehook_tester/Makefile
diff -u /dev/null src/sys/rump/kern/lib/libsimplehook_tester/Makefile:1.1
--- /dev/null	Thu Sep 30 02:00:20 2021
+++ src/sys/rump/kern/lib/libsimplehook_tester/Makefile	Thu Sep 30 02:00:20 2021
@@ -0,0 +1,13 @@
+
+
+LIB=	rumpkern_simplehook_tester
+COMMENT=Tester for simplehook
+
+SRCS=	simplehook_tester.c
+
+.ifdef RUMP_DEBUG
+CPPFLAGS.simplehook_tester.c+=	-DSIMPLEHOOK_TESTER_DEBUG
+.endif
+
+.include <bsd.lib.mk>
+.include <bsd.klinks.mk>
Index: src/sys/rump/kern/lib/libsimplehook_tester/simplehook_tester.c
diff -u /dev/null src/sys/rump/kern/lib/libsimplehook_tester/simplehook_tester.c:1.1
--- /dev/null	Thu Sep 30 02:00:20 2021
+++ src/sys/rump/kern/lib/libsimplehook_tester/simplehook_tester.c	Thu Sep 30 02:00:20 2021
@@ -0,0 +1,724 @@
+/*	$NetBSD: simplehook_tester.c,v 1.1 2021/09/30 02:00:20 yamaguchi Exp $	*/
+/*
+ * Copyright (c) 2021 Internet Initiative Japan Inc.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: simplehook_tester.c,v 1.1 2021/09/30 02:00:20 yamaguchi Exp $");
+
+#include <sys/param.h>
+
+#include <sys/condvar.h>
+#include <sys/hook.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/workqueue.h>
+
+#ifdef SIMPLEHOOK_TESTER_DEBUG
+#define HK_DPRINTF(a)	printf a
+#else
+#define HK_DPRINTF(a)	__nothing
+#endif
+
+MODULE(MODULE_CLASS_MISC, simplehook_tester, NULL);
+extern int simplehook_tester_init(void);
+struct tester_context;
+
+struct tester_hook {
+	struct tester_context	*th_ctx;
+	khook_t			*th_hook;
+	size_t			 th_idx;
+	int			 th_count;
+	bool			 th_stopping;
+	bool			 th_stopped;
+	bool			 th_disestablish;
+};
+
+static struct tester_context {
+	kmutex_t		 ctx_mutex;
+	kcondvar_t		 ctx_cv;
+	struct sysctllog	*ctx_sysctllog;
+	struct workqueue	*ctx_wq;
+	struct work		 ctx_wk;
+	bool			 ctx_wk_enqueued;
+	bool			 ctx_wk_waiting;
+
+	khook_list_t		*ctx_hooks;
+	struct tester_hook	 ctx_hook[2];
+
+	khook_t			*ctx_nbhook;
+} tester_ctx;
+
+static int
+simplehook_tester_created(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	int error, val;
+	size_t i;
+
+	node = *rnode;
+	ctx = node.sysctl_data;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = ctx->ctx_hooks != NULL ? 1 : 0;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (val != 0 && val != 1)
+		return EINVAL;
+
+	error = 0;
+	mutex_enter(&ctx->ctx_mutex);
+	if (val == 1) {
+		if (ctx->ctx_hooks != NULL) {
+			error = EEXIST;
+		} else {
+			HK_DPRINTF(("[%s, %d]: create hook list\n",
+			    __func__, __LINE__));
+			ctx->ctx_hooks = simplehook_create(IPL_NONE,
+			    "tester hooks");
+			KASSERT(ctx->ctx_hooks != NULL);
+		}
+	} else {
+		if (ctx->ctx_hooks == NULL) {
+			error = ENXIO;
+		} else if (ctx->ctx_wk_waiting) {
+			error = EBUSY;
+		} else {
+			ctx->ctx_wk_waiting = true;
+			mutex_exit(&ctx->ctx_mutex);
+
+			workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
+
+			mutex_enter(&ctx->ctx_mutex);
+			ctx->ctx_wk_waiting = false;
+
+			HK_DPRINTF(("[%s, %d]: destroy hook list\n",
+			    __func__, __LINE__));
+			simplehook_destroy(ctx->ctx_hooks);
+			ctx->ctx_hooks = NULL;
+			ctx->ctx_nbhook = NULL;
+			for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
+				ctx->ctx_hook[i].th_hook = NULL;
+			}
+		}
+	}
+	mutex_exit(&ctx->ctx_mutex);
+
+	return error;
+}
+
+static void
+simplehook_tester_work(struct work *wk, void *xctx)
+{
+	struct tester_context *ctx;
+
+	ctx = xctx;
+
+	mutex_enter(&ctx->ctx_mutex);
+	ctx->ctx_wk_enqueued = false;
+	mutex_exit(&ctx->ctx_mutex);
+
+	simplehook_dohooks(ctx->ctx_hooks);
+}
+
+static int
+simplehook_tester_dohooks(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	int error, val;
+
+	node = *rnode;
+	ctx = node.sysctl_data;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = ctx->ctx_wk_enqueued ? 1 : 0;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (val != 0 && val != 1)
+		return EINVAL;
+
+	mutex_enter(&ctx->ctx_mutex);
+	if (val == 1) {
+		if (ctx->ctx_wk_enqueued) {
+			error = EEXIST;
+		} else if (ctx->ctx_wk_waiting) {
+			error = EBUSY;
+		} else if (ctx->ctx_hooks == NULL) {
+			error = ENXIO;
+		} else {
+			HK_DPRINTF(("[%s, %d]: dohook\n", __func__, __LINE__));
+			ctx->ctx_wk_enqueued = true;
+			workqueue_enqueue(ctx->ctx_wq,
+			    &ctx->ctx_wk, NULL);
+		}
+	} else {
+		if (ctx->ctx_wk_waiting) {
+			error = EBUSY;
+		} else {
+			ctx->ctx_wk_waiting = true;
+			mutex_exit(&ctx->ctx_mutex);
+
+			workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
+
+			mutex_enter(&ctx->ctx_mutex);
+			ctx->ctx_wk_waiting = false;
+		}
+	}
+	mutex_exit(&ctx->ctx_mutex);
+
+	return error;
+}
+
+static void
+simplehook_tester_hook(void *xth)
+{
+	struct tester_context *ctx;
+	struct tester_hook *th;
+
+	th = xth;
+	ctx = th->th_ctx;
+	mutex_enter(&ctx->ctx_mutex);
+
+	HK_DPRINTF(("[%s, %d]: hook%zu called\n",
+	    __func__, __LINE__, th->th_idx));
+
+	th->th_stopped = false;
+
+	while (th->th_stopping) {
+		HK_DPRINTF(("[%s, %d]: hook%zu stopping\n",
+		    __func__, __LINE__, th->th_idx));
+		th->th_stopped = true;
+		cv_wait(&ctx->ctx_cv, &ctx->ctx_mutex);
+	}
+
+	if (th->th_stopped) {
+		HK_DPRINTF(("[%s, %d]: hook%zu restart\n",
+		    __func__, __LINE__, th->th_idx));
+		th->th_stopped = false;
+	}
+
+	th->th_count++;
+
+	if (th->th_disestablish && th->th_hook != NULL) {
+		HK_DPRINTF(("[%s, %d]: disestablish runing hook%zu\n",
+		    __func__, __LINE__, th->th_idx));
+		simplehook_disestablish(ctx->ctx_hooks,
+		    th->th_hook, &ctx->ctx_mutex);
+		th->th_hook = NULL;
+	}
+
+	HK_DPRINTF(("[%s, %d]: hook%zu exit\n",
+	    __func__, __LINE__, th->th_idx));
+
+	mutex_exit(&ctx->ctx_mutex);
+}
+
+static void
+simplehook_tester_hook_nb(void *xctx)
+{
+
+	HK_DPRINTF(("[%s, %d]: non-block hook called\n",
+	    __func__, __LINE__));
+
+	HK_DPRINTF(("[%s, %d]: sleep 1 sec\n",
+	    __func__, __LINE__));
+	kpause("smplhk_nb", true, 1 * hz, NULL);
+
+	HK_DPRINTF(("[%s, %d]: non-block hook exit\n",
+	    __func__, __LINE__));
+}
+
+static int
+simplehook_tester_established(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	struct tester_hook *th;
+	int val, error;
+
+	node = *rnode;
+	th = node.sysctl_data;
+	ctx = th->th_ctx;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = th->th_hook == NULL ? 0 : 1;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	error = 0;
+	mutex_enter(&ctx->ctx_mutex);
+
+	if (val == 1) {
+		if (th->th_hook != NULL) {
+			error = EEXIST;
+		} else {
+			th->th_hook = simplehook_establish(ctx->ctx_hooks,
+			    simplehook_tester_hook, th);
+			KASSERT(th->th_hook != NULL);
+			HK_DPRINTF(("[%s, %d]: established hook%zu (%p)\n",
+			    __func__, __LINE__, th->th_idx, th->th_hook));
+		}
+	} else {
+		if (th->th_hook == NULL) {
+			error = ENXIO;
+		} else {
+			bool stopped = false;
+			if (th->th_stopping) {
+				HK_DPRINTF(("[%s, %d]: stopping = false\n",
+				    __func__, __LINE__));
+				th->th_stopping = false;
+				cv_broadcast(&ctx->ctx_cv);
+				stopped = true;
+			}
+			HK_DPRINTF(("[%s, %d]: disestablish hook%zu (%p)\n",
+			    __func__, __LINE__, th->th_idx, th->th_hook));
+			simplehook_disestablish(ctx->ctx_hooks,
+			    th->th_hook, &ctx->ctx_mutex);
+			th->th_hook = NULL;
+			if (stopped) {
+				HK_DPRINTF(("[%s, %d]: disestablished hook%zu\n",
+				    __func__, __LINE__, th->th_idx));
+			}
+		}
+	}
+
+	mutex_exit(&ctx->ctx_mutex);
+
+	return error;
+}
+
+static int
+simplehook_tester_established_nb(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	int val, error;
+
+	node = *rnode;
+	ctx = node.sysctl_data;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = ctx->ctx_nbhook == NULL ? 0 : 1;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	error = 0;
+	mutex_enter(&ctx->ctx_mutex);
+
+	if (val == 1) {
+		if (ctx->ctx_nbhook != NULL) {
+			error = EEXIST;
+		} else {
+			ctx->ctx_nbhook = simplehook_establish(ctx->ctx_hooks,
+			    simplehook_tester_hook_nb, ctx);
+			KASSERT(ctx->ctx_nbhook != NULL);
+			HK_DPRINTF(("[%s, %d]: established nbhook (%p)\n",
+			    __func__, __LINE__, ctx->ctx_nbhook));
+		}
+	} else {
+		if (ctx->ctx_nbhook == NULL) {
+			error = ENXIO;
+		} else {
+			HK_DPRINTF(("[%s, %d]: disestablish nbhook (%p)\n",
+			    __func__, __LINE__, ctx->ctx_nbhook));
+			simplehook_disestablish(ctx->ctx_hooks,
+			    ctx->ctx_nbhook, NULL);
+			ctx->ctx_nbhook = NULL;
+			HK_DPRINTF(("[%s, %d]: disestablished\n",
+			    __func__, __LINE__));
+		}
+	}
+
+	mutex_exit(&ctx->ctx_mutex);
+
+	return error;
+}
+
+static int
+simplehook_tester_stopping(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	struct tester_hook *th;
+	int error;
+	bool val;
+
+	node = *rnode;
+	th = node.sysctl_data;
+	ctx = th->th_ctx;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = th->th_stopping;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	error = 0;
+	mutex_enter(&ctx->ctx_mutex);
+	if (val == true && !th->th_stopping) {
+		th->th_stopping = true;
+	} else if (val == false && th->th_stopping) {
+		th->th_stopping = false;
+		cv_broadcast(&ctx->ctx_cv);
+	}
+	mutex_exit(&ctx->ctx_mutex);
+
+	return error;
+}
+
+static int
+simplehook_tester_stopped(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	struct tester_hook *th;
+	bool val;
+
+	node = *rnode;
+	th = node.sysctl_data;
+	ctx = th->th_ctx;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = th->th_stopped;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	return sysctl_lookup(SYSCTLFN_CALL(&node));
+}
+
+static int
+simplehook_tester_disestablish(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	struct tester_hook *th;
+	int error;
+	bool val;
+
+	node = *rnode;
+	th = node.sysctl_data;
+	ctx = th->th_ctx;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = th->th_disestablish;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (val != 0 && val != 1)
+		return EINVAL;
+
+	error = 0;
+	mutex_enter(&ctx->ctx_mutex);
+	if (val == true && !th->th_disestablish) {
+		th->th_disestablish = true;
+	} else if (val == false && th->th_disestablish) {
+		th->th_disestablish = false;
+	}
+	mutex_exit(&ctx->ctx_mutex);
+
+	return 0;
+}
+
+static int
+simplehook_tester_count(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct tester_context *ctx;
+	struct tester_hook *th;
+	int error, val;
+
+	node = *rnode;
+	th = node.sysctl_data;
+	ctx = th->th_ctx;
+
+	mutex_enter(&ctx->ctx_mutex);
+	val = th->th_count;
+	mutex_exit(&ctx->ctx_mutex);
+
+	node.sysctl_data = &val;
+	node.sysctl_size = sizeof(val);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	mutex_enter(&ctx->ctx_mutex);
+	th->th_count = val;
+	mutex_exit(&ctx->ctx_mutex);
+
+	return 0;
+}
+
+static int
+simplehook_tester_create_sysctl(struct tester_context *ctx)
+{
+	struct sysctllog **log;
+	const struct sysctlnode *rnode, *cnode;
+	void *ptr;
+	char buf[32];
+	int error;
+	size_t i;
+
+	log = &ctx->ctx_sysctllog;
+	ptr = (void *)ctx;
+
+	error = sysctl_createv(log, 0, NULL, &rnode, CTLFLAG_PERMANENT,
+	    CTLTYPE_NODE, "simplehook_tester",
+	    SYSCTL_DESCR("simplehook testing interface"),
+	    NULL, 0, NULL, 0, CTL_KERN, CTL_CREATE, CTL_EOL);
+	if (error != 0)
+		goto bad;
+
+	error = sysctl_createv(log, 0, &rnode, &cnode,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hook_list",
+	    SYSCTL_DESCR("hook list"), NULL, 0, NULL, 0,
+	    CTL_CREATE, CTL_EOL);
+
+	error = sysctl_createv(log, 0, &cnode, NULL,
+	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
+	    "created", SYSCTL_DESCR("create and destroy hook list"),
+	    simplehook_tester_created, 0, ptr, 0,
+	    CTL_CREATE, CTL_EOL);
+	if (error != 0)
+		goto bad;
+
+	error = sysctl_createv(log, 0, &cnode, NULL,
+	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
+	    "dohooks", SYSCTL_DESCR("do hooks"),
+	    simplehook_tester_dohooks, 0, ptr, 0,
+	    CTL_CREATE, CTL_EOL);
+	if (error != 0)
+		goto bad;
+
+	error = sysctl_createv(log, 0, &rnode, &cnode,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "nbhook",
+	    SYSCTL_DESCR("non-blocking hook"), NULL, 0, NULL, 0,
+	    CTL_CREATE, CTL_EOL);
+	if (error != 0)
+		goto bad;
+
+	error = sysctl_createv(log, 0, &cnode, NULL,
+	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+	    CTLTYPE_INT, "established",
+	    SYSCTL_DESCR("establish and disestablish hook"),
+	    simplehook_tester_established_nb,
+	    0, ptr, 0, CTL_CREATE, CTL_EOL);
+	if (error != 0)
+		goto bad;
+
+	for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
+		snprintf(buf, sizeof(buf), "hook%zu", i);
+		ptr = (void *)&ctx->ctx_hook[i];
+
+		error = sysctl_createv(log, 0, &rnode, &cnode,
+		    CTLFLAG_PERMANENT, CTLTYPE_NODE, buf,
+		    SYSCTL_DESCR("hook information"), NULL, 0, NULL, 0,
+		    CTL_CREATE, CTL_EOL);
+		if (error != 0)
+			goto bad;
+
+		error = sysctl_createv(log, 0, &cnode, NULL,
+		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		    CTLTYPE_INT, "established",
+		    SYSCTL_DESCR("establish and disestablish hook"),
+		    simplehook_tester_established,
+		    0, ptr, 0, CTL_CREATE, CTL_EOL);
+		if (error != 0)
+			goto bad;
+
+		error = sysctl_createv(log, 0, &cnode, NULL,
+		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		    CTLTYPE_BOOL, "stopping",
+		    SYSCTL_DESCR("stopping at beginning of the hook"),
+		    simplehook_tester_stopping, 0, ptr, 0,
+		    CTL_CREATE, CTL_EOL);
+		if (error != 0)
+			goto bad;
+
+		error = sysctl_createv(log, 0, &cnode, NULL,
+		    CTLFLAG_PERMANENT|CTLFLAG_READONLY,
+		    CTLTYPE_BOOL, "stopped",
+		    SYSCTL_DESCR("the hook is stopped"),
+		    simplehook_tester_stopped, 0, ptr, 0,
+		    CTL_CREATE, CTL_EOL);
+		if (error != 0)
+			goto bad;
+
+		error = sysctl_createv(log, 0, &cnode, NULL,
+		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_BOOL,
+		    "disestablish_in_hook",
+		    SYSCTL_DESCR("disestablish this hook in it"),
+		    simplehook_tester_disestablish, 0, ptr, 0,
+		    CTL_CREATE, CTL_EOL);
+		if (error != 0)
+			goto bad;
+
+		error = sysctl_createv(log, 0, &cnode, NULL,
+		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		    CTLTYPE_INT, "count",
+		    SYSCTL_DESCR("the number of calls of the hook"),
+		    simplehook_tester_count, 0, ptr, 0,
+		    CTL_CREATE, CTL_EOL);
+		if (error != 0)
+			goto bad;
+	}
+
+	HK_DPRINTF(("[%s, %d]: created sysctls\n", __func__, __LINE__));
+	return 0;
+
+bad:
+	sysctl_teardown(log);
+	return error;
+}
+
+static void
+simplehook_tester_init_ctx(struct tester_context *ctx)
+{
+	size_t i;
+
+	memset(ctx, 0, sizeof(*ctx));
+	mutex_init(&ctx->ctx_mutex, MUTEX_DEFAULT, IPL_NONE);
+	workqueue_create(&ctx->ctx_wq, "shook_tester_wq",
+	    simplehook_tester_work, ctx, PRI_NONE, IPL_NONE, WQ_MPSAFE);
+	cv_init(&ctx->ctx_cv, "simplehook_tester_cv");
+
+	for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
+		ctx->ctx_hook[i].th_ctx = ctx;
+		ctx->ctx_hook[i].th_idx = i;
+	}
+}
+
+
+int
+simplehook_tester_init(void)
+{
+	int error;
+
+	simplehook_tester_init_ctx(&tester_ctx);
+	error = simplehook_tester_create_sysctl(&tester_ctx);
+
+	return error;
+}
+
+static int
+simplehook_tester_fini(void)
+{
+	struct tester_context *ctx;
+	struct tester_hook *th;
+	khook_list_t *hooks;
+	size_t i;
+
+	ctx = &tester_ctx;
+
+	sysctl_teardown(&ctx->ctx_sysctllog);
+
+	mutex_enter(&ctx->ctx_mutex);
+
+	hooks = ctx->ctx_hooks;
+	ctx->ctx_hooks = NULL;
+	ctx->ctx_wk_waiting = true;
+
+	for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
+		th = &ctx->ctx_hook[i];
+		th->th_stopping = false;
+	}
+	cv_broadcast(&ctx->ctx_cv);
+
+	mutex_exit(&ctx->ctx_mutex);
+
+	workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
+
+	workqueue_destroy(ctx->ctx_wq);
+	if (hooks != NULL)
+		simplehook_destroy(hooks);
+	cv_destroy(&ctx->ctx_cv);
+	mutex_destroy(&ctx->ctx_mutex);
+
+	return 0;
+}
+
+static int
+simplehook_tester_modcmd(modcmd_t cmd, void *arg __unused)
+{
+	int error;
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+		error = simplehook_tester_init();
+		break;
+
+	case MODULE_CMD_FINI:
+		error = simplehook_tester_fini();
+		break;
+
+	case MODULE_CMD_STAT:
+	default:
+		error = ENOTTY;
+	}
+
+	return error;
+}

Index: src/tests/kernel/t_simplehook.sh
diff -u /dev/null src/tests/kernel/t_simplehook.sh:1.1
--- /dev/null	Thu Sep 30 02:00:20 2021
+++ src/tests/kernel/t_simplehook.sh	Thu Sep 30 02:00:20 2021
@@ -0,0 +1,294 @@
+#	$NetBSD: t_simplehook.sh,v 1.1 2021/09/30 02:00:20 yamaguchi Exp $
+#
+# Copyright (c) 2021 Internet Initiative Japan Inc.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``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 FOUNDATION OR CONTRIBUTORS
+# 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.
+#
+
+DEBUG=${DEBUG:-false}
+SOCK=unix://commsock
+HIJACKING="env LD_PRELOAD=/usr/lib/librumphijack.so \
+    RUMPHIJACK=path=/rump,socket=all:nolocal,sysctl=yes"
+
+atf_sysctl_rd()
+{
+	local sysctl_key=$1
+	local expected=$2
+
+	atf_check -s exit:0 -o match:"$expected" \
+	    rump.sysctl -n $sysctl_key
+}
+
+atf_sysctl_wr()
+{
+	local sysctl_key=$1
+	local value=$2
+
+	atf_check -s exit:0 -o ignore rump.sysctl -w $sysctl_key=$value
+}
+
+atf_sysctl_wait()
+{
+	local sysctl_key=$1
+	local expected=$2
+	local n=10
+	local i
+	local v
+
+	for i in $(seq $n); do
+		v=$(rump.sysctl -n $sysctl_key)
+		if [ x"$v" = x"$expected" ]; then
+			return
+		fi
+		sleep 0.5
+	done
+
+	atf_fail "Couldn't get the value for $n seconds."
+}
+
+atf_test_case simplehook_basic cleanup
+simplehook_basic_head()
+{
+
+	atf_set "descr" "tests for basically functions of simplehook"
+	atf_set "require.progs" "rump_server"
+}
+
+
+simplehook_basic_body()
+{
+	local key_hklist="kern.simplehook_tester.hook_list"
+	local key_hk0="kern.simplehook_tester.hook0"
+	local key_hk1="kern.simplehook_tester.hook1"
+
+	rump_server -lrumpkern_simplehook_tester $SOCK
+
+	export RUMP_SERVER=$SOCK
+
+	$DEBUG && rump.sysctl -e kern.simplehook_tester
+	atf_check -s exit:0 -o ignore rump.sysctl -e kern.simplehook_tester
+
+	# create and destroy
+	atf_sysctl_rd ${key_hklist}.created '0'
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hklist}.created '0'
+	$DEBUG && rump.sysctl -e kern.simplehook_tester
+
+	# establish one hook
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hk0}.established '1'
+	atf_sysctl_wr ${key_hk0}.count '0'
+	atf_sysctl_wr ${key_hklist}.dohooks '1'
+	atf_sysctl_wr ${key_hklist}.dohooks '0'
+	atf_sysctl_rd ${key_hk0}.count '1'
+	atf_sysctl_wr ${key_hk0}.established '0'
+	atf_sysctl_wr ${key_hklist}.created '0'
+
+	# establish two hooks
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hk0}.established '1'
+	atf_sysctl_wr ${key_hk1}.established '1'
+	atf_sysctl_wr ${key_hk0}.count '0'
+	atf_sysctl_wr ${key_hk1}.count '0'
+
+	atf_sysctl_wr ${key_hklist}.dohooks '1'
+	atf_sysctl_wr ${key_hklist}.dohooks '0'
+	atf_sysctl_rd ${key_hk0}.count '1'
+	atf_sysctl_rd ${key_hk1}.count '1'
+
+	atf_sysctl_wr ${key_hk0}.established '0'
+	atf_sysctl_wr ${key_hk1}.established '0'
+	atf_sysctl_wr ${key_hklist}.created '0'
+}
+
+simplehook_basic_cleanup()
+{
+	export RUMP_SERVER=$SOCK
+
+	$DEBUG && rump.sysctl -e kern.simplehook_tester
+	$DEBUG && $HIJACKING dmesg
+	rump.halt
+}
+
+atf_test_case simplehook_disestablish cleanup
+simplehook_disestablish_head()
+{
+
+	atf_set "descr" "tests for disestablish of simplehook"
+	atf_set "require.progs" "rump_server"
+}
+
+simplehook_disestablish_body()
+{
+	local key_hklist="kern.simplehook_tester.hook_list"
+	local key_hk0="kern.simplehook_tester.hook0"
+	local key_hk1="kern.simplehook_tester.hook1"
+
+	rump_server -lrumpkern_simplehook_tester $SOCK
+
+	export RUMP_SERVER=$SOCK
+
+	$DEBUG && rump.sysctl -e kern.simplehook_tester
+	atf_check -s exit:0 -o ignore rump.sysctl -e kern.simplehook_tester
+
+	#
+	# disestablish on the running hook
+	#
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hk0}.established '1'
+	atf_sysctl_wr ${key_hk0}.disestablish_in_hook '1'
+	atf_sysctl_wr ${key_hklist}.dohooks '1'
+	atf_sysctl_wr ${key_hklist}.dohooks '0'
+
+	# already disestablished
+	atf_sysctl_rd ${key_hk0}.established '0'
+	atf_sysctl_wr ${key_hk0}.disestablish_in_hook '0'
+
+	atf_sysctl_wr ${key_hklist}.created '0'
+
+	#
+	# disestablish called hook while doing other hook
+	#
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hk0}.established '1'
+	atf_sysctl_wr ${key_hk1}.established '1'
+
+	atf_sysctl_wr ${key_hk0}.count '0'
+	atf_sysctl_wr ${key_hk1}.count '0'
+	atf_sysctl_wr ${key_hk0}.stopping '1'
+
+	# calls hook1 -> hook0
+	atf_sysctl_wr ${key_hklist}.dohooks '1'
+
+	# stop in hook0
+	atf_sysctl_wait ${key_hk0}.stopped '1'
+
+	atf_sysctl_rd ${key_hk1}.count '1'
+	atf_sysctl_wr ${key_hk1}.established '0'
+
+	# wakeup hook0
+	atf_sysctl_wr ${key_hk0}.stopping '0'
+	atf_sysctl_wr ${key_hklist}.dohooks '0'
+
+	atf_sysctl_wr ${key_hk0}.established '0'
+	atf_sysctl_wr ${key_hklist}.created '0'
+
+	#
+	# disestablish a hook in running hook list
+	#
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hk0}.established '1'
+	atf_sysctl_wr ${key_hk1}.established '1'
+
+	atf_sysctl_wr ${key_hk0}.count '0'
+	atf_sysctl_wr ${key_hk1}.count '0'
+	atf_sysctl_wr ${key_hk1}.stopping '1'
+
+	# calls hook1 -> hook0
+	atf_sysctl_wr ${key_hklist}.dohooks '1'
+
+	# stop in hook1
+	atf_sysctl_wait ${key_hk1}.stopped '1'
+
+	atf_sysctl_wr ${key_hk0}.established '0'
+
+	# wakeup hook1
+	atf_sysctl_wr ${key_hk1}.stopping '0'
+	atf_sysctl_wr ${key_hklist}.dohooks '0'
+
+	# hook0 is not called
+	atf_sysctl_rd ${key_hk0}.count '0'
+
+	atf_sysctl_wr ${key_hk1}.established '0'
+	atf_sysctl_wr ${key_hklist}.created '0'
+
+	#
+	# disestablish the running hook
+	#
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hk0}.established '1'
+	atf_sysctl_wr ${key_hk0}.stopping '1'
+
+	atf_sysctl_wr ${key_hklist}.dohooks '1'
+
+	atf_sysctl_wait ${key_hk0}.stopped '1'
+	atf_sysctl_wr ${key_hk0}.established '0'
+
+	atf_sysctl_wr ${key_hklist}.dohooks '0'
+	atf_sysctl_wr ${key_hklist}.created '0'
+}
+
+simplehook_disestablish_cleanup()
+{
+	export RUMP_SERVER=$SOCK
+
+	$DEBUG && rump.sysctl -e kern.simplehook_tester
+	$DEBUG && $HIJACKING dmesg
+	rump.halt
+}
+
+atf_test_case simplehook_nolock cleanup
+simplehook_nolock_head()
+{
+
+	atf_set "descr" "tests for hook that does not use lock in it"
+	atf_set "require.progs" "rump_server"
+}
+
+simplehook_nolock_body()
+{
+	local key_hklist="kern.simplehook_tester.hook_list"
+	local key_hk="kern.simplehook_tester.nbhook"
+
+	rump_server -lrumpkern_simplehook_tester $SOCK
+
+	export RUMP_SERVER=$SOCK
+	$DEBUG && rump.sysctl -e kern.simplehook_tester
+	atf_check -s exit:0 -o ignore rump.sysctl -e kern.simplehook_tester
+
+	atf_sysctl_wr ${key_hklist}.created '1'
+	atf_sysctl_wr ${key_hk}.established '1'
+
+	atf_sysctl_wr ${key_hklist}.dohooks '1'
+	atf_sysctl_wr ${key_hk}.established '0'
+	atf_sysctl_wr ${key_hklist}.dohooks '0'
+
+	atf_sysctl_wr ${key_hklist}.created '0'
+}
+
+simplehook_nolock_cleanup()
+{
+	export RUMP_SERVER=$SOCK
+
+	$DEBUG && rump.sysctl -e kern.simplehook_tester
+	$DEBUG && $HIJACKING dmesg
+	rump.halt
+}
+
+atf_init_test_cases()
+{
+
+	atf_add_test_case simplehook_basic
+	atf_add_test_case simplehook_disestablish
+	atf_add_test_case simplehook_nolock
+}

Reply via email to