4 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
6 * This code is derived from software contributed to The DragonFly Project
7 * by Matthew Dillon <dillon@backplane.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
17 * the documentation and/or other materials provided with the
19 * 3. Neither the name of The DragonFly Project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific, prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/slaballoc.h>
42 #include <sys/vmmeter.h>
44 #include <sys/thread.h>
45 #include <sys/globaldata.h>
46 #include <sys/mpipe.h>
47 #include <sys/thread2.h>
49 #define arysize(ary) (sizeof(ary)/sizeof((ary)[0]))
51 static MALLOC_DEFINE(M_MPIPEARY, "MPipe Array", "Auxillary MPIPE structure");
54 * Initialize a malloc pipeline for the specified malloc type and allocation
55 * size. Create an array to cache up to nom_count buffers and preallocate
59 mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
62 void (*construct)(void *, void *),
63 void (*deconstruct)(void *, void *),
71 nmax = 0x7FFF0000; /* some very large number */
74 bzero(mpipe, sizeof(struct malloc_pipe));
77 mpipe->mpflags = mpflags;
78 mpipe->construct = construct;
79 mpipe->deconstruct = deconstruct;
81 if ((mpflags & MPF_NOZERO) == 0)
82 mpipe->mflags |= M_ZERO;
83 if (mpflags & MPF_INT)
84 mpipe->mflags |= M_USE_RESERVE | M_USE_INTERRUPT_RESERVE;
85 mpipe->ary_count = nnom;
86 mpipe->max_count = nmax;
87 mpipe->array = kmalloc(nnom * sizeof(mpipe->array[0]), M_MPIPEARY,
90 while (mpipe->free_count < nnom) {
91 n = mpipe->free_count;
92 mpipe->array[n] = kmalloc(bytes, mpipe->type, M_WAITOK | mpipe->mflags);
94 construct(mpipe->array[n], priv);
99 lwkt_token_init(&mpipe->token, 1, "mpipe token");
103 * Destroy a previously initialized mpipe. This routine can also safely be
104 * called on an uninitialized mpipe structure if it was zero'd or mpipe_done()
105 * was previously called on it.
108 mpipe_done(malloc_pipe_t mpipe)
113 KKASSERT(mpipe->free_count == mpipe->total_count); /* no outstanding mem */
114 for (n = mpipe->free_count - 1; n >= 0; --n) {
115 buf = mpipe->array[n];
116 mpipe->array[n] = NULL;
117 KKASSERT(buf != NULL);
118 if (mpipe->deconstruct)
119 mpipe->deconstruct(buf, mpipe->priv);
120 kfree(buf, mpipe->type);
122 mpipe->free_count = 0;
123 mpipe->total_count = 0;
125 kfree(mpipe->array, M_MPIPEARY);
129 lwkt_token_uninit(&mpipe->token);
133 * Allocate an entry, nominally non-blocking. The allocation is guarenteed
134 * to return non-NULL up to the nominal count after which it may return NULL.
135 * Note that the implementation is defined to be allowed to block for short
136 * periods of time. Use mpipe_alloc_waitok() to guarentee the allocation.
139 mpipe_alloc_nowait(malloc_pipe_t mpipe)
144 lwkt_gettoken(&mpipe->token);
145 if ((n = mpipe->free_count) != 0) {
147 * Use a free entry if it exists.
150 buf = mpipe->array[n];
151 mpipe->array[n] = NULL; /* sanity check, not absolutely needed */
152 mpipe->free_count = n;
153 } else if (mpipe->total_count >= mpipe->max_count) {
155 * Return NULL if we have hit our limit
160 * Otherwise try to malloc() non-blocking.
162 buf = kmalloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
164 ++mpipe->total_count;
165 if (mpipe->construct)
166 mpipe->construct(buf, mpipe->priv);
169 lwkt_reltoken(&mpipe->token);
174 * Allocate an entry, block until the allocation succeeds. This may cause
175 * us to block waiting for a prior allocation to be freed.
178 mpipe_alloc_waitok(malloc_pipe_t mpipe)
184 lwkt_gettoken(&mpipe->token);
187 if ((n = mpipe->free_count) != 0) {
189 * Use a free entry if it exists.
192 buf = mpipe->array[n];
193 mpipe->array[n] = NULL;
194 mpipe->free_count = n;
197 if (mpipe->total_count >= mpipe->max_count || mfailed) {
199 * Block if we have hit our limit
202 tsleep(mpipe, 0, "mpipe1", 0);
206 * Otherwise try to malloc() non-blocking. If that fails loop to
207 * recheck, and block instead of trying to malloc() again.
209 buf = kmalloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
211 ++mpipe->total_count;
212 if (mpipe->construct)
213 mpipe->construct(buf, mpipe->priv);
218 lwkt_reltoken(&mpipe->token);
223 * Free an entry, unblock any waiters. Allow NULL.
226 mpipe_free(malloc_pipe_t mpipe, void *buf)
233 lwkt_gettoken(&mpipe->token);
234 if ((n = mpipe->free_count) < mpipe->ary_count) {
236 * Free slot available in free array (LIFO)
238 mpipe->array[n] = buf;
240 if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0)
241 bzero(buf, mpipe->bytes);
242 lwkt_reltoken(&mpipe->token);
245 * Wakeup anyone blocked in mpipe_alloc_*().
247 if (mpipe->pending) {
253 * All the free slots are full, free the buffer directly.
255 --mpipe->total_count;
256 KKASSERT(mpipe->total_count >= mpipe->free_count);
257 if (mpipe->deconstruct)
258 mpipe->deconstruct(buf, mpipe->priv);
259 lwkt_reltoken(&mpipe->token);
260 kfree(buf, mpipe->type);