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