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.
*/
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);
}
/*
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