File:  [DragonFly] / src / sys / kern / kern_mpipe.c
Revision 1.5: download - view: text, annotated - select for diffs
Mon Mar 29 16:22:21 2004 UTC (10 years, 7 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Bring in a bunch of well tested MPIPE changes.  Preallocate a minimum
number of mpipe elements when it is initialized.  Use an array to cache
free MPIPE buffers nad remove the data structure overloading that was
previously occuring on the buffer itself.  Add a deconstructor.  Separate
the blocking and non-blocking allocation APIs into their own functions.

The new code still needs Giant, but it's getting a lot closer to being
lock free.

    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.5 2004/03/29 16:22:21 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: void
   85: mpipe_done(malloc_pipe_t mpipe)
   86: {
   87:     void *buf;
   88:     int n;
   89: 
   90:     KKASSERT(mpipe->free_count == mpipe->total_count);	/* no outstanding mem */
   91:     while (--mpipe->free_count >= 0) {
   92: 	n = mpipe->free_count;
   93: 	buf = mpipe->array[n];
   94: 	mpipe->array[n] = NULL;
   95: 	KKASSERT(buf != NULL);
   96: 	--mpipe->total_count;
   97: 	if (mpipe->deconstruct)
   98: 	    mpipe->deconstruct(mpipe, buf);
   99: 	free(buf, mpipe->type);
  100:     }
  101: }
  102: 
  103: /*
  104:  * Allocate an entry, nominally non-blocking.  The allocation is guarenteed
  105:  * to return non-NULL up to the nominal count after which it may return NULL.
  106:  * Note that the implementation is defined to be allowed to block for short
  107:  * periods of time.  Use mpipe_alloc_waitok() to guarentee the allocation.
  108:  */
  109: void *
  110: mpipe_alloc_nowait(malloc_pipe_t mpipe)
  111: {
  112:     void *buf;
  113:     int n;
  114: 
  115:     crit_enter();
  116:     if ((n = mpipe->free_count) != 0) {
  117: 	/*
  118: 	 * Use a free entry if it exists.
  119: 	 */
  120: 	--n;
  121: 	buf = mpipe->array[n];
  122: 	mpipe->array[n] = NULL;	/* sanity check, not absolutely needed */
  123: 	mpipe->free_count = n;
  124:     } else if (mpipe->total_count >= mpipe->max_count) {
  125: 	/*
  126: 	 * Return NULL if we have hit our limit
  127: 	 */
  128: 	buf = NULL;
  129:     } else {
  130: 	/*
  131: 	 * Otherwise try to malloc() non-blocking.
  132: 	 */
  133: 	buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
  134: 	if (buf)
  135: 	    ++mpipe->total_count;
  136:     }
  137:     crit_exit();
  138:     return(buf);
  139: }
  140: 
  141: /*
  142:  * Allocate an entry, block until the allocation succeeds.  This may cause
  143:  * us to block waiting for a prior allocation to be freed.
  144:  */
  145: void *
  146: mpipe_alloc_waitok(malloc_pipe_t mpipe)
  147: {
  148:     void *buf;
  149:     int n;
  150:     int mfailed;
  151: 
  152:     crit_enter();
  153:     mfailed = 0;
  154:     for (;;) {
  155: 	if ((n = mpipe->free_count) != 0) {
  156: 	    /*
  157: 	     * Use a free entry if it exists.
  158: 	     */
  159: 	    --n;
  160: 	    buf = mpipe->array[n];
  161: 	    mpipe->array[n] = NULL;
  162: 	    mpipe->free_count = n;
  163: 	    break;
  164: 	}
  165: 	if (mpipe->total_count >= mpipe->max_count || mfailed) {
  166: 	    /*
  167: 	     * Block if we have hit our limit
  168: 	     */
  169: 	    mpipe->pending = 1;
  170: 	    tsleep(mpipe, 0, "mpipe1", 0);
  171: 	    continue;
  172: 	}
  173: 	/*
  174: 	 * Otherwise try to malloc() non-blocking.  If that fails loop to
  175: 	 * recheck, and block instead of trying to malloc() again.
  176: 	 */
  177: 	buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
  178: 	if (buf) {
  179: 	    ++mpipe->total_count;
  180: 	    break;
  181: 	}
  182: 	mfailed = 1;
  183:     }
  184:     crit_exit();
  185:     return(buf);
  186: }
  187: 
  188: /*
  189:  * Free an entry, unblock any waiters.  Allow NULL.
  190:  */
  191: void
  192: mpipe_free(malloc_pipe_t mpipe, void *buf)
  193: {
  194:     int n;
  195: 
  196:     if (buf == NULL)
  197: 	return;
  198: 
  199:     crit_enter();
  200:     if ((n = mpipe->free_count) < mpipe->ary_count) {
  201: 	/*
  202: 	 * Free slot available in free array (LIFO)
  203: 	 */
  204: 	mpipe->array[n] = buf;
  205: 	++mpipe->free_count;
  206: 	if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0) 
  207: 	    bzero(buf, mpipe->bytes);
  208: 	crit_exit();
  209: 
  210: 	/*
  211: 	 * Wakeup anyone blocked in mpipe_alloc_*().
  212: 	 */
  213: 	if (mpipe->pending) {
  214: 	    mpipe->pending = 0;
  215: 	    wakeup(mpipe);
  216: 	}
  217:     } else {
  218: 	/*
  219: 	 * All the free slots are full, free the buffer directly.
  220: 	 */
  221: 	--mpipe->total_count;
  222: 	KKASSERT(mpipe->total_count >= mpipe->free_count);
  223: 	if (mpipe->deconstruct)
  224: 	    mpipe->deconstruct(mpipe, buf);
  225: 	crit_exit();
  226: 	free(buf, mpipe->type);
  227:     }
  228: }
  229: