Diff for /src/sys/kern/kern_mpipe.c between versions 1.4 and 1.5

version 1.4, 2004/03/29 14:16:32 version 1.5, 2004/03/29 16:22:21
Line 41 Line 41
   
 #define arysize(ary)    (sizeof(ary)/sizeof((ary)[0]))  #define arysize(ary)    (sizeof(ary)/sizeof((ary)[0]))
   
 typedef struct mpipe_buf {  static MALLOC_DEFINE(M_MPIPEARY, "MPipe Array", "Auxillary MPIPE structure");
         TAILQ_ENTRY(mpipe_buf)  entry;  
 } *mpipe_buf_t;  
   
 /*  /*
  * Initialize a malloc pipeline for the specified malloc type and allocation   * Initialize a malloc pipeline for the specified malloc type and allocation
  * size, and immediately allocate nnow buffers and set the nominal maximum   * size.  Create an array to cache up to nom_count buffers and preallocate
  * to nmax.   * them.
  */   */
 void  void
 mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,  mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes,
         int nnow, int nmax)          int nnom, int nmax, 
           int mpflags, void (*deconstruct)(struct malloc_pipe *, void *))
 {  {
     if (bytes < sizeof(struct mpipe_buf))      int n;
         bytes = sizeof(struct mpipe_buf);  
       if (nnom < 1)
           nnom = 1;
       if (nmax < 0)
           nmax = 0x7FFF0000;      /* some very large number */
       if (nmax < nnom)
           nmax = nnom;
     bzero(mpipe, sizeof(struct malloc_pipe));      bzero(mpipe, sizeof(struct malloc_pipe));
     TAILQ_INIT(&mpipe->queue);  
     mpipe->type = type;      mpipe->type = type;
     mpipe->bytes = bytes;      mpipe->bytes = bytes;
       mpipe->mpflags = mpflags;
       mpipe->deconstruct = deconstruct;
       if ((mpflags & MPF_NOZERO) == 0)
           mpipe->mflags |= M_ZERO;
       mpipe->ary_count = nnom;
     mpipe->max_count = nmax;      mpipe->max_count = nmax;
     if (nnow > 0) {      mpipe->array = malloc(nnom * sizeof(mpipe->array[0]), M_MPIPEARY, 
         void *buf;                              M_WAITOK | M_ZERO);
   
         buf = malloc(bytes, mpipe->type, M_WAITOK);      while (mpipe->free_count < nnom) {
         KKASSERT(buf != NULL);          n = mpipe->free_count;
           mpipe->array[n] = malloc(bytes, mpipe->type, M_WAITOK | mpipe->mflags);
           ++mpipe->free_count;
         ++mpipe->total_count;          ++mpipe->total_count;
         mpipe_free(mpipe, buf);  
         while (--nnow > 0) {  
             buf = malloc(bytes, mpipe->type, M_SYSNOWAIT);  
             if (buf == NULL)  
                 break;  
             ++mpipe->total_count;  
             mpipe_free(mpipe, buf);  
         }  
     }      }
     if (mpipe->max_count < mpipe->total_count)  
         mpipe->max_count = mpipe->total_count;  
 }  }
   
 void  void
 mpipe_done(malloc_pipe_t mpipe)  mpipe_done(malloc_pipe_t mpipe)
 {  {
     struct mpipe_buf *buf;      void *buf;
       int n;
   
     KKASSERT(mpipe->free_count == mpipe->total_count);      KKASSERT(mpipe->free_count == mpipe->total_count);  /* no outstanding mem */
     while (mpipe->free_count) {      while (--mpipe->free_count >= 0) {
         buf = TAILQ_FIRST(&mpipe->queue);          n = mpipe->free_count;
           buf = mpipe->array[n];
           mpipe->array[n] = NULL;
         KKASSERT(buf != NULL);          KKASSERT(buf != NULL);
         TAILQ_REMOVE(&mpipe->queue, buf, entry);  
         --mpipe->free_count;  
         --mpipe->total_count;          --mpipe->total_count;
           if (mpipe->deconstruct)
               mpipe->deconstruct(mpipe, buf);
         free(buf, mpipe->type);          free(buf, mpipe->type);
     }      }
     KKASSERT(TAILQ_EMPTY(&mpipe->queue));  
 }  }
   
 /*  /*
  * Allocate an entry.  flags can be M_RNOWAIT which tells us not to block.   * Allocate an entry, nominally non-blocking.  The allocation is guarenteed
  * Unlike a normal malloc, if we block in mpipe_alloc() no deadlock will occur   * to return non-NULL up to the nominal count after which it may return NULL.
  * because it will unblock the moment an existing in-use buffer is freed.   * Note that the implementation is defined to be allowed to block for short
    * periods of time.  Use mpipe_alloc_waitok() to guarentee the allocation.
  */   */
 void *  void *
 mpipe_alloc(malloc_pipe_t mpipe, int flags)  mpipe_alloc_nowait(malloc_pipe_t mpipe)
 {  {
     mpipe_buf_t buf;      void *buf;
       int n;
   
     crit_enter();      crit_enter();
     while (mpipe->free_count == 0) {      if ((n = mpipe->free_count) != 0) {
         if (mpipe->total_count < mpipe->max_count) {          /*
            * Use a free entry if it exists.
            */
           --n;
           buf = mpipe->array[n];
           mpipe->array[n] = NULL; /* sanity check, not absolutely needed */
           mpipe->free_count = n;
       } else if (mpipe->total_count >= mpipe->max_count) {
           /*
            * Return NULL if we have hit our limit
            */
           buf = NULL;
       } else {
           /*
            * Otherwise try to malloc() non-blocking.
            */
           buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
           if (buf)
             ++mpipe->total_count;              ++mpipe->total_count;
             if ((buf = malloc(mpipe->bytes, mpipe->type, flags)) != NULL) {      }
                 crit_exit();      crit_exit();
                 return(buf);      return(buf);
             }  }
             --mpipe->total_count;  
         } else if (flags & M_RNOWAIT) {  /*
             crit_exit();   * Allocate an entry, block until the allocation succeeds.  This may cause
             return(NULL);   * us to block waiting for a prior allocation to be freed.
         } else {   */
   void *
   mpipe_alloc_waitok(malloc_pipe_t mpipe)
   {
       void *buf;
       int n;
       int mfailed;
   
       crit_enter();
       mfailed = 0;
       for (;;) {
           if ((n = mpipe->free_count) != 0) {
               /*
                * Use a free entry if it exists.
                */
               --n;
               buf = mpipe->array[n];
               mpipe->array[n] = NULL;
               mpipe->free_count = n;
               break;
           }
           if (mpipe->total_count >= mpipe->max_count || mfailed) {
               /*
                * Block if we have hit our limit
                */
             mpipe->pending = 1;              mpipe->pending = 1;
             tsleep(mpipe, 0, "mpipe", 0);              tsleep(mpipe, 0, "mpipe1", 0);
               continue;
         }          }
           /*
            * Otherwise try to malloc() non-blocking.  If that fails loop to
            * recheck, and block instead of trying to malloc() again.
            */
           buf = malloc(mpipe->bytes, mpipe->type, M_NOWAIT | mpipe->mflags);
           if (buf) {
               ++mpipe->total_count;
               break;
           }
           mfailed = 1;
     }      }
     buf = TAILQ_FIRST(&mpipe->queue);  
     KKASSERT(buf != NULL);  
     TAILQ_REMOVE(&mpipe->queue, buf, entry);  
     --mpipe->free_count;  
     crit_exit();      crit_exit();
     if (flags & M_ZERO)  
         bzero(buf, mpipe->bytes);  
     return(buf);      return(buf);
 }  }
   
 /*  /*
  * Free an entry, unblock any waiters.   * Free an entry, unblock any waiters.  Allow NULL.
  */   */
 void  void
 mpipe_free(malloc_pipe_t mpipe, void *vbuf)  mpipe_free(malloc_pipe_t mpipe, void *buf)
 {  {
     struct mpipe_buf *buf;      int n;
   
       if (buf == NULL)
           return;
   
     if ((buf = vbuf) != NULL) {      crit_enter();
         crit_enter();      if ((n = mpipe->free_count) < mpipe->ary_count) {
         if (mpipe->total_count > mpipe->max_count) {          /*
             --mpipe->total_count;           * Free slot available in free array (LIFO)
             crit_exit();           */
             free(buf, mpipe->type);          mpipe->array[n] = buf;
         } else {          ++mpipe->free_count;
             TAILQ_INSERT_TAIL(&mpipe->queue, buf, entry);          if ((mpipe->mpflags & (MPF_CACHEDATA|MPF_NOZERO)) == 0) 
             ++mpipe->free_count;              bzero(buf, mpipe->bytes);
             crit_exit();          crit_exit();
             if (mpipe->free_count >= (mpipe->total_count >> 2) + 1) {  
                 if (mpipe->trigger) {          /*
                     mpipe->trigger(mpipe->trigger_data);           * Wakeup anyone blocked in mpipe_alloc_*().
                 }           */
                 if (mpipe->pending) {          if (mpipe->pending) {
                     mpipe->pending = 0;              mpipe->pending = 0;
                     wakeup(mpipe);              wakeup(mpipe);
                 }  
             }  
         }          }
       } else {
           /*
            * All the free slots are full, free the buffer directly.
            */
           --mpipe->total_count;
           KKASSERT(mpipe->total_count >= mpipe->free_count);
           if (mpipe->deconstruct)
               mpipe->deconstruct(mpipe, buf);
           crit_exit();
           free(buf, mpipe->type);
     }      }
 }  }
   

Removed from v.1.4  
changed lines
  Added in v.1.5