2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $DragonFly: src/sys/kern/kern_mpipe.c,v 1.7 2004/06/04 06:56:12 dillon Exp $
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/slaballoc.h>
34 #include <sys/vmmeter.h>
36 #include <sys/thread.h>
37 #include <sys/globaldata.h>
38 #include <sys/mpipe.h>
40 #include <sys/thread2.h>
42 #define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
44 static MALLOC_DEFINE(M_MPIPEARY, "MPipe Array", "Auxillary MPIPE structure");
47 * Initialize a malloc pipeline for the specified malloc type and allocation
48 * size. Create an array to cache up to nom_count buffers and preallocate
52 mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
54 int mpflags, void (*deconstruct)(struct malloc_pipe *, void *))
61 nmax = 0x7FFF0000; /* some very large number */
64 bzero(mpipe, sizeof(struct malloc_pipe));
67 mpipe->mpflags = mpflags;
68 mpipe->deconstruct = deconstruct;
69 if ((mpflags & MPF_NOZERO) == 0)
70 mpipe->mflags |= M_ZERO;
71 if (mpflags & MPF_INT)
72 mpipe->mflags |= M_USE_RESERVE | M_USE_INTERRUPT_RESERVE;
73 mpipe->ary_count = nnom;
74 mpipe->max_count = nmax;
75 mpipe->array = malloc(nnom * sizeof(mpipe->array[0]), M_MPIPEARY,
78 while (mpipe->free_count < nnom) {
79 n = mpipe->free_count;
80 mpipe->array[n] = malloc(bytes, mpipe->type, M_WAITOK | mpipe->mflags);
87 * Destroy a previously initialized mpipe. This routine can also safely be
88 * called on an uninitialized mpipe structure if it was zero'd or mpipe_done()
89 * was previously called on it.
92 mpipe_done(malloc_pipe_t mpipe)
97 KKASSERT(mpipe->free_count == mpipe->total_count); /* no outstanding mem */
98 for (n = mpipe->free_count - 1; n >= 0; --n) {
99 buf = mpipe->array[n];
100 mpipe->array[n] = NULL;
101 KKASSERT(buf != NULL);
102 if (mpipe->deconstruct)
103 mpipe->deconstruct(mpipe, buf);
104 free(buf, mpipe->type);
106 mpipe->free_count = 0;
107 mpipe->total_count = 0;
109 free(mpipe->array, M_MPIPEARY);
115 * Allocate an entry, nominally non-blocking. The allocation is guarenteed
116 * to return non-NULL up to the nominal count after which it may return NULL.
117 * Note that the implementation is defined to be allowed to block for short
118 * periods of time. Use mpipe_alloc_waitok() to guarentee the allocation.
121 mpipe_alloc_nowait(malloc_pipe_t mpipe)
127 if ((n = mpipe->free_count) != 0) {
129 * Use a free entry if it exists.
132 buf = mpipe->array[n];
133 mpipe->array[n] = NULL; /* sanity check, not absolutely needed */
134 mpipe->free_count = n;
135 } else if (mpipe->total_count >= mpipe->max_count) {
137 * Return NULL if we have hit our limit
142 * Otherwise try to malloc() non-blocking.
144 buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
146 ++mpipe->total_count;
153 * Allocate an entry, block until the allocation succeeds. This may cause
154 * us to block waiting for a prior allocation to be freed.
157 mpipe_alloc_waitok(malloc_pipe_t mpipe)
166 if ((n = mpipe->free_count) != 0) {
168 * Use a free entry if it exists.
171 buf = mpipe->array[n];
172 mpipe->array[n] = NULL;
173 mpipe->free_count = n;
176 if (mpipe->total_count >= mpipe->max_count || mfailed) {
178 * Block if we have hit our limit
181 tsleep(mpipe, 0, "mpipe1", 0);
185 * Otherwise try to malloc() non-blocking. If that fails loop to
186 * recheck, and block instead of trying to malloc() again.
188 buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
190 ++mpipe->total_count;
200 * Free an entry, unblock any waiters. Allow NULL.
203 mpipe_free(malloc_pipe_t mpipe, void *buf)
211 if ((n = mpipe->free_count) < mpipe->ary_count) {
213 * Free slot available in free array (LIFO)
215 mpipe->array[n] = buf;
217 if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0)
218 bzero(buf, mpipe->bytes);
222 * Wakeup anyone blocked in mpipe_alloc_*().
224 if (mpipe->pending) {
230 * All the free slots are full, free the buffer directly.
232 --mpipe->total_count;
233 KKASSERT(mpipe->total_count >= mpipe->free_count);
234 if (mpipe->deconstruct)
235 mpipe->deconstruct(mpipe, buf);
237 free(buf, mpipe->type);