2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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
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>
42 #include <sys/vmmeter.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
60 mpipe_init(malloc_pipe_t mpipe
, malloc_type_t type
, int bytes
,
62 int mpflags
, void (*deconstruct
)(struct malloc_pipe
*, void *))
69 nmax
= 0x7FFF0000; /* some very large number */
72 bzero(mpipe
, sizeof(struct malloc_pipe
));
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
,
86 while (mpipe
->free_count
< nnom
) {
87 n
= mpipe
->free_count
;
88 mpipe
->array
[n
] = kmalloc(bytes
, mpipe
->type
, M_WAITOK
| mpipe
->mflags
);
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.
100 mpipe_done(malloc_pipe_t mpipe
)
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;
117 kfree(mpipe
->array
, M_MPIPEARY
);
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.
129 mpipe_alloc_nowait(malloc_pipe_t mpipe
)
135 if ((n
= mpipe
->free_count
) != 0) {
137 * Use a free entry if it exists.
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
150 * Otherwise try to malloc() non-blocking.
152 buf
= kmalloc(mpipe
->bytes
, mpipe
->type
, M_NOWAIT
| mpipe
->mflags
);
154 ++mpipe
->total_count
;
161 * Allocate an entry, block until the allocation succeeds. This may cause
162 * us to block waiting for a prior allocation to be freed.
165 mpipe_alloc_waitok(malloc_pipe_t mpipe
)
174 if ((n
= mpipe
->free_count
) != 0) {
176 * Use a free entry if it exists.
179 buf
= mpipe
->array
[n
];
180 mpipe
->array
[n
] = NULL
;
181 mpipe
->free_count
= n
;
184 if (mpipe
->total_count
>= mpipe
->max_count
|| mfailed
) {
186 * Block if we have hit our limit
189 tsleep(mpipe
, 0, "mpipe1", 0);
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
);
198 ++mpipe
->total_count
;
208 * Free an entry, unblock any waiters. Allow NULL.
211 mpipe_free(malloc_pipe_t mpipe
, void *buf
)
219 if ((n
= mpipe
->free_count
) < mpipe
->ary_count
) {
221 * Free slot available in free array (LIFO)
223 mpipe
->array
[n
] = buf
;
225 if ((mpipe
->mpflags
& (MPF_CACHEDATA
|MPF_NOZERO
)) == 0)
226 bzero(buf
, mpipe
->bytes
);
230 * Wakeup anyone blocked in mpipe_alloc_*().
232 if (mpipe
->pending
) {
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
);
245 kfree(buf
, mpipe
->type
);