示例#1
0
void Allocator__free(struct Allocator* alloc, const char* file, int line)
{
    struct Allocator_pvt* context = Identity_check((struct Allocator_pvt*) alloc);
    check(context);

    // It's really difficult to know that you didn't get called back inside of a freeing of a
    // parent of a parent allocator which causes your allocator to be in isFreeing state so
    // lets be forgiving here.
    if (context->pub.isFreeing) { return; }

    if (context->rootAlloc == (struct Allocator_FirstCtx*)context) {
        struct Allocator_FirstCtx* rootAlloc = Identity_check((struct Allocator_FirstCtx*)context);
        if (bytesAllocated(context) + rootAlloc->spaceAvailable != (uint64_t)rootAlloc->maxSpace) {
            failure(context, "unaccounted for memory", file, line);
        }
    }

    check(context);
    if (!pivotChildrenToAdoptedParents(context, file, line)) { return; }
    check(context);
    marshalOnFreeJobs(context, context);
    check(context);
    doOnFreeJobs(context);
    check(context);
    if (!context->onFree) {
        freeAllocator(context);
    }
}
示例#2
0
static void freeAllocator(struct Allocator_pvt* context)
{
    Assert_true(context->pub.isFreeing);
    int isTop = !context->parent->pub.isFreeing;
    if (isTop) {
        check(context);
        disconnect(context);
    }
    struct Allocator_pvt* child = context->firstChild;
    while (child) {
        struct Allocator_pvt* nextChild = child->nextSibling;
        freeAllocator(child);
        child = nextChild;
    }

    // Grab out the provider and provider context in case the root allocator is freed.
    struct Allocator_FirstCtx* rootAlloc = Identity_check(context->rootAlloc);
    Allocator_Provider provider = rootAlloc->provider;
    Allocator_Provider_CONTEXT_TYPE* providerCtx = rootAlloc->providerContext;

    releaseMemory(context, provider, providerCtx);
    if (isTop) {
        check((struct Allocator_pvt*)rootAlloc);
    }
}
示例#3
0
文件: Allocator.c 项目: 0x20c24/cjdns
static void childFreed(struct Allocator_pvt* child)
{
    struct Allocator_pvt* parent = child->parent;
    // disconnect the child and if there are no children left then call freeAllocator()
    // on the parent a second time. If child == parent then it's a root allocator and
    // we do not want to double-free it.
    disconnect(child);
    if (parent && parent != child && !parent->firstChild && parent->pub.isFreeing) {
        freeAllocator(parent, child->pub.fileName, child->pub.lineNum);
    }
}
示例#4
0
void Allocator_onFreeComplete(struct Allocator_OnFreeJob* onFreeJob)
{
    struct Allocator_OnFreeJob_pvt* job = (struct Allocator_OnFreeJob_pvt*) onFreeJob;
    struct Allocator_pvt* context = Identity_check(job->alloc);

    if (removeJob(job)) {
        failure(context, "OnFreeJob->complete() called multiple times", job->file, job->line);
    }

    if (!context->onFree) {
        // There are no more jobs, release the memory.
        freeAllocator(context);
    }
}
示例#5
0
文件: Allocator.c 项目: 0x20c24/cjdns
void Allocator__free(struct Allocator* alloc, const char* file, int line)
{
    struct Allocator_pvt* context = Identity_check((struct Allocator_pvt*) alloc);
    freeAllocator(context, file, line);
}
示例#6
0
文件: Allocator.c 项目: 0x20c24/cjdns
/**
 * Triggered when freeAllocator() is called and the allocator nolonger
 * has any remaining links to the allocator tree.
 */
static void freeAllocator(struct Allocator_pvt* context, const char* file, int line)
{
    if (context->adoptions && context->adoptions->parents) {
        disconnect(context);
        connect(context->adoptions->parents->alloc, context, file, line);
        disconnectAdopted(context->adoptions->parents->alloc, context);
        return;
    }

    // When the last child calls us back via childFreed() we will be called the last time and
    // if this is not set, the child will be disconnected from us and we will be left.
    context->pub.isFreeing = 1;

    // from now on, fileName/line will point to the place of freeing.
    // this allows childFreed() to tell the truth when calling us back.
    context->pub.fileName = file;
    context->pub.lineNum = line;

    // Disconnect adopted children.
    struct Allocator_List* childL = context->adoptions ? context->adoptions->children : NULL;
    while (childL) {
        disconnectAdopted(context, childL->alloc);
        childL = childL->next;
    }

    // Do the onFree jobs.
    struct Allocator_OnFreeJob_pvt** jobP = &context->onFree;
    while (*jobP != NULL) {
        struct Allocator_OnFreeJob_pvt* job = *jobP;
        if (!job->pub.callback) {
            // no callback, remove the job
            Assert_true(!removeJob(job));
            continue;
        } else if (!job->done) {
            if  (job->pub.callback(&job->pub) != Allocator_ONFREE_ASYNC) {
                Assert_true(!removeJob(job));
                continue;
            }
            // asynchronously completing, don't bother it again.
            job->done = 1;
        }
        jobP = &job->next;
    }

    if (context->onFree) {
        // onFreeComplete() will call us back.
        return;
    }

    // Free children
    struct Allocator_pvt* child = context->firstChild;
    if (child) {
        while (child) {
            struct Allocator_pvt* nextChild = child->nextSibling;
            freeAllocator(child, file, line);
            child = nextChild;
        }
        // childFreed() will call us back.
        return;
    }

    // Grab out the provider and provider context in case the root allocator is freed.
    Allocator_Provider provider = context->rootAlloc->provider;
    Allocator_Provider_CONTEXT_TYPE* providerCtx = context->rootAlloc->providerContext;

    childFreed(context);
    releaseMemory(context, provider, providerCtx);
}