static void pool_print1(struct pool *, const char *, int (*)(const char *, ...));
void pool_print1(struct pool *, const char *, int (*)(const char *, ...));
TAILQ_HEAD(,pool) pool_head = TAILQ_HEAD_INITIALIZER(pool_head);/* Private pool for page header structures */static struct pool phpool;/* # of seconds to retain page after last use */int pool_inactive_time = 10;/* Next candidate for drainage (see pool_drain()) */static struct pool	*drainpp;/* This spin lock protects both pool_head and drainpp. */struct simplelock pool_head_slock = SIMPLELOCK_INITIALIZER;struct pool_item_header {	/* Page headers */	TAILQ_ENTRY(pool_item_header)				ph_pagelist;	/* pool page list */	TAILQ_HEAD(,pool_item)	ph_itemlist;	/* chunk list for this page */	LIST_ENTRY(pool_item_header)				ph_hashlist;	/* Off-page page headers */	int			ph_nmissing;	/* # of chunks in use */	caddr_t			ph_page;	/* this page's address */	struct timeval		ph_time;	/* last referenced */};TAILQ_HEAD(pool_pagelist,pool_item_header);struct pool_item {#ifdef DIAGNOSTIC	int pi_magic;#endif#define	PI_MAGIC 0xdeadbeef	/* Other entries use only this list entry */	TAILQ_ENTRY(pool_item)	pi_list;};#define	PR_HASH_INDEX(pp,addr) \	(((u_long)(addr) >> (pp)->pr_alloc->pa_pageshift) & (PR_HASHTABSIZE - 1))#define	POOL_NEEDS_CATCHUP(pp)						\	((pp)->pr_nitems < (pp)->pr_minitems)/* * Every pool get a unique serial number assigned to it. If this counter * wraps, we're screwed, but we shouldn't create so many pools anyway. */unsigned int pool_serial;/* * Pool cache management. * * Pool caches provide a way for constructed objects to be cached by the * pool subsystem.  This can lead to performance improvements by avoiding * needless object construction/destruction; it is deferred until absolutely * necessary. * * Caches are grouped into cache groups.  Each cache group references * up to 16 constructed objects.  When a cache allocates an object * from the pool, it calls the object's constructor and places it into * a cache group.  When a cache group frees an object back to the pool, * it first calls the object's destructor.  This allows the object to * persist in constructed form while freed to the cache. * * Multiple caches may exist for each pool.  This allows a single * object type to have multiple constructed forms.  The pool references * each cache, so that when a pool is drained by the pagedaemon, it can * drain each individual cache as well.  Each time a cache is drained, * the most idle cache group is freed to the pool in its entirety. * * Pool caches are layed on top of pools.  By layering them, we can avoid * the complexity of cache management for pools which would not benefit * from it. *//* The cache group pool. */static struct pool pcgpool;/* The pool cache group. */#define	PCG_NOBJECTS		16struct pool_cache_group {	TAILQ_ENTRY(pool_cache_group)		pcg_list;	/* link in the pool cache's group list */	u_int	pcg_avail;	/* # available objects */				/* pointers to the objects */	void	*pcg_objects[PCG_NOBJECTS];};static void	pool_cache_reclaim(struct pool_cache *);static int	pool_catchup(struct pool *);static void	pool_prime_page(struct pool *, caddr_t,		    struct pool_item_header *);void *pool_allocator_alloc(struct pool *, int);void pool_allocator_free(struct pool *, void *);static void pool_print1(struct pool *, const char *,	int (*)(const char *, ...));/* * Pool log entry. An array of these is allocated in pool_init(). */struct pool_log {	const char	*pl_file;	long		pl_line;	int		pl_action;#define	PRLOG_GET	1#define	PRLOG_PUT	2	void		*pl_addr;};/* Number of entries in pool log buffers */#ifndef POOL_LOGSIZE#define	POOL_LOGSIZE	10#endifint pool_logsize = POOL_LOGSIZE;#ifdef POOL_DIAGNOSTICstatic __inline voidpr_log(struct pool *pp, void *v, int action, const char *file, long line){	int n = pp->pr_curlogentry;	struct pool_log *pl;	if ((pp->pr_roflags & PR_LOGGING) == 0)		return;	/*	 * Fill in the current entry. Wrap around and overwrite	 * the oldest entry if necessary.	 */	pl = &pp->pr_log[n];	pl->pl_file = file;	pl->pl_line = line;	pl->pl_action = action;	pl->pl_addr = v;	if (++n >= pp->pr_logsize)		n = 0;	pp->pr_curlogentry = n;}static voidpr_printlog(struct pool *pp, struct pool_item *pi,    int (*pr)(const char *, ...)){	int i = pp->pr_logsize;	int n = pp->pr_curlogentry;	if ((pp->pr_roflags & PR_LOGGING) == 0)		return;	/*	 * Print all entries in this pool's log.	 */	while (i-- > 0) {		struct pool_log *pl = &pp->pr_log[n];		if (pl->pl_action != 0) {			if (pi == NULL || pi == pl->pl_addr) {				(*pr)("\tlog entry %d:\n", i);				(*pr)("\t\taction = %s, addr = %p\n",				    pl->pl_action == PRLOG_GET ? "get" : "put",				    pl->pl_addr);				(*pr)("\t\tfile: %s at line %lu\n",				    pl->pl_file, pl->pl_line);			}		}		if (++n >= pp->pr_logsize)			n = 0;	}}static __inline voidpr_enter(struct pool *pp, const char *file, long line){	if (__predict_false(pp->pr_entered_file != NULL)) {		printf("pool %s: reentrancy at file %s line %ld\n",		    pp->pr_wchan, file, line);		printf("         previous entry at file %s line %ld\n",		    pp->pr_entered_file, pp->pr_entered_line);		panic("pr_enter");	}	pp->pr_entered_file = file;	pp->pr_entered_line = line;}static __inline voidpr_leave(struct pool *pp){	if (__predict_false(pp->pr_entered_file == NULL)) {		printf("pool %s not entered?\n", pp->pr_wchan);		panic("pr_leave");	}	pp->pr_entered_file = NULL;	pp->pr_entered_line = 0;}static __inline voidpr_enter_check(struct pool *pp, int (*pr)(const char *, ...)){	if (pp->pr_entered_file != NULL)		(*pr)("\n\tcurrently entered from file %s line %ld\n",		    pp->pr_entered_file, pp->pr_entered_line);}#else#define	pr_log(pp, v, action, file, line)#define	pr_printlog(pp, pi, pr)#define	pr_enter(pp, file, line)#define	pr_leave(pp)#define	pr_enter_check(pp, pr)#endif /* POOL_DIAGNOSTIC *//* * Return the pool page header based on page address. */static __inline struct pool_item_header *pr_find_pagehead(struct pool *pp, caddr_t page){	struct pool_item_header *ph;	if ((pp->pr_roflags & PR_PHINPAGE) != 0)		return ((struct pool_item_header *)(page + pp->pr_phoffset));	for (ph = LIST_FIRST(&pp->pr_hashtab[PR_HASH_INDEX(pp, page)]);	     ph != NULL;	     ph = LIST_NEXT(ph, ph_hashlist)) {		if (ph->ph_page == page)			return (ph);	}	return (NULL);}