mem.c
来自「非常好的dns解析软件」· C语言 代码 · 共 1,955 行 · 第 1/3 页
C
1,955 行
/*! * 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--; }}/* * 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);}static voidinitialize_action(void) { RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);}/* * 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){ return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree, arg, ctxp, ISC_MEMFLAG_DEFAULT)); }isc_result_tisc_mem_createx2(size_t init_max_size, size_t target_size, isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, isc_mem_t **ctxp, unsigned int flags){ 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); RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); ctx = (memalloc)(arg, sizeof(*ctx)); if (ctx == NULL) return (ISC_R_NOMEMORY); if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { result = isc_mutex_init(&ctx->lock); if (result != ISC_R_SUCCESS) { (memfree)(arg, ctx); return (result); } } if (init_max_size == 0U) ctx->max_size = DEF_MAX_SIZE; else ctx->max_size = init_max_size; ctx->flags = flags; 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); ctx->freelists = NULL; ctx->basic_blocks = NULL; ctx->basic_table = NULL; ctx->basic_table_count = 0; ctx->basic_table_size = 0; ctx->lowest = NULL; ctx->highest = NULL; 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 ((flags & ISC_MEMFLAG_INTERNAL) != 0) { if (target_size == 0U) 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 *)); }#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; LOCK(&lock); ISC_LIST_INITANDAPPEND(contexts, ctx, link); UNLOCK(&lock); *ctxp = ctx; return (ISC_R_SUCCESS); error: if (ctx != NULL) { if (ctx->stats != NULL) (memfree)(arg, ctx->stats); if (ctx->freelists != NULL) (memfree)(arg, ctx->freelists);#if ISC_MEM_TRACKLINES if (ctx->debuglist != NULL) (ctx->memfree)(ctx->arg, ctx->debuglist);#endif /* ISC_MEM_TRACKLINES */ if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) DESTROYLOCK(&ctx->lock); (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_createx2(init_max_size, target_size, default_memalloc, default_memfree, NULL, ctxp, ISC_MEMFLAG_DEFAULT));}isc_result_tisc_mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **ctxp, unsigned int flags){ return (isc_mem_createx2(init_max_size, target_size, default_memalloc, default_memfree, NULL, ctxp, flags));}static voiddestroy(isc_mem_t *ctx) { unsigned int i; isc_ondestroy_t ondest; ctx->magic = 0; LOCK(&lock); ISC_LIST_UNLINK(contexts, ctx, link); UNLOCK(&lock); INSIST(ISC_LIST_EMPTY(ctx->pools));#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 ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { 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); } ondest = ctx->ondestroy; if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) 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); MCTXLOCK(source, &source->lock); source->references++; MCTXUNLOCK(source, &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)); MCTXLOCK(ctx, &ctx->lock); INSIST(ctx->references > 0); ctx->references--; if (ctx->references == 0) want_destroy = ISC_TRUE; MCTXUNLOCK(ctx, &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; size_info *si; size_t oldsize; 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_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { si = &(((size_info *)ptr)[-1]); oldsize = si->u.size - ALIGNMENT_SIZE; if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) oldsize -= ALIGNMENT_SIZE; INSIST(oldsize == size); } isc__mem_free(ctx, ptr FLARG_PASS); MCTXLOCK(ctx, &ctx->lock); ctx->references--; if (ctx->references == 0) want_destroy = ISC_TRUE; MCTXUNLOCK(ctx, &ctx->lock); if (want_destroy) destroy(ctx); return; } if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { MCTXLOCK(ctx, &ctx->lock); mem_putunlocked(ctx, ptr, size); } else { mem_put(ctx, ptr, size); MCTXLOCK(ctx, &ctx->lock); mem_putstats(ctx, ptr, size); } DELETE_TRACE(ctx, ptr, size, file, line); INSIST(ctx->references > 0); ctx->references--; if (ctx->references == 0) want_destroy = ISC_TRUE; MCTXUNLOCK(ctx, &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)); MCTXLOCK(ctx, &ctx->lock);#if ISC_MEM_TRACKLINES if (ctx->references != 1) print_active(ctx, stderr);#endif REQUIRE(ctx->references == 1); ctx->references--; MCTXUNLOCK(ctx, &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; MCTXLOCK(ctx, &ctx->lock); res = isc_ondestroy_register(&ctx->ondestroy, task, event); MCTXUNLOCK(ctx, &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_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) return (isc__mem_allocate(ctx, size FLARG_PASS)); if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { MCTXLOCK(ctx, &ctx->lock); ptr = mem_getunlocked(ctx, size); } else { ptr = mem_get(ctx, size); MCTXLOCK(ctx, &ctx->lock); if (ptr != NULL) mem_getstats(ctx, size); } 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); } MCTXUNLOCK(ctx, &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; size_info *si; size_t oldsize; REQUIRE(VALID_CONTEXT(ctx)); REQUIRE(ptr != NULL); if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { si = &(((size_info *)ptr)[-1]); oldsize = si->u.size - ALIGNMENT_SIZE; if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) oldsize -= ALIGNMENT_SIZE; INSIST(oldsize == size); } isc__mem_free(ctx, ptr FLARG_PASS); return; } if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { MCTXLOCK(ctx, &ctx->lock); mem_putunlocked(ctx, ptr, size); } else { mem_put(ctx, ptr, size); MCTXLOCK(ctx, &ctx->lock); mem_putstats(ctx, ptr, size); } 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; } MCTXUNLOCK(ctx, &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)); MCTXLOCK(ctx, &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 ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && (s->blocks != 0U || s->freefrags != 0U)) fprintf(out, " (%lu bl, %lu ff)", s->blocks, s->freefrags); 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, ISC_MSG_POOLFILLCOUNT, "fillcount"), isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, ISC_MSG_POOLGETS, "gets"), "L"); } while (pool != NULL) { fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", pool->name, (unsigned long) pool->size, pool->maxalloc, pool->allocated, pool->freecount, pool->freemax, pool->fillcount, pool->gets, (pool->lock == NULL ? "N" : "Y")); pool = ISC_LIST_NEXT(pool, link); }#if ISC_MEM_TRACKLINES print_active(ctx, out);#endif MCTXUNLOCK(ctx, &ctx->lock);}/* * Replacements for malloc() and free() -- they implicitly remember the * size of the object allocated (with some additional overhead). */static void *isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { size_info *si; size += ALIGNMENT_SIZE; if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) size += ALIGNMENT_SIZE; if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) si = mem_getunlocked(ctx, size); else si = mem_get(ctx, size); if (si == NULL) return (NULL); if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { si->u.ctx = ctx; si++; } si->u.size = size; return (&si[1]);}void *isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) { size_info *si; isc_boolean_t call_water = ISC_FALSE; REQUIRE(VALID_CONTEXT(ctx));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?