Module Name: src Committed By: yamaguchi Date: Thu Sep 30 01:26:08 UTC 2021
Modified Files: src/distrib/sets/lists/comp: mi src/sys/kern: kern_hook.c src/sys/sys: Makefile Added Files: src/sys/sys: hook.h Log Message: Introduce a generic linear hook list To generate a diff of this commit: cvs rdiff -u -r1.2393 -r1.2394 src/distrib/sets/lists/comp/mi cvs rdiff -u -r1.8 -r1.9 src/sys/kern/kern_hook.c cvs rdiff -u -r1.178 -r1.179 src/sys/sys/Makefile cvs rdiff -u -r0 -r1.1 src/sys/sys/hook.h 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/comp/mi diff -u src/distrib/sets/lists/comp/mi:1.2393 src/distrib/sets/lists/comp/mi:1.2394 --- src/distrib/sets/lists/comp/mi:1.2393 Sun Sep 19 15:51:27 2021 +++ src/distrib/sets/lists/comp/mi Thu Sep 30 01:26:07 2021 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.2393 2021/09/19 15:51:27 thorpej Exp $ +# $NetBSD: mi,v 1.2394 2021/09/30 01:26:07 yamaguchi Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. ./etc/mtree/set.comp comp-sys-root @@ -3306,6 +3306,7 @@ ./usr/include/sys/gmon.h comp-c-include ./usr/include/sys/gpio.h comp-c-include ./usr/include/sys/hash.h comp-c-include +./usr/include/sys/hook.h comp-c-include ./usr/include/sys/idtype.h comp-c-include ./usr/include/sys/ieee754.h comp-c-include ./usr/include/sys/intr.h comp-c-include Index: src/sys/kern/kern_hook.c diff -u src/sys/kern/kern_hook.c:1.8 src/sys/kern/kern_hook.c:1.9 --- src/sys/kern/kern_hook.c:1.8 Wed Oct 16 18:29:49 2019 +++ src/sys/kern/kern_hook.c Thu Sep 30 01:26:07 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_hook.c,v 1.8 2019/10/16 18:29:49 christos Exp $ */ +/* $NetBSD: kern_hook.c,v 1.9 2021/09/30 01:26:07 yamaguchi Exp $ */ /*- * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc. @@ -31,13 +31,16 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_hook.c,v 1.8 2019/10/16 18:29:49 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_hook.c,v 1.9 2021/09/30 01:26:07 yamaguchi Exp $"); #include <sys/param.h> #include <sys/malloc.h> #include <sys/rwlock.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/hook.h> +#include <sys/kmem.h> +#include <sys/condvar.h> /* * A generic linear hook. @@ -49,6 +52,23 @@ struct hook_desc { }; typedef LIST_HEAD(, hook_desc) hook_list_t; +enum hook_list_st { + HKLIST_IDLE, + HKLIST_INUSE, +}; + +struct khook_list { + hook_list_t hl_list; + kmutex_t hl_lock; + kmutex_t *hl_cvlock; + struct lwp *hl_lwp; + kcondvar_t hl_cv; + enum hook_list_st + hl_state; + khook_t *hl_active_hk; + char hl_namebuf[HOOKNAMSIZ]; +}; + int powerhook_debug = 0; static void * @@ -398,3 +418,186 @@ dopowerhooks(int why) if (powerhook_debug) printf("dopowerhooks: %s done\n", why_name); } + +/* + * A simple linear hook. + */ + +khook_list_t * +simplehook_create(int ipl, const char *wmsg) +{ + khook_list_t *l; + + l = kmem_zalloc(sizeof(*l), KM_SLEEP); + + mutex_init(&l->hl_lock, MUTEX_DEFAULT, ipl); + strlcpy(l->hl_namebuf, wmsg, sizeof(l->hl_namebuf)); + cv_init(&l->hl_cv, l->hl_namebuf); + LIST_INIT(&l->hl_list); + l->hl_state = HKLIST_IDLE; + + return l; +} + +void +simplehook_destroy(khook_list_t *l) +{ + struct hook_desc *hd; + + KASSERT(l->hl_state == HKLIST_IDLE); + + while ((hd = LIST_FIRST(&l->hl_list)) != NULL) { + LIST_REMOVE(hd, hk_list); + kmem_free(hd, sizeof(*hd)); + } + + cv_destroy(&l->hl_cv); + mutex_destroy(&l->hl_lock); + kmem_free(l, sizeof(*l)); +} + +int +simplehook_dohooks(khook_list_t *l) +{ + struct hook_desc *hd, *nexthd; + kmutex_t *cv_lock; + void (*fn)(void *); + void *arg; + + mutex_enter(&l->hl_lock); + if (l->hl_state != HKLIST_IDLE) { + mutex_exit(&l->hl_lock); + return EBUSY; + } + + /* stop removing hooks */ + l->hl_state = HKLIST_INUSE; + l->hl_lwp = curlwp; + + LIST_FOREACH(hd, &l->hl_list, hk_list) { + if (hd->hk_fn == NULL) + continue; + + fn = hd->hk_fn; + arg = hd->hk_arg; + l->hl_active_hk = hd; + l->hl_cvlock = NULL; + + mutex_exit(&l->hl_lock); + + /* do callback without l->hl_lock */ + (*fn)(arg); + + mutex_enter(&l->hl_lock); + l->hl_active_hk = NULL; + cv_lock = l->hl_cvlock; + + if (hd->hk_fn == NULL) { + if (cv_lock != NULL) { + mutex_exit(&l->hl_lock); + mutex_enter(cv_lock); + } + + cv_broadcast(&l->hl_cv); + + if (cv_lock != NULL) { + mutex_exit(cv_lock); + mutex_enter(&l->hl_lock); + } + } + } + + /* remove marked node while running hooks */ + LIST_FOREACH_SAFE(hd, &l->hl_list, hk_list, nexthd) { + if (hd->hk_fn == NULL) { + LIST_REMOVE(hd, hk_list); + kmem_free(hd, sizeof(*hd)); + } + } + + l->hl_lwp = NULL; + l->hl_state = HKLIST_IDLE; + mutex_exit(&l->hl_lock); + + return 0; +} + +khook_t * +simplehook_establish(khook_list_t *l, void (*fn)(void *), void *arg) +{ + struct hook_desc *hd; + + hd = kmem_zalloc(sizeof(*hd), KM_SLEEP); + hd->hk_fn = fn; + hd->hk_arg = arg; + + mutex_enter(&l->hl_lock); + LIST_INSERT_HEAD(&l->hl_list, hd, hk_list); + mutex_exit(&l->hl_lock); + + return hd; +} + +void +simplehook_disestablish(khook_list_t *l, khook_t *hd, kmutex_t *lock) +{ + struct hook_desc *hd0 __diagused; + kmutex_t *cv_lock; + + KASSERT(lock == NULL || mutex_owned(lock)); + mutex_enter(&l->hl_lock); + +#ifdef DIAGNOSTIC + LIST_FOREACH(hd0, &l->hl_list, hk_list) { + if (hd == hd0) + break; + } + + if (hd0 == NULL) + panic("hook_disestablish: hook %p not established", hd); +#endif + + /* The hook is not referred, remove immidiately */ + if (l->hl_state == HKLIST_IDLE) { + LIST_REMOVE(hd, hk_list); + kmem_free(hd, sizeof(*hd)); + mutex_exit(&l->hl_lock); + return; + } + + /* remove callback. hd will be removed in dohooks */ + hd->hk_fn = NULL; + hd->hk_arg = NULL; + + /* If the hook is running, wait for the completion */ + if (l->hl_active_hk == hd && + l->hl_lwp != curlwp) { + if (lock != NULL) { + cv_lock = lock; + KASSERT(l->hl_cvlock == NULL); + l->hl_cvlock = lock; + mutex_exit(&l->hl_lock); + } else { + cv_lock = &l->hl_lock; + } + + cv_wait(&l->hl_cv, cv_lock); + + if (lock == NULL) + mutex_exit(&l->hl_lock); + } else { + mutex_exit(&l->hl_lock); + } +} + +bool +simplehook_has_hooks(khook_list_t *l) +{ + bool empty; + + mutex_enter(&l->hl_lock); + empty = LIST_EMPTY(&l->hl_list); + mutex_exit(&l->hl_lock); + + return !empty; +} Index: src/sys/sys/Makefile diff -u src/sys/sys/Makefile:1.178 src/sys/sys/Makefile:1.179 --- src/sys/sys/Makefile:1.178 Sun Sep 19 15:51:27 2021 +++ src/sys/sys/Makefile Thu Sep 30 01:26:07 2021 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.178 2021/09/19 15:51:27 thorpej Exp $ +# $NetBSD: Makefile,v 1.179 2021/09/30 01:26:07 yamaguchi Exp $ .include <bsd.own.mk> @@ -23,7 +23,7 @@ INCS= acct.h acl.h agpio.h aio.h ansi.h fault.h \ fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \ flashio.h float_ieee754.h fstypes.h futex.h gcq.h gmon.h gpio.h hash.h \ - idtype.h ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h \ + hook.h idtype.h ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h \ ioctl_compat.h iostat.h ipc.h ipmi.h \ joystick.h \ kcore.h kcov.h kcpuset.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \ Added files: Index: src/sys/sys/hook.h diff -u /dev/null src/sys/sys/hook.h:1.1 --- /dev/null Thu Sep 30 01:26:08 2021 +++ src/sys/sys/hook.h Thu Sep 30 01:26:07 2021 @@ -0,0 +1,52 @@ +/* $NetBSD: hook.h,v 1.1 2021/09/30 01:26:07 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. + */ + +#ifndef _SYS_HOOK_H_ +#define _SYS_HOOK_H_ + +#include <sys/mutex.h> + +#define HOOKNAMSIZ 128 + +struct khook_list; +struct hook_desc; + +typedef struct khook_list khook_list_t; +typedef struct hook_desc khook_t; + +khook_list_t *simplehook_create(int, const char *); +void simplehook_destroy(khook_list_t *); +int simplehook_dohooks(khook_list_t *); + +khook_t *simplehook_establish(khook_list_t *, + void (*)(void *), void *); +void simplehook_disestablish(khook_list_t *, + khook_t *, kmutex_t *); +bool simplehook_has_hooks(khook_list_t *); + +#endif /* !_SYS_HOOK_H_ */