📄 mem.c
字号:
/* * Perform a malloc, doing memory filling and overrun detection as necessary. */static inline void *mem_get(isc_mem_t *ctx, size_t size) { char *ret;#if ISC_MEM_CHECKOVERRUN size += 1;#endif ret = (ctx->memalloc)(ctx->arg, size); if (ret == NULL) ctx->memalloc_failures++; #if ISC_MEM_FILL if (ret != NULL) memset(ret, 0xbe, size); /* Mnemonic for "beef". */#else# if ISC_MEM_CHECKOVERRUN if (ret != NULL) ret[size-1] = 0xbe;# endif#endif return (ret);}/* * Perform a free, doing memory filling and overrun detection as necessary. */static inline voidmem_put(isc_mem_t *ctx, void *mem, size_t size) {#if ISC_MEM_CHECKOVERRUN INSIST(((unsigned char *)mem)[size] == 0xbe);#endif#if ISC_MEM_FILL memset(mem, 0xde, size); /* Mnemonic for "dead". */#else UNUSED(size);#endif (ctx->memfree)(ctx->arg, mem);}/* * Update internal counters after a memory get. */static inline voidmem_getstats(isc_mem_t *ctx, size_t size) { ctx->total += size; ctx->inuse += size; if (size > ctx->max_size) { ctx->stats[ctx->max_size].gets++; ctx->stats[ctx->max_size].totalgets++; } else { ctx->stats[size].gets++; ctx->stats[size].totalgets++; }}/* * Update internal counters after a memory put. */static inline voidmem_putstats(isc_mem_t *ctx, void *ptr, size_t size) { UNUSED(ptr); INSIST(ctx->inuse >= size); ctx->inuse -= size; if (size > ctx->max_size) { INSIST(ctx->stats[ctx->max_size].gets > 0U); ctx->stats[ctx->max_size].gets--; } else { INSIST(ctx->stats[size].gets > 0U); ctx->stats[size].gets--; }}#endif /* ISC_MEM_USE_INTERNAL_MALLOC *//* * Private. */static void *default_memalloc(void *arg, size_t size) { UNUSED(arg); if (size == 0U) size = 1; return (malloc(size));}static voiddefault_memfree(void *arg, void *ptr) { UNUSED(arg); free(ptr);}/* * Public. */isc_result_tisc_mem_createx(size_t init_max_size, size_t target_size, isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, isc_mem_t **ctxp){ isc_mem_t *ctx; isc_result_t result; REQUIRE(ctxp != NULL && *ctxp == NULL); REQUIRE(memalloc != NULL); REQUIRE(memfree != NULL); INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);#if !ISC_MEM_USE_INTERNAL_MALLOC UNUSED(target_size);#endif ctx = (memalloc)(arg, sizeof(*ctx)); if (ctx == NULL) return (ISC_R_NOMEMORY); if (init_max_size == 0U) ctx->max_size = DEF_MAX_SIZE; else ctx->max_size = init_max_size; ctx->references = 1; ctx->quota = 0; ctx->total = 0; ctx->inuse = 0; ctx->maxinuse = 0; ctx->hi_water = 0; ctx->lo_water = 0; ctx->hi_called = ISC_FALSE; ctx->water = NULL; ctx->water_arg = NULL; ctx->magic = MEM_MAGIC; isc_ondestroy_init(&ctx->ondestroy); ctx->memalloc = memalloc; ctx->memfree = memfree; ctx->arg = arg; ctx->stats = NULL; ctx->checkfree = ISC_TRUE;#if ISC_MEM_TRACKLINES ctx->debuglist = NULL;#endif ISC_LIST_INIT(ctx->pools);#if ISC_MEM_USE_INTERNAL_MALLOC ctx->freelists = NULL;#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ ctx->stats = (memalloc)(arg, (ctx->max_size+1) * sizeof(struct stats)); if (ctx->stats == NULL) { result = ISC_R_NOMEMORY; goto error; } memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));#if ISC_MEM_USE_INTERNAL_MALLOC if (target_size == 0) ctx->mem_target = DEF_MEM_TARGET; else ctx->mem_target = target_size; ctx->freelists = (memalloc)(arg, ctx->max_size * sizeof(element *)); if (ctx->freelists == NULL) { result = ISC_R_NOMEMORY; goto error; } memset(ctx->freelists, 0, ctx->max_size * sizeof(element *)); ctx->basic_blocks = NULL; ctx->basic_table = NULL; ctx->basic_table_count = 0; ctx->basic_table_size = 0; ctx->lowest = NULL; ctx->highest = NULL;#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ if (isc_mutex_init(&ctx->lock) != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); result = ISC_R_UNEXPECTED; goto error; }#if ISC_MEM_TRACKLINES if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { unsigned int i; ctx->debuglist = (memalloc)(arg, (ctx->max_size+1) * sizeof(debuglist_t)); if (ctx->debuglist == NULL) { result = ISC_R_NOMEMORY; goto error; } for (i = 0; i <= ctx->max_size; i++) ISC_LIST_INIT(ctx->debuglist[i]); }#endif ctx->memalloc_failures = 0; *ctxp = ctx; return (ISC_R_SUCCESS); error: if (ctx) { if (ctx->stats) (memfree)(arg, ctx->stats);#if ISC_MEM_USE_INTERNAL_MALLOC if (ctx->freelists) (memfree)(arg, ctx->freelists);#endif /* ISC_MEM_USE_INTERNAL_MALLOC */#if ISC_MEM_TRACKLINES if (ctx->debuglist) (ctx->memfree)(ctx->arg, ctx->debuglist);#endif /* ISC_MEM_TRACKLINES */ (memfree)(arg, ctx); } return (result);}isc_result_tisc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp){ return (isc_mem_createx(init_max_size, target_size, default_memalloc, default_memfree, NULL, ctxp));}static voiddestroy(isc_mem_t *ctx) { unsigned int i; isc_ondestroy_t ondest; ctx->magic = 0;#if ISC_MEM_USE_INTERNAL_MALLOC INSIST(ISC_LIST_EMPTY(ctx->pools));#endif /* ISC_MEM_USE_INTERNAL_MALLOC */#if ISC_MEM_TRACKLINES if (ctx->debuglist != NULL) { if (ctx->checkfree) { for (i = 0; i <= ctx->max_size; i++) { if (!ISC_LIST_EMPTY(ctx->debuglist[i])) print_active(ctx, stderr); INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); } } else { debuglink_t *dl; for (i = 0; i <= ctx->max_size; i++) for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); dl != NULL; dl = ISC_LIST_HEAD(ctx->debuglist[i])) { ISC_LIST_UNLINK(ctx->debuglist[i], dl, link); free(dl); } } (ctx->memfree)(ctx->arg, ctx->debuglist); }#endif INSIST(ctx->references == 0); if (ctx->checkfree) { for (i = 0; i <= ctx->max_size; i++) {#if ISC_MEM_TRACKLINES if (ctx->stats[i].gets != 0U) print_active(ctx, stderr);#endif INSIST(ctx->stats[i].gets == 0U); } } (ctx->memfree)(ctx->arg, ctx->stats);#if ISC_MEM_USE_INTERNAL_MALLOC for (i = 0; i < ctx->basic_table_count; i++) (ctx->memfree)(ctx->arg, ctx->basic_table[i]); (ctx->memfree)(ctx->arg, ctx->freelists); (ctx->memfree)(ctx->arg, ctx->basic_table);#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ ondest = ctx->ondestroy; DESTROYLOCK(&ctx->lock); (ctx->memfree)(ctx->arg, ctx); isc_ondestroy_notify(&ondest, ctx);}voidisc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { REQUIRE(VALID_CONTEXT(source)); REQUIRE(targetp != NULL && *targetp == NULL); LOCK(&source->lock); source->references++; UNLOCK(&source->lock); *targetp = source;}voidisc_mem_detach(isc_mem_t **ctxp) { isc_mem_t *ctx; isc_boolean_t want_destroy = ISC_FALSE; REQUIRE(ctxp != NULL); ctx = *ctxp; REQUIRE(VALID_CONTEXT(ctx)); LOCK(&ctx->lock); INSIST(ctx->references > 0); ctx->references--; if (ctx->references == 0) want_destroy = ISC_TRUE; UNLOCK(&ctx->lock); if (want_destroy) destroy(ctx); *ctxp = NULL;}/* * isc_mem_putanddetach() is the equivalent of: * * mctx = NULL; * isc_mem_attach(ptr->mctx, &mctx); * isc_mem_detach(&ptr->mctx); * isc_mem_put(mctx, ptr, sizeof(*ptr); * isc_mem_detach(&mctx); */voidisc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { isc_mem_t *ctx; isc_boolean_t want_destroy = ISC_FALSE; REQUIRE(ctxp != NULL); ctx = *ctxp; REQUIRE(VALID_CONTEXT(ctx)); REQUIRE(ptr != NULL); /* * Must be before mem_putunlocked() as ctxp is usually within * [ptr..ptr+size). */ *ctxp = NULL;#if ISC_MEM_USE_INTERNAL_MALLOC LOCK(&ctx->lock); mem_putunlocked(ctx, ptr, size);#else /* ISC_MEM_USE_INTERNAL_MALLOC */ mem_put(ctx, ptr, size); LOCK(&ctx->lock); mem_putstats(ctx, ptr, size);#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ DELETE_TRACE(ctx, ptr, size, file, line); INSIST(ctx->references > 0); ctx->references--; if (ctx->references == 0) want_destroy = ISC_TRUE; UNLOCK(&ctx->lock); if (want_destroy) destroy(ctx);}voidisc_mem_destroy(isc_mem_t **ctxp) { isc_mem_t *ctx; /* * This routine provides legacy support for callers who use mctxs * without attaching/detaching. */ REQUIRE(ctxp != NULL); ctx = *ctxp; REQUIRE(VALID_CONTEXT(ctx)); LOCK(&ctx->lock);#if ISC_MEM_TRACKLINES if (ctx->references != 1) print_active(ctx, stderr);#endif REQUIRE(ctx->references == 1); ctx->references--; UNLOCK(&ctx->lock); destroy(ctx); *ctxp = NULL;}isc_result_tisc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) { isc_result_t res; LOCK(&ctx->lock); res = isc_ondestroy_register(&ctx->ondestroy, task, event); UNLOCK(&ctx->lock); return (res);}void *isc__mem_get(isc_mem_t *ctx, size_t size FLARG) { void *ptr; isc_boolean_t call_water = ISC_FALSE; REQUIRE(VALID_CONTEXT(ctx));#if ISC_MEM_USE_INTERNAL_MALLOC LOCK(&ctx->lock); ptr = mem_getunlocked(ctx, size);#else /* ISC_MEM_USE_INTERNAL_MALLOC */ ptr = mem_get(ctx, size); LOCK(&ctx->lock); if (ptr != NULL) mem_getstats(ctx, size);#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ ADD_TRACE(ctx, ptr, size, file, line); if (ctx->hi_water != 0U && !ctx->hi_called && ctx->inuse > ctx->hi_water) { ctx->hi_called = ISC_TRUE; call_water = ISC_TRUE; } if (ctx->inuse > ctx->maxinuse) { ctx->maxinuse = ctx->inuse; if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) fprintf(stderr, "maxinuse = %lu\n", (unsigned long)ctx->inuse); } UNLOCK(&ctx->lock); if (call_water) (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); return (ptr);}voidisc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG){ isc_boolean_t call_water = ISC_FALSE; REQUIRE(VALID_CONTEXT(ctx)); REQUIRE(ptr != NULL);#if ISC_MEM_USE_INTERNAL_MALLOC LOCK(&ctx->lock); mem_putunlocked(ctx, ptr, size);#else /* ISC_MEM_USE_INTERNAL_MALLOC */ mem_put(ctx, ptr, size); LOCK(&ctx->lock); mem_putstats(ctx, ptr, size);#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ DELETE_TRACE(ctx, ptr, size, file, line); /* * The check against ctx->lo_water == 0 is for the condition * when the context was pushed over hi_water but then had * isc_mem_setwater() called with 0 for hi_water and lo_water. */ if (ctx->hi_called && (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { ctx->hi_called = ISC_FALSE; if (ctx->water != NULL) call_water = ISC_TRUE; } UNLOCK(&ctx->lock); if (call_water) (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);}#if ISC_MEM_TRACKLINESstatic voidprint_active(isc_mem_t *mctx, FILE *out) { if (mctx->debuglist != NULL) { debuglink_t *dl; unsigned int i, j; const char *format; isc_boolean_t found; fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_DUMPALLOC, "Dump of all outstanding " "memory allocations:\n")); found = ISC_FALSE; format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_PTRFILELINE, "\tptr %p size %u file %s line %u\n"); for (i = 0; i <= mctx->max_size; i++) { dl = ISC_LIST_HEAD(mctx->debuglist[i]); if (dl != NULL) found = ISC_TRUE; while (dl != NULL) { for (j = 0; j < DEBUGLIST_COUNT; j++) if (dl->ptr[j] != NULL) fprintf(out, format, dl->ptr[j], dl->size[j], dl->file[j], dl->line[j]); dl = ISC_LIST_NEXT(dl, link); } } if (!found) fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_NONE, "\tNone.\n")); }}#endif/* * Print the stats[] on the stream "out" with suitable formatting. */voidisc_mem_stats(isc_mem_t *ctx, FILE *out) { size_t i; const struct stats *s; const isc_mempool_t *pool; REQUIRE(VALID_CONTEXT(ctx)); LOCK(&ctx->lock); for (i = 0; i <= ctx->max_size; i++) { s = &ctx->stats[i]; if (s->totalgets == 0U && s->gets == 0U) continue; fprintf(out, "%s%5lu: %11lu gets, %11lu rem", (i == ctx->max_size) ? ">=" : " ", (unsigned long) i, s->totalgets, s->gets);#if ISC_MEM_USE_INTERNAL_MALLOC if (s->blocks != 0 || s->freefrags != 0) fprintf(out, " (%lu bl, %lu ff)", s->blocks, s->freefrags);#endif /* ISC_MEM_USE_INTERNAL_MALLOC */ fputc('\n', out); } /* * Note that since a pool can be locked now, these stats might be * somewhat off if the pool is in active use at the time the stats * are dumped. The link fields are protected by the isc_mem_t's * lock, however, so walking this list and extracting integers from * stats fields is always safe. */ pool = ISC_LIST_HEAD(ctx->pools); if (pool != NULL) { fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLSTATS, "[Pool statistics]\n")); fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLNAME, "name"), isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLSIZE, "size"), isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLMAXALLOC, "maxalloc"), isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLALLOCATED, "allocated"), isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLFREECOUNT, "freecount"), isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLFREEMAX, "freemax"), isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -