From 93efcae809aa8f6d7c94d55503520a0aa03d405f Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Fri, 19 Nov 1999 21:29:03 +0000 Subject: [PATCH] The at_exit and at_fork functions currently use a 'roll your own' linked list to store the callbak routines. The patch converts the lists to queue(3) TAILQs, making the code slightly clearer and ensuring that callbacks are executed in FIFO order. Man page also updated as necesary. (discontinued use of M_TEMP malloc type while here anyway /phk) Submitted by: Jake Burkholder jake@checker.org PR: 14912 --- share/man/man9/at_exit.9 | 4 --- share/man/man9/at_fork.9 | 4 --- sys/kern/kern_exit.c | 57 +++++++++++++++++++-------------------- sys/kern/kern_fork.c | 58 +++++++++++++++++++--------------------- 4 files changed, 54 insertions(+), 69 deletions(-) diff --git a/share/man/man9/at_exit.9 b/share/man/man9/at_exit.9 index 352e6b229e2..234ef45a9cf 100644 --- a/share/man/man9/at_exit.9 +++ b/share/man/man9/at_exit.9 @@ -70,10 +70,6 @@ The .Fn at_exit function appeared in .Fx 2.2 . -.Sh BUGS -Since the exit queue is not sorted -and items are added to the head, order of execution -is reversed to that of insertion. .Sh AUTHORS The function was written by .An Julian Elischer Aq julian@FreeBSD.org . diff --git a/share/man/man9/at_fork.9 b/share/man/man9/at_fork.9 index 369bc54d776..f9ea282d291 100644 --- a/share/man/man9/at_fork.9 +++ b/share/man/man9/at_fork.9 @@ -72,10 +72,6 @@ The .Fn at_fork function appeared in .Fx 2.2 . -.Sh BUGS -Since the fork queue is not sorted -and items are added to the head, order of execution -is reversed to that of insertion. .Sh AUTHORS The function was written by .An Julian Elischer Aq julian@FreeBSD.org . diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 6c00e43c518..abbe9de4a0d 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -75,17 +75,20 @@ /* Required to be non-static for SysVR4 emulator */ MALLOC_DEFINE(M_ZOMBIE, "zombie", "zombie proc status"); +static MALLOC_DEFINE(M_ATEXIT, "atexit", "atexit callback"); + static int wait1 __P((struct proc *, struct wait_args *, int)); /* * callout list for things to do at exit time */ -typedef struct exit_list_element { - struct exit_list_element *next; +struct exitlist { exitlist_fn function; -} *ele_p; + TAILQ_ENTRY(exitlist) next; +}; -static ele_p exit_list; +TAILQ_HEAD(exit_list_head, exitlist); +static struct exit_list_head exit_list = TAILQ_HEAD_INITIALIZER(exit_list); /* * exit -- @@ -115,7 +118,7 @@ exit1(p, rv) { register struct proc *q, *nq; register struct vmspace *vm; - ele_p ep = exit_list; + struct exitlist *ep; if (p->p_pid == 1) { printf("init died (signal %d, exit %d)\n", @@ -154,10 +157,8 @@ exit1(p, rv) * e.g. SYSV IPC stuff * XXX what if one of these generates an error? */ - while (ep) { + TAILQ_FOREACH(ep, &exit_list, next) (*ep->function)(p); - ep = ep->next; - } if (p->p_flag & P_PROFIL) stopprofclock(p); @@ -580,49 +581,45 @@ proc_reparent(child, parent) * However first make sure that it's not already there. * returns 0 on success. */ + int at_exit(function) exitlist_fn function; { - ele_p ep; + struct exitlist *ep; +#ifdef INVARIANTS /* Be noisy if the programmer has lost track of things */ if (rm_at_exit(function)) - printf("exit callout entry already present\n"); - ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); + printf("WARNING: exit callout entry (%p) already present\n", + function); +#endif + ep = malloc(sizeof(*ep), M_ATEXIT, M_NOWAIT); if (ep == NULL) return (ENOMEM); - ep->next = exit_list; ep->function = function; - exit_list = ep; + TAILQ_INSERT_TAIL(&exit_list, ep, next); return (0); } + /* - * Scan the exit callout list for the given items and remove them. - * Returns the number of items removed. - * Logically this can only be 0 or 1. + * Scan the exit callout list for the given item and remove it. + * Returns the number of items removed (0 or 1) */ int rm_at_exit(function) exitlist_fn function; { - ele_p *epp, ep; - int count; + struct exitlist *ep; - count = 0; - epp = &exit_list; - ep = *epp; - while (ep) { + TAILQ_FOREACH(ep, &exit_list, next) { if (ep->function == function) { - *epp = ep->next; - free(ep, M_TEMP); - count++; - } else { - epp = &ep->next; + TAILQ_REMOVE(&exit_list, ep, next); + free(ep, M_ATEXIT); + return(1); } - ep = *epp; - } - return (count); + } + return (0); } void check_sigacts (void) diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 9268592a1cc..c12c965f7b6 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -65,6 +65,8 @@ #include +static MALLOC_DEFINE(M_ATFORK, "atfork", "atfork callback"); + static int fast_vfork = 1; SYSCTL_INT(_kern, OID_AUTO, fast_vfork, CTLFLAG_RW, &fast_vfork, 0, ""); @@ -72,12 +74,13 @@ SYSCTL_INT(_kern, OID_AUTO, fast_vfork, CTLFLAG_RW, &fast_vfork, 0, ""); * These are the stuctures used to create a callout list for things to do * when forking a process */ -typedef struct fork_list_element { - struct fork_list_element *next; +struct forklist { forklist_fn function; -} *fle_p; + TAILQ_ENTRY(forklist) next; +}; -static fle_p fork_list; +TAILQ_HEAD(forklist_head, forklist); +static struct forklist_head fork_list = TAILQ_HEAD_INITIALIZER(fork_list); #ifndef _SYS_SYSPROTO_H_ struct fork_args { @@ -150,9 +153,7 @@ fork1(p1, flags, procp) struct proc *newproc; int count; static int pidchecked = 0; - fle_p ep ; - - ep = fork_list; + struct forklist *ep; if ((flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) return (EINVAL); @@ -461,9 +462,8 @@ fork1(p1, flags, procp) * to adjust anything. * What if they have an error? XXX */ - while (ep) { + TAILQ_FOREACH(ep, &fork_list, next) { (*ep->function)(p1, p2, flags); - ep = ep->next; } /* @@ -505,48 +505,44 @@ fork1(p1, flags, procp) * However first make sure that it's not already there. * Returns 0 on success or a standard error number. */ + int at_fork(function) forklist_fn function; { - fle_p ep; + struct forklist *ep; +#ifdef INVARIANTS /* let the programmer know if he's been stupid */ if (rm_at_fork(function)) - printf("fork callout entry already present\n"); - ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); + printf("WARNING: fork callout entry (%p) already present\n", + function); +#endif + ep = malloc(sizeof(*ep), M_ATFORK, M_NOWAIT); if (ep == NULL) return (ENOMEM); - ep->next = fork_list; ep->function = function; - fork_list = ep; + TAILQ_INSERT_TAIL(&fork_list, ep, next); return (0); } /* - * Scan the exit callout list for the given items and remove them. - * Returns the number of items removed. - * Theoretically this value can only be 0 or 1. + * Scan the exit callout list for the given item and remove it.. + * Returns the number of items removed (0 or 1) */ + int rm_at_fork(function) forklist_fn function; { - fle_p *epp, ep; - int count; + struct forklist *ep; - count= 0; - epp = &fork_list; - ep = *epp; - while (ep) { + TAILQ_FOREACH(ep, &fork_list, next) { if (ep->function == function) { - *epp = ep->next; - free(ep, M_TEMP); - count++; - } else { - epp = &ep->next; + TAILQ_REMOVE(&fork_list, ep, next); + free(ep, M_ATFORK); + return(1); } - ep = *epp; - } - return (count); + } + return (0); } -- 2.45.2