]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Reinstate isc_mempool
authorOndřej Surý <ondrej@sury.org>
Tue, 31 Jul 2018 10:15:22 +0000 (12:15 +0200)
committerOndřej Surý <ondrej@sury.org>
Wed, 8 Aug 2018 07:49:06 +0000 (09:49 +0200)
lib/isc/include/isc/mem.h
lib/isc/mem.c
lib/isc/tests/mem_test.c

index eaf38dc001d43f055e6a63699d37bfc64e0900f9..0b70f994081bb011981e718bb339e2ae9e619223 100644 (file)
@@ -38,7 +38,7 @@ typedef void (*isc_memfree_t)(void *, void *);
  * allocation and freeing by file and line number.
  */
 #ifndef ISC_MEM_TRACKLINES
-#define ISC_MEM_TRACKLINES 1
+#define ISC_MEM_TRACKLINES 0
 #endif
 
 /*%
index f1374295bc53189057ac444fa658cf638e807172..e9f250e83cdfa6d52dee9a52ff78e266a08bd893 100644 (file)
 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
 LIBISC_EXTERNAL_DATA unsigned int isc_mem_defaultflags = ISC_MEMFLAG_DEFAULT;
 
+typedef struct isc__mempool isc__mempool_t;
+
+typedef struct element element;
+struct element {
+       element *               next;
+};
+
+#define MEMPOOL_MAGIC          ISC_MAGIC('M', 'E', 'M', 'p')
+#define VALID_MEMPOOL(c)       ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
+
+struct isc__mempool {
+       /* always unlocked */
+       isc_mempool_t   common;         /*%< common header of mempool's */
+       isc_mutex_t    *lock;           /*%< optional lock */
+       isc_mem_t      *mctx;           /*%< our memory context */
+       /*%< locked via the memory context's lock */
+       ISC_LINK(isc__mempool_t)        link;   /*%< next pool in this mem context */
+       /*%< optionally locked from here down */
+       element        *items;          /*%< low water item list */
+       size_t          size;           /*%< size of each item on this pool */
+       unsigned int    maxalloc;       /*%< max number of items allowed */
+       unsigned int    allocated;      /*%< # of items currently given out */
+       unsigned int    freecount;      /*%< # of items on reserved list */
+       unsigned int    freemax;        /*%< # of items allowed on free list */
+       unsigned int    fillcount;      /*%< # of items to fetch on each fill */
+       /*%< Stats only. */
+       unsigned int    gets;           /*%< # of requests to this pool */
+       /*%< Debugging only. */
+#if ISC_MEMPOOL_NAMES
+       char            name[16];       /*%< printed name in stats reports */
+#endif
+};
+
 /*
  * Public.
  */
@@ -264,57 +297,210 @@ isc_mem_gettag(isc_mem_t *ctx0) {
 
 isc_result_t
 isc_mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
+       isc__mempool_t *mpctx;
+
        UNUSED(mctx0);
-       UNUSED(size);
-       UNUSED(mpctxp);
+       
+       REQUIRE(size > 0U);
+       REQUIRE(mpctxp != NULL && *mpctxp == NULL);
+
+       /*
+        * Allocate space for this pool, initialize values, and if all works
+        * well, attach to the memory context.
+        */
+       mpctx = isc_mem_get(NULL, sizeof(isc__mempool_t));
+       if (mpctx == NULL)
+               return (ISC_R_NOMEMORY);
+
+       mpctx->common.impmagic = MEMPOOL_MAGIC;
+       mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
+       mpctx->lock = NULL;
+       mpctx->mctx = NULL;
+       mpctx->size = ALIGN_TO(size, sizeof(void *));
+       mpctx->maxalloc = UINT_MAX;
+       mpctx->allocated = 0;
+       mpctx->freecount = 0;
+       mpctx->freemax = 1;
+       mpctx->fillcount = 1;
+       mpctx->gets = 0;
+#if ISC_MEMPOOL_NAMES
+       mpctx->name[0] = 0;
+#endif
+       mpctx->items = NULL;
 
-       isc_mempool_t *mpctx = calloc(1, sizeof(*mpctx));
-       REQUIRE(mpctx != NULL);
-       *mpctxp = (isc_mempool_t *)mpctx;       
+       *mpctxp = (isc_mempool_t *)mpctx;
 
-       mpctx->size = ALIGN_TO(size, sizeof(void *));
-       REQUIRE((isc_refcount_init(&mpctx->allocated, 0)) == ISC_R_SUCCESS);
-       
        return (ISC_R_SUCCESS);
 }
 
 void
 isc_mempool_setname(isc_mempool_t *mpctx0, const char *name) {
-       UNUSED(mpctx0);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+       REQUIRE(name != NULL);
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+#if ISC_MEMPOOL_NAMES
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       strlcpy(mpctx->name, name, sizeof(mpctx->name));
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+#else
+       UNUSED(mpctx);
        UNUSED(name);
+#endif
 }
 
 void
 isc_mempool_destroy(isc_mempool_t **mpctxp) {
-       isc_mempool_t *mpctx = (isc_mempool_t *)*mpctxp;
+       isc__mempool_t *mpctx;
+       isc_mutex_t *lock;
+       element *item;
+
+       REQUIRE(mpctxp != NULL);
+       mpctx = (isc__mempool_t *)*mpctxp;
+       REQUIRE(VALID_MEMPOOL(mpctx));
+#if ISC_MEMPOOL_NAMES
+       if (mpctx->allocated > 0)
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc__mempool_destroy(): mempool %s "
+                                "leaked memory",
+                                mpctx->name);
+#endif
+       REQUIRE(mpctx->allocated == 0);
+
+       lock = mpctx->lock;
+
+       if (lock != NULL)
+               LOCK(lock);
+
+       /*
+        * Return any items on the free list
+        */
+       while (mpctx->items != NULL) {
+               INSIST(mpctx->freecount > 0);
+               mpctx->freecount--;
+               item = mpctx->items;
+               mpctx->items = item->next;
+
+               isc_mem_put(NULL, item, mpctx->size);
+       }
+
+       mpctx->common.impmagic = 0;
+       mpctx->common.magic = 0;
+
+       isc_mem_put(NULL, mpctx, sizeof(isc__mempool_t));
+
+       if (lock != NULL)
+               UNLOCK(lock);
 
-       isc_refcount_destroy(&mpctx->allocated);
-       isc_mem_free(NULL, mpctx);
        *mpctxp = NULL;
 }
 
 void
 isc_mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
-       UNUSED(mpctx0);
-       UNUSED(lock);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+       REQUIRE(mpctx->lock == NULL);
+       REQUIRE(lock != NULL);
+
+       mpctx->lock = lock;
 }
 
 void *
 isc_mempool_get(isc_mempool_t *mpctx0) {
-       unsigned int refs;
-       void *ret = isc_mem_allocate(NULL, mpctx0->size);
-       REQUIRE(ret != NULL);
-       isc_refcount_increment0(&mpctx0->allocated, &refs);
-       return (ret);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+       element *item;
+       unsigned int i;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       /*
+        * Don't let the caller go over quota
+        */
+       if (ISC_UNLIKELY(mpctx->allocated >= mpctx->maxalloc)) {
+               item = NULL;
+               goto out;
+       }
+
+       if (ISC_UNLIKELY(mpctx->items == NULL)) {
+               /*
+                * We need to dip into the well.  Lock the memory context
+                * here and fill up our free list.
+                */
+               for (i = 0; i < mpctx->fillcount; i++) {
+                       item = isc_mem_get(NULL, mpctx->size);
+                       item->next = mpctx->items;
+                       mpctx->items = item;
+                       mpctx->freecount++;
+               }
+       }
+
+       /*
+        * If we didn't get any items, return NULL.
+        */
+       item = mpctx->items;
+       if (ISC_UNLIKELY(item == NULL))
+               goto out;
+
+       mpctx->items = item->next;
+       INSIST(mpctx->freecount > 0);
+       mpctx->freecount--;
+       mpctx->gets++;
+       mpctx->allocated++;
+
+ out:
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (item);
 }
 
 /* coverity[+free : arg-1] */
 void
 isc_mempool_put(isc_mempool_t *mpctx0, void *mem) {
-       unsigned int refs;
-       isc_mem_free(NULL, mem);
-       isc_refcount_decrement(&mpctx0->allocated, &refs);
-       REQUIRE(refs >= 0);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+       element *item;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (ISC_UNLIKELY(mem == NULL)) {
+               return;
+       }
+       
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       INSIST(mpctx->allocated > 0);
+       mpctx->allocated--;
+
+       /*
+        * If our free list is full, return this to the mctx directly.
+        */
+       if (mpctx->freecount >= mpctx->freemax) {
+               isc_mem_put(NULL, mem, mpctx->size);
+               if (mpctx->lock != NULL)
+                       UNLOCK(mpctx->lock);
+               return;
+       }
+
+       /*
+        * Otherwise, attach it to our free list and bump the counter.
+        */
+       mpctx->freecount++;
+       item = (element *)mem;
+       item->next = mpctx->items;
+       mpctx->items = item;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
 }
 
 /*
@@ -323,51 +509,141 @@ isc_mempool_put(isc_mempool_t *mpctx0, void *mem) {
 
 void
 isc_mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
-       UNUSED(mpctx0);
-       UNUSED(limit);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       mpctx->freemax = limit;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
 }
 
 unsigned int
 isc_mempool_getfreemax(isc_mempool_t *mpctx0) {
-       UNUSED(mpctx0);
-       return (0);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+       unsigned int freemax;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       freemax = mpctx->freemax;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (freemax);
 }
 
 unsigned int
 isc_mempool_getfreecount(isc_mempool_t *mpctx0) {
-       UNUSED(mpctx0);
-       return (1);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+       unsigned int freecount;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       freecount = mpctx->freecount;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (freecount);
 }
 
 void
 isc_mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
-       UNUSED(mpctx0);
-       UNUSED(limit);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+       REQUIRE(limit > 0);
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       mpctx->maxalloc = limit;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
 }
 
 unsigned int
 isc_mempool_getmaxalloc(isc_mempool_t *mpctx0) {
-       UNUSED(mpctx0);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+       unsigned int maxalloc;
 
-       return (0);
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       maxalloc = mpctx->maxalloc;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (maxalloc);
 }
 
 unsigned int
 isc_mempool_getallocated(isc_mempool_t *mpctx0) {
-       return (isc_refcount_current(&mpctx0->allocated));
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+       unsigned int allocated;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       allocated = mpctx->allocated;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (allocated);
 }
 
 void
 isc_mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
-       UNUSED(mpctx0);
-       UNUSED(limit);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
+
+       REQUIRE(limit > 0);
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       mpctx->fillcount = limit;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
 }
 
 unsigned int
 isc_mempool_getfillcount(isc_mempool_t *mpctx0) {
-       UNUSED(mpctx0);
+       isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
 
-       return (0);
+       unsigned int fillcount;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       fillcount = mpctx->fillcount;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (fillcount);
 }
 
 void
index a7d54bcf8775cfffa3db44a67f830fa1b66bb4ab..6c5222ffbed66bdfffa472e94cf51f8e39783691 100644 (file)
@@ -88,7 +88,7 @@ ATF_TC_BODY(isc_mem, tc) {
         * Try to allocate one more.  This should fail.
         */
        tmp = isc_mempool_get(mp1);
-       /* ATF_CHECK_EQ(tmp, NULL); */
+       ATF_CHECK_EQ(tmp, NULL);
        isc_mempool_put(mp1, tmp);
 
        /*
@@ -101,7 +101,7 @@ ATF_TC_BODY(isc_mem, tc) {
        }
 
        rval = isc_mempool_getfreecount(mp1);
-       ATF_CHECK_EQ(rval, 1);
+       ATF_CHECK_EQ(rval, 10);
 
        rval = isc_mempool_getallocated(mp1);
        ATF_CHECK_EQ(rval, 19);