Home | History | Annotate | Line # | Download | only in kern
subr_pool.c revision 1.2
      1 /*	$NetBSD: subr_pool.c,v 1.2 1998/02/19 23:52:14 pk Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Paul Kranenburg.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/proc.h>
     42 #include <sys/errno.h>
     43 #include <sys/kernel.h>
     44 #include <sys/malloc.h>
     45 #include <sys/lock.h>
     46 #include <sys/pool.h>
     47 
     48 /*
     49  * Pool resource management utility.
     50  */
     51 
     52 struct pool_item {
     53 	struct pool_item	*pi_next;
     54 };
     55 
     56 
     57 struct pool *
     58 pool_create(size, nitems, wchan, mtype, storage)
     59 	size_t	size;
     60 	int	nitems;
     61 	char	*wchan;
     62 	int	mtype;
     63 	caddr_t storage;
     64 {
     65 	struct pool *pp;
     66 	caddr_t cp;
     67 
     68 	if (size < sizeof(struct pool_item)) {
     69 		printf("pool_create: size %lu too small\n", (u_long)size);
     70 		return (NULL);
     71 	}
     72 
     73 	if (storage) {
     74 		pp = (struct pool *)storage;
     75 		cp = (caddr_t)ALIGN(pp + 1);
     76 	} else {
     77 		pp = (struct pool *)malloc(sizeof(*pp), mtype, M_NOWAIT);
     78 		if (pp == NULL)
     79 			return (NULL);
     80 		cp = NULL;
     81 	}
     82 
     83 	pp->pr_freelist = NULL;
     84 	pp->pr_freecount = 0;
     85 	pp->pr_hiwat = 0;
     86 	pp->pr_flags = (storage ? PR_STATIC : 0);
     87 	pp->pr_size = size;
     88 	pp->pr_wchan = wchan;
     89 	pp->pr_mtype = mtype;
     90 	simple_lock_init(&pp->pr_lock);
     91 
     92 	if (nitems != 0) {
     93 		if (pool_prime(pp, nitems, cp) != 0) {
     94 			pool_destroy(pp);
     95 			return (NULL);
     96 		}
     97 	}
     98 
     99 	return (pp);
    100 }
    101 
    102 /*
    103  * De-commision a pool resource.
    104  */
    105 void
    106 pool_destroy(pp)
    107 	struct pool *pp;
    108 {
    109 	struct pool_item *pi;
    110 
    111 	if (pp->pr_flags & PR_STATIC)
    112 		return;
    113 
    114 	while ((pi = pp->pr_freelist) != NULL) {
    115 		pp->pr_freelist = pi->pi_next;
    116 		free(pi, pp->pr_mtype);
    117 	}
    118 	free(pp, pp->pr_mtype);
    119 }
    120 
    121 
    122 /*
    123  * Grab an item from the pool; must be called at splbio
    124  */
    125 void *
    126 pool_get(pp, flags)
    127 	struct pool *pp;
    128 	int flags;
    129 {
    130 	void *v;
    131 	struct pool_item *pi;
    132 
    133 #ifdef DIAGNOSTIC
    134 	if ((pp->pr_flags & PR_STATIC) && (flags & PR_MALLOCOK))
    135 		panic("pool_get: static");
    136 #endif
    137 
    138 again:
    139 	simple_lock(&pp->pr_lock);
    140 	if ((v = pp->pr_freelist) == NULL) {
    141 		if (flags & PR_MALLOCOK)
    142 			v = (void *)malloc(pp->pr_size, pp->pr_mtype, M_NOWAIT);
    143 
    144 		if (v == NULL) {
    145 			if ((flags & PR_WAITOK) == 0)
    146 				return (NULL);
    147 			pp->pr_flags |= PR_WANTED;
    148 			simple_unlock(&pp->pr_lock);
    149 			tsleep((caddr_t)pp, PSWP, pp->pr_wchan, 0);
    150 			goto again;
    151 		}
    152 	} else {
    153 		pi = v;
    154 		pp->pr_freelist = pi->pi_next;
    155 		pp->pr_freecount--;
    156 	}
    157 	simple_unlock(&pp->pr_lock);
    158 	return (v);
    159 }
    160 
    161 /*
    162  * Return resource to the pool; must be called at splbio
    163  */
    164 void
    165 pool_put(pp, v)
    166 	struct pool *pp;
    167 	void *v;
    168 {
    169 	struct pool_item *pi = v;
    170 
    171 	simple_lock(&pp->pr_lock);
    172 	if ((pp->pr_flags & PR_WANTED) || pp->pr_freecount < pp->pr_hiwat) {
    173 		/* Return to pool */
    174 		pi->pi_next = pp->pr_freelist;
    175 		pp->pr_freelist = pi;
    176 		pp->pr_freecount++;
    177 		if (pp->pr_flags & PR_WANTED) {
    178 			pp->pr_flags &= ~PR_WANTED;
    179 			wakeup((caddr_t)pp);
    180 		}
    181 	} else {
    182 #ifdef DIAGNOSTIC
    183 		if (pp->pr_flags & PR_STATIC) {
    184 			/* can't happen because hiwat > freecount */
    185 			panic("pool_put: static");
    186 		}
    187 #endif
    188 		/* Return to system */
    189 		free(v, M_DEVBUF);
    190 
    191 		/*
    192 		 * Return any excess items allocated during periods of
    193 		 * contention.
    194 		 */
    195 		while (pp->pr_freecount > pp->pr_hiwat) {
    196 			pi = pp->pr_freelist;
    197 			pp->pr_freelist = pi->pi_next;
    198 			pp->pr_freecount--;
    199 			free(pi, M_DEVBUF);
    200 		}
    201 	}
    202 	simple_unlock(&pp->pr_lock);
    203 }
    204 
    205 /*
    206  * Add N items to the pool
    207  */
    208 int
    209 pool_prime(pp, n, storage)
    210 	struct pool *pp;
    211 	int n;
    212 	caddr_t storage;
    213 {
    214 	struct pool_item *pi;
    215 	caddr_t cp = storage;
    216 
    217 #ifdef DIAGNOSTIC
    218 	if (storage && !(pp->pr_flags & PR_STATIC))
    219 		panic("pool_prime: static");
    220 	/* !storage && static caught below */
    221 #endif
    222 
    223 	simple_lock(&pp->pr_lock);
    224 	pp->pr_hiwat += n;
    225 	while (n--) {
    226 		if (pp->pr_flags & PR_STATIC) {
    227 			pi = (struct pool_item *)cp;
    228 			cp = (caddr_t)ALIGN(cp + pp->pr_size);
    229 		} else
    230 			pi = malloc(pp->pr_size, pp->pr_mtype, M_NOWAIT);
    231 
    232 		if (pi == NULL) {
    233 			simple_unlock(&pp->pr_lock);
    234 			return (ENOMEM);
    235 		}
    236 
    237 		pi->pi_next = pp->pr_freelist;
    238 		pp->pr_freelist = pi;
    239 		pp->pr_freecount++;
    240 	}
    241 	simple_unlock(&pp->pr_lock);
    242 	return (0);
    243 }
    244