File:  [DragonFly] / src / sys / kern / kern_mpipe.c
Revision 1.2: download - view: text, annotated - select for diffs
Tue Jan 20 05:04:06 2004 UTC (10 years, 7 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Retool the M_* flags to malloc() and the VM_ALLOC_* flags to
vm_page_alloc(), and vm_page_grab() and friends.

The M_* flags now have more flexibility, with the intent that we will start
using some of it to deal with NULL pointer return problems in the codebase
(CAM is especially bad at dealing with unexpected return values).  In
particular, add M_USE_INTERRUPT_RESERVE and M_FAILSAFE, and redefine
M_NOWAIT as a combination of M_ flags instead of its own flag.

The VM_ALLOC_* macros are now flags (0x01, 0x01, 0x04) rather then states
(1, 2, 3), which allows us to create combinations that the old interface
could not handle.

    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: