1 /* 2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 * 26 * $DragonFly: src/sys/kern/kern_mpipe.c,v 1.2 2004/01/20 05:04:06 dillon Exp $ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/slaballoc.h> 33 #include <sys/mpipe.h> 34 #include <sys/mbuf.h> 35 #include <sys/vmmeter.h> 36 #include <sys/lock.h> 37 #include <sys/thread.h> 38 #include <sys/globaldata.h> 39 40 #include <sys/thread2.h> 41 42 #define arysize(ary) (sizeof(ary)/sizeof((ary)[0])) 43 44 typedef struct mpipe_buf { 45 TAILQ_ENTRY(mpipe_buf) entry; 46 } *mpipe_buf_t; 47 48 /* 49 * Initialize a malloc pipeline for the specified malloc type and allocation 50 * size, and immediately allocate nnow buffers and set the nominal maximum 51 * to nmax. 52 */ 53 void 54 mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes, 55 int nnow, int nmax) 56 { 57 if (bytes < sizeof(struct mpipe_buf)) 58 bytes = sizeof(struct mpipe_buf); 59 bzero(mpipe, sizeof(struct malloc_pipe)); 60 TAILQ_INIT(&mpipe->queue); 61 mpipe->type = type; 62 mpipe->bytes = bytes; 63 mpipe->max_count = nmax; 64 if (nnow > 0) { 65 void *buf; 66 67 buf = malloc(bytes, mpipe->type, M_WAITOK); 68 KKASSERT(buf != NULL); 69 ++mpipe->total_count; 70 mpipe_free(mpipe, buf); 71 while (--nnow > 0) { 72 buf = malloc(bytes, mpipe->type, M_SYSNOWAIT); 73 if (buf == NULL) 74 break; 75 ++mpipe->total_count; 76 mpipe_free(mpipe, buf); 77 } 78 } 79 if (mpipe->max_count < mpipe->total_count) 80 mpipe->max_count = mpipe->total_count; 81 } 82 83 void 84 mpipe_done(malloc_pipe_t mpipe) 85 { 86 struct mpipe_buf *buf; 87 88 KKASSERT(mpipe->free_count == mpipe->total_count); 89 while (mpipe->free_count) { 90 buf = TAILQ_FIRST(&mpipe->queue); 91 KKASSERT(buf != NULL); 92 TAILQ_REMOVE(&mpipe->queue, buf, entry); 93 --mpipe->free_count; 94 --mpipe->total_count; 95 free(buf, mpipe->type); 96 } 97 KKASSERT(TAILQ_EMPTY(&mpipe->queue)); 98 } 99 100 /* 101 * Allocate an entry. flags can be M_RNOWAIT which tells us not to block. 102 * Unlike a normal malloc, if we block in mpipe_alloc() no deadlock will occur 103 * because it will unblock the moment an existing in-use buffer is freed. 104 */ 105 void * 106 mpipe_alloc(malloc_pipe_t mpipe, int flags) 107 { 108 mpipe_buf_t buf; 109 110 crit_enter(); 111 while (mpipe->free_count == 0) { 112 if (mpipe->total_count < mpipe->max_count) { 113 ++mpipe->total_count; 114 if ((buf = malloc(mpipe->bytes, mpipe->type, flags)) != NULL) { 115 crit_exit(); 116 return(buf); 117 } 118 --mpipe->total_count; 119 } else if (flags & M_RNOWAIT) { 120 crit_exit(); 121 return(NULL); 122 } else { 123 mpipe->pending = 1; 124 tsleep(mpipe, 0, "mpipe", 0); 125 } 126 } 127 buf = TAILQ_FIRST(&mpipe->queue); 128 KKASSERT(buf != NULL); 129 TAILQ_REMOVE(&mpipe->queue, buf, entry); 130 --mpipe->free_count; 131 crit_exit(); 132 if (flags & M_ZERO) 133 bzero(buf, mpipe->bytes); 134 return(buf); 135 } 136 137 /* 138 * Free an entry, unblock any waiters. 139 */ 140 void 141 mpipe_free(malloc_pipe_t mpipe, void *vbuf) 142 { 143 struct mpipe_buf *buf; 144 145 if ((buf = vbuf) != NULL) { 146 crit_enter(); 147 if (mpipe->total_count > mpipe->max_count) { 148 --mpipe->total_count; 149 crit_exit(); 150 free(buf, mpipe->type); 151 } else { 152 TAILQ_INSERT_TAIL(&mpipe->queue, buf, entry); 153 ++mpipe->free_count; 154 crit_exit(); 155 if (mpipe->free_count >= (mpipe->total_count >> 2) + 1) { 156 if (mpipe->trigger) { 157 mpipe->trigger(mpipe->trigger_data); 158 } 159 if (mpipe->pending) { 160 mpipe->pending = 0; 161 wakeup(mpipe); 162 } 163 } 164 } 165 } 166 } 167 168