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>
41 #include <sys/malloc.h>
43 #include <sys/vmmeter.h>
45 #include <sys/thread.h>
46 #include <sys/globaldata.h>
47 #include <sys/mpipe.h>
48 #include <sys/kthread.h>
50 struct mpipe_callback {
51 STAILQ_ENTRY(mpipe_callback) entry;
52 void (*func)(void *arg1, void *arg2);
57 static MALLOC_DEFINE(M_MPIPEARY, "MPipe Array", "Auxiliary MPIPE structure");
59 static void mpipe_thread(void *arg);
62 * Initialize a malloc pipeline for the specified malloc type and allocation
63 * size. Create an array to cache up to nom_count buffers and preallocate
67 mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
70 void (*construct)(void *, void *),
71 void (*deconstruct)(void *, void *),
79 nmax = 0x7FFF0000; /* some very large number */
82 bzero(mpipe, sizeof(struct malloc_pipe));
85 mpipe->mpflags = mpflags;
86 mpipe->construct = construct;
87 mpipe->deconstruct = deconstruct;
89 if ((mpflags & MPF_NOZERO) == 0)
90 mpipe->mflags |= M_ZERO;
91 if (mpflags & MPF_INT)
92 mpipe->mflags |= M_USE_RESERVE | M_USE_INTERRUPT_RESERVE;
93 mpipe->ary_count = nnom;
94 mpipe->max_count = nmax;
95 mpipe->array = kmalloc(nnom * sizeof(mpipe->array[0]), M_MPIPEARY,
98 while (mpipe->free_count < nnom) {
99 n = mpipe->free_count;
100 mpipe->array[n] = kmalloc(bytes, mpipe->type, M_WAITOK | mpipe->mflags);
102 construct(mpipe->array[n], priv);
104 ++mpipe->total_count;
106 STAILQ_INIT(&mpipe->queue);
108 lwkt_token_init(&mpipe->token, "mpipe token");
111 * Create a support thread for the mpipe queue
113 if (mpflags & MPF_CALLBACK) {
114 kthread_create(mpipe_thread, mpipe, &mpipe->thread,
115 "mpipe_%s", type->ks_shortdesc);
120 * Destroy a previously initialized mpipe. This routine can also safely be
121 * called on an uninitialized mpipe structure if it was zero'd or mpipe_done()
122 * was previously called on it.
125 mpipe_done(malloc_pipe_t mpipe)
130 KKASSERT(mpipe->free_count == mpipe->total_count); /* no outstanding mem */
133 * Clean up the kthread
135 lwkt_gettoken(&mpipe->token);
136 mpipe->mpflags |= MPF_EXITING;
137 while (mpipe->thread) {
138 wakeup(&mpipe->queue);
139 tsleep(mpipe, 0, "mpipex", 1);
143 * Clean up the mpipe buffers
145 for (n = mpipe->free_count - 1; n >= 0; --n) {
146 buf = mpipe->array[n];
147 mpipe->array[n] = NULL;
148 KKASSERT(buf != NULL);
149 if (mpipe->deconstruct)
150 mpipe->deconstruct(buf, mpipe->priv);
151 kfree(buf, mpipe->type);
153 mpipe->free_count = 0;
154 mpipe->total_count = 0;
156 kfree(mpipe->array, M_MPIPEARY);
159 lwkt_reltoken(&mpipe->token);
160 lwkt_token_uninit(&mpipe->token);
164 * mpipe support thread for request failures when mpipe_alloc_callback()
168 mpipe_thread(void *arg)
170 malloc_pipe_t mpipe = arg;
171 struct mpipe_callback *mcb;
173 lwkt_gettoken(&mpipe->token);
174 while ((mpipe->mpflags & MPF_EXITING) == 0) {
175 while (mpipe->free_count &&
176 (mcb = STAILQ_FIRST(&mpipe->queue)) != NULL) {
177 STAILQ_REMOVE(&mpipe->queue, mcb, mpipe_callback, entry);
178 mcb->func(mcb->arg1, mcb->arg2);
179 kfree(mcb, M_MPIPEARY);
181 mpipe->mpflags |= MPF_QUEUEWAIT;
182 tsleep(&mpipe->queue, 0, "wait", 0);
184 mpipe->thread = NULL;
186 lwkt_reltoken(&mpipe->token);
191 * Allocate an entry (inline suppot routine). The allocation is guarenteed
192 * to return non-NULL up to the nominal count after which it may return NULL.
193 * Note that the implementation is defined to be allowed to block for short
196 * Use mpipe_alloc_callback() for non-blocking operation with a callback
197 * Use mpipe_alloc_nowait() for non-blocking operation without a callback
198 * Use mpipe_alloc_waitok() for blocking operation & guarenteed non-NULL
202 _mpipe_alloc_locked(malloc_pipe_t mpipe, int mfailed)
207 if ((n = mpipe->free_count) != 0) {
209 * Use a free entry if it exists.
212 buf = mpipe->array[n];
213 mpipe->array[n] = NULL; /* sanity check, not absolutely needed */
214 mpipe->free_count = n;
215 } else if (mpipe->total_count >= mpipe->max_count || mfailed) {
217 * Return NULL if we have hit our limit
222 * Otherwise try to malloc() non-blocking.
224 buf = kmalloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
226 ++mpipe->total_count;
227 if (mpipe->construct)
228 mpipe->construct(buf, mpipe->priv);
235 * Nominal non-blocking mpipe allocation
238 mpipe_alloc_nowait(malloc_pipe_t mpipe)
242 lwkt_gettoken(&mpipe->token);
243 buf = _mpipe_alloc_locked(mpipe, 0);
244 lwkt_reltoken(&mpipe->token);
250 * non-blocking mpipe allocation with callback for retry.
252 * If NULL is returned func(arg) is queued and will be called back when
253 * space is likely (but not necessarily) available.
255 * If non-NULL is returned func(arg) is ignored.
258 mpipe_alloc_callback(malloc_pipe_t mpipe, void (*func)(void *arg1, void *arg2),
259 void *arg1, void *arg2)
261 struct mpipe_callback *mcb;
264 lwkt_gettoken(&mpipe->token);
265 buf = _mpipe_alloc_locked(mpipe, 0);
267 mcb = kmalloc(sizeof(*mcb), M_MPIPEARY, M_INTWAIT);
268 buf = _mpipe_alloc_locked(mpipe, 0);
273 STAILQ_INSERT_TAIL(&mpipe->queue, mcb, entry);
275 kfree(mcb, M_MPIPEARY);
278 lwkt_reltoken(&mpipe->token);
284 * This function can be called to nominally wait until resources are
285 * available and mpipe_alloc_nowait() is likely to return non-NULL.
287 * NOTE: mpipe_alloc_nowait() can still return NULL.
290 mpipe_wait(malloc_pipe_t mpipe)
292 if (mpipe->free_count == 0) {
293 lwkt_gettoken(&mpipe->token);
294 while ((mpipe->mpflags & MPF_EXITING) == 0) {
295 if (mpipe->free_count)
297 mpipe->mpflags |= MPF_QUEUEWAIT;
298 tsleep(&mpipe->queue, 0, "wait", 0);
300 lwkt_reltoken(&mpipe->token);
305 * Allocate an entry, block until the allocation succeeds. This may cause
306 * us to block waiting for a prior allocation to be freed.
309 mpipe_alloc_waitok(malloc_pipe_t mpipe)
314 lwkt_gettoken(&mpipe->token);
316 while ((buf = _mpipe_alloc_locked(mpipe, mfailed)) == NULL) {
318 * Block if we have hit our limit
321 tsleep(mpipe, 0, "mpipe1", 0);
324 lwkt_reltoken(&mpipe->token);
330 * Free an entry, unblock any waiters. Allow NULL.
333 mpipe_free(malloc_pipe_t mpipe, void *buf)
340 lwkt_gettoken(&mpipe->token);
341 if ((n = mpipe->free_count) < mpipe->ary_count) {
343 * Free slot available in free array (LIFO)
345 mpipe->array[n] = buf;
347 if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0)
348 bzero(buf, mpipe->bytes);
349 if (mpipe->mpflags & MPF_QUEUEWAIT) {
350 mpipe->mpflags &= ~MPF_QUEUEWAIT;
351 lwkt_reltoken(&mpipe->token);
352 wakeup(&mpipe->queue);
354 lwkt_reltoken(&mpipe->token);
357 * Wakeup anyone blocked in mpipe_alloc_*().
359 if (mpipe->pending) {
365 * All the free slots are full, free the buffer directly.
367 --mpipe->total_count;
368 KKASSERT(mpipe->total_count >= mpipe->free_count);
369 if (mpipe->deconstruct)
370 mpipe->deconstruct(buf, mpipe->priv);
371 lwkt_reltoken(&mpipe->token);
372 kfree(buf, mpipe->type);