Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/subr_pool.c,v retrieving revision 1.67 retrieving revision 1.68 diff -u -p -r1.67 -r1.68 --- src/sys/kern/subr_pool.c 2002/03/08 20:51:26 1.67 +++ src/sys/kern/subr_pool.c 2002/03/08 21:41:59 1.68 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_pool.c,v 1.67 2002/03/08 20:51:26 thorpej Exp $ */ +/* $NetBSD: subr_pool.c,v 1.68 2002/03/08 21:41:59 thorpej Exp $ */ /*- * Copyright (c) 1997, 1999, 2000 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.67 2002/03/08 20:51:26 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.68 2002/03/08 21:41:59 thorpej Exp $"); #include "opt_pool.h" #include "opt_poollog.h" @@ -456,6 +456,8 @@ pool_init(struct pool *pp, size_t size, pp->pr_hardlimit_ratecap.tv_usec = 0; pp->pr_hardlimit_warning_last.tv_sec = 0; pp->pr_hardlimit_warning_last.tv_usec = 0; + pp->pr_drain_hook = NULL; + pp->pr_drain_hook_arg = NULL; /* * Decide whether to put the page header off page to avoid @@ -596,6 +598,19 @@ pool_destroy(struct pool *pp) #endif } +void +pool_set_drain_hook(struct pool *pp, void (*fn)(void *, int), void *arg) +{ + + /* XXX no locking -- must be used just after pool_init() */ +#ifdef DIAGNOSTIC + if (pp->pr_drain_hook != NULL) + panic("pool_set_drain_hook(%s): already set", pp->pr_wchan); +#endif + pp->pr_drain_hook = fn; + pp->pr_drain_hook_arg = arg; +} + static __inline struct pool_item_header * pool_alloc_item_header(struct pool *pp, caddr_t storage, int flags) { @@ -663,6 +678,21 @@ pool_get(struct pool *pp, int flags) } #endif if (__predict_false(pp->pr_nout == pp->pr_hardlimit)) { + if (pp->pr_drain_hook != NULL) { + /* + * Since the drain hook is going to free things + * back to the pool, unlock, call the hook, re-lock, + * and check the hardlimit condition again. + */ + pr_leave(pp); + simple_unlock(&pp->pr_slock); + (*pp->pr_drain_hook)(pp->pr_drain_hook_arg, flags); + simple_lock(&pp->pr_slock); + pr_enter(pp, file, line); + if (pp->pr_nout < pp->pr_hardlimit) + goto startover; + } + if ((flags & PR_WAITOK) && !(flags & PR_LIMITFAIL)) { /* * XXX: A warning isn't logged in this case. Should @@ -1264,9 +1294,17 @@ pool_reclaim(struct pool *pp) if (pp->pr_roflags & PR_STATIC) return (0); + if (pp->pr_drain_hook != NULL) { + /* + * The drain hook must be called with the pool unlocked. + */ + (*pp->pr_drain_hook)(pp->pr_drain_hook_arg, PR_NOWAIT); + } + if (simple_lock_try(&pp->pr_slock) == 0) return (0); pr_enter(pp, file, line); + TAILQ_INIT(&pq); /* @@ -1899,8 +1937,20 @@ pool_allocator_alloc(struct pool *org, i do { if ((res = (*pa->pa_alloc)(org, flags)) != NULL) return (res); - if ((flags & PR_WAITOK) == 0) + if ((flags & PR_WAITOK) == 0) { + /* + * We only run the drain hookhere if PR_NOWAIT. + * In other cases, the hook will be run in + * pool_reclaim(). + */ + if (org->pr_drain_hook != NULL) { + (*org->pr_drain_hook)(org->pr_drain_hook_arg, + flags); + if ((res = (*pa->pa_alloc)(org, flags)) != NULL) + return (res); + } break; + } /* * Drain all pools, except "org", that use this @@ -1913,6 +1963,9 @@ pool_allocator_alloc(struct pool *org, i * other way to have potentially sleeping pool_reclaim, * non-sleeping locks on pool_allocator, and some * stirring of drained pools in the allocator. + * + * XXX Maybe we should use pool_head_slock for locking + * the allocators? */ freed = 0;