MFC r1.27:
[dragonfly.git] / sys / kern / kern_mpipe.c
blobb83776d62079d282f8b988020fb249de9c646620
1 /*
2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * $DragonFly: src/sys/kern/kern_mpipe.c,v 1.9 2006/09/05 00:55:45 dillon Exp $
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/slaballoc.h>
41 #include <sys/mbuf.h>
42 #include <sys/vmmeter.h>
43 #include <sys/lock.h>
44 #include <sys/thread.h>
45 #include <sys/globaldata.h>
46 #include <sys/mpipe.h>
48 #include <sys/thread2.h>
50 #define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
52 static MALLOC_DEFINE(M_MPIPEARY, "MPipe Array", "Auxillary MPIPE structure");
55 * Initialize a malloc pipeline for the specified malloc type and allocation
56 * size. Create an array to cache up to nom_count buffers and preallocate
57 * them.
59 void
60 mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
61 int nnom, int nmax,
62 int mpflags, void (*deconstruct)(struct malloc_pipe *, void *))
64 int n;
66 if (nnom < 1)
67 nnom = 1;
68 if (nmax < 0)
69 nmax = 0x7FFF0000; /* some very large number */
70 if (nmax < nnom)
71 nmax = nnom;
72 bzero(mpipe, sizeof(struct malloc_pipe));
73 mpipe->type = type;
74 mpipe->bytes = bytes;
75 mpipe->mpflags = mpflags;
76 mpipe->deconstruct = deconstruct;
77 if ((mpflags & MPF_NOZERO) == 0)
78 mpipe->mflags |= M_ZERO;
79 if (mpflags & MPF_INT)
80 mpipe->mflags |= M_USE_RESERVE | M_USE_INTERRUPT_RESERVE;
81 mpipe->ary_count = nnom;
82 mpipe->max_count = nmax;
83 mpipe->array = kmalloc(nnom * sizeof(mpipe->array[0]), M_MPIPEARY,
84 M_WAITOK | M_ZERO);
86 while (mpipe->free_count < nnom) {
87 n = mpipe->free_count;
88 mpipe->array[n] = kmalloc(bytes, mpipe->type, M_WAITOK | mpipe->mflags);
89 ++mpipe->free_count;
90 ++mpipe->total_count;
95 * Destroy a previously initialized mpipe. This routine can also safely be
96 * called on an uninitialized mpipe structure if it was zero'd or mpipe_done()
97 * was previously called on it.
99 void
100 mpipe_done(malloc_pipe_t mpipe)
102 void *buf;
103 int n;
105 KKASSERT(mpipe->free_count == mpipe->total_count); /* no outstanding mem */
106 for (n = mpipe->free_count - 1; n >= 0; --n) {
107 buf = mpipe->array[n];
108 mpipe->array[n] = NULL;
109 KKASSERT(buf != NULL);
110 if (mpipe->deconstruct)
111 mpipe->deconstruct(mpipe, buf);
112 kfree(buf, mpipe->type);
114 mpipe->free_count = 0;
115 mpipe->total_count = 0;
116 if (mpipe->array) {
117 kfree(mpipe->array, M_MPIPEARY);
118 mpipe->array = NULL;
123 * Allocate an entry, nominally non-blocking. The allocation is guarenteed
124 * to return non-NULL up to the nominal count after which it may return NULL.
125 * Note that the implementation is defined to be allowed to block for short
126 * periods of time. Use mpipe_alloc_waitok() to guarentee the allocation.
128 void *
129 mpipe_alloc_nowait(malloc_pipe_t mpipe)
131 void *buf;
132 int n;
134 crit_enter();
135 if ((n = mpipe->free_count) != 0) {
137 * Use a free entry if it exists.
139 --n;
140 buf = mpipe->array[n];
141 mpipe->array[n] = NULL; /* sanity check, not absolutely needed */
142 mpipe->free_count = n;
143 } else if (mpipe->total_count >= mpipe->max_count) {
145 * Return NULL if we have hit our limit
147 buf = NULL;
148 } else {
150 * Otherwise try to malloc() non-blocking.
152 buf = kmalloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
153 if (buf)
154 ++mpipe->total_count;
156 crit_exit();
157 return(buf);
161 * Allocate an entry, block until the allocation succeeds. This may cause
162 * us to block waiting for a prior allocation to be freed.
164 void *
165 mpipe_alloc_waitok(malloc_pipe_t mpipe)
167 void *buf;
168 int n;
169 int mfailed;
171 crit_enter();
172 mfailed = 0;
173 for (;;) {
174 if ((n = mpipe->free_count) != 0) {
176 * Use a free entry if it exists.
178 --n;
179 buf = mpipe->array[n];
180 mpipe->array[n] = NULL;
181 mpipe->free_count = n;
182 break;
184 if (mpipe->total_count >= mpipe->max_count || mfailed) {
186 * Block if we have hit our limit
188 mpipe->pending = 1;
189 tsleep(mpipe, 0, "mpipe1", 0);
190 continue;
193 * Otherwise try to malloc() non-blocking. If that fails loop to
194 * recheck, and block instead of trying to malloc() again.
196 buf = kmalloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
197 if (buf) {
198 ++mpipe->total_count;
199 break;
201 mfailed = 1;
203 crit_exit();
204 return(buf);
208 * Free an entry, unblock any waiters. Allow NULL.
210 void
211 mpipe_free(malloc_pipe_t mpipe, void *buf)
213 int n;
215 if (buf == NULL)
216 return;
218 crit_enter();
219 if ((n = mpipe->free_count) < mpipe->ary_count) {
221 * Free slot available in free array (LIFO)
223 mpipe->array[n] = buf;
224 ++mpipe->free_count;
225 if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0)
226 bzero(buf, mpipe->bytes);
227 crit_exit();
230 * Wakeup anyone blocked in mpipe_alloc_*().
232 if (mpipe->pending) {
233 mpipe->pending = 0;
234 wakeup(mpipe);
236 } else {
238 * All the free slots are full, free the buffer directly.
240 --mpipe->total_count;
241 KKASSERT(mpipe->total_count >= mpipe->free_count);
242 if (mpipe->deconstruct)
243 mpipe->deconstruct(mpipe, buf);
244 crit_exit();
245 kfree(buf, mpipe->type);