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