File:  [DragonFly] / src / sys / kern / kern_mpipe.c
Revision 1.6: download - view: text, annotated - select for diffs
Tue Apr 20 16:58:32 2004 UTC (9 years, 11 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
When an mpipe was being destroyed, each element in the array was being
freed, but the array itself was not.  Free the array as well.

Also do some minor tidying up of mpipe_done().

Reported-by: Craig Dooley <craig@xlnx-x.net>

    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.6 2004/04/20 16:58:32 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/mbuf.h>
   34: #include <sys/vmmeter.h>
   35: #include <sys/lock.h>
   36: #include <sys/thread.h>
   37: #include <sys/globaldata.h>
   38: #include <sys/mpipe.h>
   39: 
   40: #include <sys/thread2.h>
   41: 
   42: #define arysize(ary)	(sizeof(ary)/sizeof((ary)[0]))
   43: 
   44: static MALLOC_DEFINE(M_MPIPEARY, "MPipe Array", "Auxillary MPIPE structure");
   45: 
   46: /*
   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
   49:  * them.
   50:  */
   51: void
   52: mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
   53: 	int nnom, int nmax, 
   54: 	int mpflags, void (*deconstruct)(struct malloc_pipe *, void *))
   55: {
   56:     int n;
   57: 
   58:     if (nnom < 1)
   59: 	nnom = 1;
   60:     if (nmax < 0)
   61: 	nmax = 0x7FFF0000;	/* some very large number */
   62:     if (nmax < nnom)
   63: 	nmax = nnom;
   64:     bzero(mpipe, sizeof(struct malloc_pipe));
   65:     mpipe->type = type;
   66:     mpipe->bytes = bytes;
   67:     mpipe->mpflags = mpflags;
   68:     mpipe->deconstruct = deconstruct;
   69:     if ((mpflags & MPF_NOZERO) == 0)
   70: 	mpipe->mflags |= M_ZERO;
   71:     mpipe->ary_count = nnom;
   72:     mpipe->max_count = nmax;
   73:     mpipe->array = malloc(nnom * sizeof(mpipe->array[0]), M_MPIPEARY, 
   74: 			    M_WAITOK | M_ZERO);
   75: 
   76:     while (mpipe->free_count < nnom) {
   77: 	n = mpipe->free_count;
   78: 	mpipe->array[n] = malloc(bytes, mpipe->type, M_WAITOK | mpipe->mflags);
   79: 	++mpipe->free_count;
   80: 	++mpipe->total_count;
   81:     }
   82: }
   83: 
   84: /*
   85:  * Destroy a previously initialized mpipe.  This routine can also safely be
   86:  * called on an uninitialized mpipe structure if it was zero'd or mpipe_done()
   87:  * was previously called on it.
   88:  */
   89: void
   90: mpipe_done(malloc_pipe_t mpipe)
   91: {
   92:     void *buf;
   93:     int n;
   94: 
   95:     KKASSERT(mpipe->free_count == mpipe->total_count);	/* no outstanding mem */
   96:     for (n = mpipe->free_count - 1; n >= 0; --n) {
   97: 	buf = mpipe->array[n];
   98: 	mpipe->array[n] = NULL;
   99: 	KKASSERT(buf != NULL);
  100: 	if (mpipe->deconstruct)
  101: 	    mpipe->deconstruct(mpipe, buf);
  102: 	free(buf, mpipe->type);
  103:     }
  104:     mpipe->free_count = 0;
  105:     mpipe->total_count = 0;
  106:     if (mpipe->array) {
  107: 	free(mpipe->array, M_MPIPEARY);
  108: 	mpipe->array = NULL;
  109:     }
  110: }
  111: 
  112: /*
  113:  * Allocate an entry, nominally non-blocking.  The allocation is guarenteed
  114:  * to return non-NULL up to the nominal count after which it may return NULL.
  115:  * Note that the implementation is defined to be allowed to block for short
  116:  * periods of time.  Use mpipe_alloc_waitok() to guarentee the allocation.
  117:  */
  118: void *
  119: mpipe_alloc_nowait(malloc_pipe_t mpipe)
  120: {
  121:     void *buf;
  122:     int n;
  123: 
  124:     crit_enter();
  125:     if ((n = mpipe->free_count) != 0) {
  126: 	/*
  127: 	 * Use a free entry if it exists.
  128: 	 */
  129: 	--n;
  130: 	buf = mpipe->array[n];
  131: 	mpipe->array[n] = NULL;	/* sanity check, not absolutely needed */
  132: 	mpipe->free_count = n;
  133:     } else if (mpipe->total_count >= mpipe->max_count) {
  134: 	/*
  135: 	 * Return NULL if we have hit our limit
  136: 	 */
  137: 	buf = NULL;
  138:     } else {
  139: 	/*
  140: 	 * Otherwise try to malloc() non-blocking.
  141: 	 */
  142: 	buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
  143: 	if (buf)
  144: 	    ++mpipe->total_count;
  145:     }
  146:     crit_exit();
  147:     return(buf);
  148: }
  149: 
  150: /*
  151:  * Allocate an entry, block until the allocation succeeds.  This may cause
  152:  * us to block waiting for a prior allocation to be freed.
  153:  */
  154: void *
  155: mpipe_alloc_waitok(malloc_pipe_t mpipe)
  156: {
  157:     void *buf;
  158:     int n;
  159:     int mfailed;
  160: 
  161:     crit_enter();
  162:     mfailed = 0;
  163:     for (;;) {
  164: 	if ((n = mpipe->free_count) != 0) {
  165: 	    /*
  166: 	     * Use a free entry if it exists.
  167: 	     */
  168: 	    --n;
  169: 	    buf = mpipe->array[n];
  170: 	    mpipe->array[n] = NULL;
  171: 	    mpipe->free_count = n;
  172: 	    break;
  173: 	}
  174: 	if (mpipe->total_count >= mpipe->max_count || mfailed) {
  175: 	    /*
  176: 	     * Block if we have hit our limit
  177: 	     */
  178: 	    mpipe->pending = 1;
  179: 	    tsleep(mpipe, 0, "mpipe1", 0);
  180: 	    continue;
  181: 	}
  182: 	/*
  183: 	 * Otherwise try to malloc() non-blocking.  If that fails loop to
  184: 	 * recheck, and block instead of trying to malloc() again.
  185: 	 */
  186: 	buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
  187: 	if (buf) {
  188: 	    ++mpipe->total_count;
  189: 	    break;
  190: 	}
  191: 	mfailed = 1;
  192:     }
  193:     crit_exit();
  194:     return(buf);
  195: }
  196: 
  197: /*
  198:  * Free an entry, unblock any waiters.  Allow NULL.
  199:  */
  200: void
  201: mpipe_free(malloc_pipe_t mpipe, void *buf)
  202: {
  203:     int n;
  204: 
  205:     if (buf == NULL)
  206: 	return;
  207: 
  208:     crit_enter();
  209:     if ((n = mpipe->free_count) < mpipe->ary_count) {
  210: 	/*
  211: 	 * Free slot available in free array (LIFO)
  212: 	 */
  213: 	mpipe->array[n] = buf;
  214: 	++mpipe->free_count;
  215: 	if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0) 
  216: 	    bzero(buf, mpipe->bytes);
  217: 	crit_exit();
  218: 
  219: 	/*
  220: 	 * Wakeup anyone blocked in mpipe_alloc_*().
  221: 	 */
  222: 	if (mpipe->pending) {
  223: 	    mpipe->pending = 0;
  224: 	    wakeup(mpipe);
  225: 	}
  226:     } else {
  227: 	/*
  228: 	 * All the free slots are full, free the buffer directly.
  229: 	 */
  230: 	--mpipe->total_count;
  231: 	KKASSERT(mpipe->total_count >= mpipe->free_count);
  232: 	if (mpipe->deconstruct)
  233: 	    mpipe->deconstruct(mpipe, buf);
  234: 	crit_exit();
  235: 	free(buf, mpipe->type);
  236:     }
  237: }
  238: