diff options
author | msmith <msmith@FreeBSD.org> | 1999-08-21 06:24:40 +0000 |
---|---|---|
committer | msmith <msmith@FreeBSD.org> | 1999-08-21 06:24:40 +0000 |
commit | b51f157bff8b959d943b0836a1c57f065b9318d5 (patch) | |
tree | e447ab34080a4d202ed41db3476df31ef1f56a50 /sys/kern | |
parent | a753b272ec1066c690e1ba83c8780af55e3a6c78 (diff) | |
download | FreeBSD-src-b51f157bff8b959d943b0836a1c57f065b9318d5.zip FreeBSD-src-b51f157bff8b959d943b0836a1c57f065b9318d5.tar.gz |
Implement a new generic mechanism for attaching handler functions to
events, in order to pave the way for removing a number of the ad-hoc
implementations currently in use.
Retire the at_shutdown family of functions and replace them with
new event handler lists.
Rework kern_shutdown.c to take greater advantage of the use of event
handlers.
Reviewed by: green
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_module.c | 10 | ||||
-rw-r--r-- | sys/kern/kern_shutdown.c | 189 | ||||
-rw-r--r-- | sys/kern/subr_eventhandler.c | 140 |
3 files changed, 201 insertions, 138 deletions
diff --git a/sys/kern/kern_module.c b/sys/kern/kern_module.c index f380386..19dd2be 100644 --- a/sys/kern/kern_module.c +++ b/sys/kern/kern_module.c @@ -23,12 +23,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: kern_module.c,v 1.17 1999/05/08 13:01:57 peter Exp $ + * $Id: kern_module.c,v 1.18 1999/05/20 00:00:58 peter Exp $ */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/eventhandler.h> #include <sys/malloc.h> #include <sys/sysproto.h> #include <sys/sysent.h> @@ -56,19 +57,20 @@ struct module { static modulelist_t modules; static int nextid = 1; -static void module_shutdown(int, void*); +static void module_shutdown(void*, int); static void module_init(void* arg) { TAILQ_INIT(&modules); - at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC); + EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL, + SHUTDOWN_PRI_DEFAULT); } SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); static void -module_shutdown(int arg1, void* arg2) +module_shutdown(void* arg1, int arg2) { module_t mod; diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 8465777..4df03a7 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)kern_shutdown.c 8.3 (Berkeley) 1/21/94 - * $Id: kern_shutdown.c,v 1.59 1999/08/11 14:02:20 alfred Exp $ + * $Id: kern_shutdown.c,v 1.60 1999/08/13 10:29:21 phk Exp $ */ #include "opt_ddb.h" @@ -46,6 +46,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/eventhandler.h> #include <sys/buf.h> #include <sys/reboot.h> #include <sys/proc.h> @@ -107,34 +108,26 @@ watchdog_tickle_fn wdog_tickler = NULL; */ const char *panicstr; -/* - * callout list for things to do a shutdown - */ -typedef struct shutdown_list_element { - LIST_ENTRY(shutdown_list_element) links; - bootlist_fn function; - void *arg; - int priority; -} *sle_p; - -/* - * There are three shutdown lists. Some things need to be shut down - * earlier than others. - */ -LIST_HEAD(shutdown_list, shutdown_list_element); - -static struct shutdown_list shutdown_lists[SHUTDOWN_FINAL + 1]; - static void boot __P((int)) __dead2; static void dumpsys __P((void)); static int setdumpdev __P((dev_t dev)); +static void poweroff_wait __P((void *, int)); +static void shutdown_halt __P((void *junk, int howto)); +static void shutdown_panic __P((void *junk, int howto)); +static void shutdown_reset __P((void *junk, int howto)); + +/* register various local shutdown events */ +static void +shutdown_conf(void *unused) +{ + EVENTHANDLER_REGISTER(shutdown_final, poweroff_wait, NULL, SHUTDOWN_PRI_FIRST); + EVENTHANDLER_REGISTER(shutdown_final, shutdown_halt, NULL, SHUTDOWN_PRI_LAST + 100); + EVENTHANDLER_REGISTER(shutdown_final, shutdown_panic, NULL, SHUTDOWN_PRI_LAST + 100); + EVENTHANDLER_REGISTER(shutdown_final, shutdown_reset, NULL, SHUTDOWN_PRI_LAST + 200); +} +SYSINIT(shutdown_conf, SI_SUB_INTRINSIC, SI_ORDER_ANY, shutdown_conf, NULL) -#ifndef _SYS_SYSPROTO_H_ -struct reboot_args { - int opt; -}; -#endif /* ARGSUSED */ /* @@ -181,7 +174,6 @@ static void boot(howto) int howto; { - sle_p ep; #ifdef SMP if (smp_active) { @@ -191,8 +183,7 @@ boot(howto) /* * Do any callouts that should be done BEFORE syncing the filesystems. */ - LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_PRE_SYNC], links) - (*ep->function)(howto, ep->arg); + EVENTHANDLER_INVOKE(shutdown_pre_sync, howto); /* * Now sync filesystems @@ -282,8 +273,7 @@ boot(howto) * Ok, now do things that assume all filesystem activity has * been completed. */ - LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_POST_SYNC], links) - (*ep->function)(howto, ep->arg); + EVENTHANDLER_INVOKE(shutdown_post_sync, howto); splhigh(); if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold) { savectx(&dumppcb); @@ -294,9 +284,18 @@ boot(howto) } /* Now that we're going to really halt the system... */ - LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_FINAL], links) - (*ep->function)(howto, ep->arg); + EVENTHANDLER_INVOKE(shutdown_final, howto); + + for(;;) ; /* safety against shutdown_reset not working */ + /* NOTREACHED */ +} +/* + * If the shutdown was a clean halt, behave accordingly. + */ +static void +shutdown_halt(void *junk, int howto) +{ if (howto & RB_HALT) { printf("\n"); printf("The operating system has halted.\n"); @@ -309,12 +308,21 @@ boot(howto) howto &= ~RB_HALT; break; } - } else if (howto & RB_DUMP) { - /* System Paniced */ + } +} + +/* + * Check to see if the system paniced, pause and then reboot + * according to the specified delay. + */ +static void +shutdown_panic(void *junk, int howto) +{ + int loop; + if (howto & RB_DUMP) { if (PANIC_REBOOT_WAIT_TIME != 0) { if (PANIC_REBOOT_WAIT_TIME != -1) { - int loop; printf("Automatic reboot in %d seconds - " "press a key on the console to abort\n", PANIC_REBOOT_WAIT_TIME); @@ -326,21 +334,27 @@ boot(howto) break; } if (!loop) - goto die; + return; } } else { /* zero time specified - reboot NOW */ - goto die; + return; } printf("--> Press a key on the console to reboot <--\n"); cngetc(); } -die: +} + +/* + * Everything done, now reset + */ +static void +shutdown_reset(void *junk, int howto) +{ printf("Rebooting...\n"); DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ /* cpu_boot(howto); */ /* doesn't do anything at the moment */ cpu_reset(); - for(;;) ; - /* NOTREACHED */ + /* NOTREACHED */ /* assuming reset worked */ } /* @@ -516,109 +530,16 @@ panic(const char *fmt, ...) } /* - * Three routines to handle adding/deleting items on the - * shutdown callout lists - * - * at_shutdown(): - * Take the arguments given and put them onto the shutdown callout list. - * However first make sure that it's not already there. - * returns 0 on success. - */ -int -at_shutdown(bootlist_fn function, void *arg, int queue) -{ - return(at_shutdown_pri(function, arg, queue, SHUTDOWN_PRI_DEFAULT)); -} - -/* - * at_shutdown_pri(): - * Take the arguments given and put them onto the shutdown callout list - * with the given execution priority. - * returns 0 on success. - */ -int -at_shutdown_pri(bootlist_fn function, void *arg, int queue, int pri) -{ - sle_p op, ep, ip; - - op = NULL; /* shut up gcc */ - if (queue < SHUTDOWN_PRE_SYNC - || queue > SHUTDOWN_FINAL) { - printf("at_shutdown: bad exit callout queue %d specified\n", - queue); - return (EINVAL); - } - if (rm_at_shutdown(function, arg)) - printf("at_shutdown: exit callout entry was already present\n"); - ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); - if (ep == NULL) - return (ENOMEM); - ep->function = function; - ep->arg = arg; - ep->priority = pri; - - /* Sort into list of items on this queue */ - ip = LIST_FIRST(&shutdown_lists[queue]); - if (ip == NULL) { - LIST_INSERT_HEAD(&shutdown_lists[queue], ep, links); - } else { - for (; ip != NULL; op = ip, ip = LIST_NEXT(ip, links)) { - if (ep->priority < ip->priority) { - LIST_INSERT_BEFORE(ip, ep, links); - ep = NULL; - break; - } - } - if (ep != NULL) - LIST_INSERT_AFTER(op, ep, links); - } - return (0); -} - -/* - * Scan the exit callout lists for the given items and remove them. - * Returns the number of items removed. - */ -int -rm_at_shutdown(bootlist_fn function, void *arg) -{ - sle_p ep; - int count; - int queue; - - count = 0; - for (queue = SHUTDOWN_PRE_SYNC; queue < SHUTDOWN_FINAL; queue++) { - LIST_FOREACH(ep, &shutdown_lists[queue], links) { - if ((ep->function == function) && (ep->arg == arg)) { - LIST_REMOVE(ep, links); - free(ep, M_TEMP); - count++; - } - } - } - return (count); -} - -/* * Support for poweroff delay. */ static int poweroff_delay = 0; SYSCTL_INT(_kern_shutdown, OID_AUTO, poweroff_delay, CTLFLAG_RW, &poweroff_delay, 0, ""); -static void poweroff_wait(int howto, void *unused) +static void +poweroff_wait(void *junk, int howto) { if(!(howto & RB_POWEROFF) || poweroff_delay <= 0) return; DELAY(poweroff_delay * 1000); } - -/* - * XXX OK? This implies I know SHUTDOWN_PRI_LAST > SHUTDOWN_PRI_FIRST - */ -static void poweroff_conf(void *unused) -{ - at_shutdown_pri(poweroff_wait, NULL, SHUTDOWN_FINAL, SHUTDOWN_PRI_FIRST); -} - -SYSINIT(poweroff_conf, SI_SUB_INTRINSIC, SI_ORDER_ANY, poweroff_conf, NULL) diff --git a/sys/kern/subr_eventhandler.c b/sys/kern/subr_eventhandler.c new file mode 100644 index 0000000..2caef17 --- /dev/null +++ b/sys/kern/subr_eventhandler.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> + * 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 AUTHOR 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 AUTHOR 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. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/systm.h> +#include <sys/eventhandler.h> + +MALLOC_DEFINE(M_EVENTHANDLER, "eventhandler", "Event handler records"); + +/* List of 'slow' lists */ +static TAILQ_HEAD(, eventhandler_list) eventhandler_lists; +static int eventhandler_lists_initted = 0; + +struct eventhandler_entry_generic +{ + struct eventhandler_entry ee; + void (* func)(void); +}; + +/* + * Insertion is O(n) due to the priority scan, but optimises to O(1) + * if all priorities are identical. + */ +eventhandler_tag +eventhandler_register(struct eventhandler_list *list, char *name, + void *func, void *arg, int priority) +{ + struct eventhandler_entry_generic *eg; + struct eventhandler_entry *ep; + + /* avoid the need for a SYSINIT just to init the list */ + if (!eventhandler_lists_initted) { + TAILQ_INIT(&eventhandler_lists); + eventhandler_lists_initted = 1; + } + + /* Do we need to find/create the (slow) list? */ + if (list == NULL) { + /* look for a matching, existing list */ + list = eventhandler_find_list(name); + + /* Do we need to create the list? */ + if (list == NULL) { + if ((list = malloc(sizeof(struct eventhandler_list) + strlen(name) + 1, + M_EVENTHANDLER, M_NOWAIT)) == NULL) + return(NULL); + list->el_flags = 0; + list->el_name = (char *)list + sizeof(struct eventhandler_list); + strcpy(list->el_name, name); + TAILQ_INSERT_HEAD(&eventhandler_lists, list, el_link); + } + } + if (!(list->el_flags & EHE_INITTED)) { + TAILQ_INIT(&list->el_entries); + list->el_flags = EHE_INITTED; + } + + /* allocate an entry for this handler, populate it */ + if ((eg = malloc(sizeof(struct eventhandler_entry_generic), + M_EVENTHANDLER, M_NOWAIT)) == NULL) + return(NULL); + eg->func = func; + eg->ee.ee_arg = arg; + eg->ee.ee_priority = priority; + + /* sort it into the list */ + for (ep = TAILQ_FIRST(&list->el_entries); + ep != NULL; + ep = TAILQ_NEXT(ep, ee_link)) { + if (eg->ee.ee_priority < ep->ee_priority) { + TAILQ_INSERT_BEFORE(ep, &eg->ee, ee_link); + break; + } + } + if (ep == NULL) + TAILQ_INSERT_TAIL(&list->el_entries, &eg->ee, ee_link); + return(&eg->ee); +} + +void +eventhandler_deregister(struct eventhandler_list *list, eventhandler_tag tag) +{ + struct eventhandler_entry *ep = tag; + + /* XXX insert diagnostic check here? */ + if (ep != NULL) { + /* remove just this entry */ + TAILQ_REMOVE(&list->el_entries, ep, ee_link); + free(ep, M_EVENTHANDLER); + } else { + /* remove entire list */ + while (!TAILQ_EMPTY(&list->el_entries)) { + ep = TAILQ_FIRST(&list->el_entries); + TAILQ_REMOVE(&list->el_entries, list->el_entries.tqh_first, ee_link); + free(ep, M_EVENTHANDLER); + } + } +} + +struct eventhandler_list * +eventhandler_find_list(char *name) +{ + struct eventhandler_list *list; + + /* scan looking for the requested list */ + for (list = TAILQ_FIRST(&eventhandler_lists); + list != NULL; + list = TAILQ_NEXT(list, el_link)) { + if (!strcmp(name, list->el_name)) + break; + } + return(list); +} |