xref: /netbsd-src/sys/kern/subr_pool.c (revision 7c7c171d130af9949261bc7dce2150a03c3d239c)
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