root/src/pkg/runtime/mcache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. runtime·allocmcache
  2. runtime·freemcache
  3. runtime·MCache_Refill
  4. runtime·MCache_Free
  5. runtime·MCache_ReleaseAll

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Per-P malloc cache for small objects.
//
// See malloc.h for an overview.

#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"

extern volatile intgo runtime·MemProfileRate;

// dummy MSpan that contains no free objects.
static MSpan emptymspan;

MCache*
runtime·allocmcache(void)
{
        intgo rate;
        MCache *c;
        int32 i;

        runtime·lock(&runtime·mheap);
        c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
        runtime·unlock(&runtime·mheap);
        runtime·memclr((byte*)c, sizeof(*c));
        for(i = 0; i < NumSizeClasses; i++)
                c->alloc[i] = &emptymspan;

        // Set first allocation sample size.
        rate = runtime·MemProfileRate;
        if(rate > 0x3fffffff)   // make 2*rate not overflow
                rate = 0x3fffffff;
        if(rate != 0)
                c->next_sample = runtime·fastrand1() % (2*rate);

        return c;
}

void
runtime·freemcache(MCache *c)
{
        runtime·MCache_ReleaseAll(c);
        runtime·lock(&runtime·mheap);
        runtime·purgecachedstats(c);
        runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
        runtime·unlock(&runtime·mheap);
}

// Gets a span that has a free object in it and assigns it
// to be the cached span for the given sizeclass.  Returns this span.
MSpan*
runtime·MCache_Refill(MCache *c, int32 sizeclass)
{
        MCacheList *l;
        MSpan *s;

        m->locks++;
        // Return the current cached span to the central lists.
        s = c->alloc[sizeclass];
        if(s->freelist != nil)
                runtime·throw("refill on a nonempty span");
        if(s != &emptymspan)
                runtime·MCentral_UncacheSpan(&runtime·mheap.central[sizeclass], s);

        // Push any explicitly freed objects to the central lists.
        // Not required, but it seems like a good time to do it.
        l = &c->free[sizeclass];
        if(l->nlist > 0) {
                runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], l->list);
                l->list = nil;
                l->nlist = 0;
        }

        // Get a new cached span from the central lists.
        s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass]);
        if(s == nil)
                runtime·throw("out of memory");
        if(s->freelist == nil) {
                runtime·printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize));
                runtime·throw("empty span");
        }
        c->alloc[sizeclass] = s;
        m->locks--;
        return s;
}

void
runtime·MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size)
{
        MCacheList *l;

        // Put on free list.
        l = &c->free[sizeclass];
        p->next = l->list;
        l->list = p;
        l->nlist++;

        // We transfer a span at a time from MCentral to MCache,
        // so we'll do the same in the other direction.
        if(l->nlist >= (runtime·class_to_allocnpages[sizeclass]<<PageShift)/size) {
                runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], l->list);
                l->list = nil;
                l->nlist = 0;
        }
}

void
runtime·MCache_ReleaseAll(MCache *c)
{
        int32 i;
        MSpan *s;
        MCacheList *l;

        for(i=0; i<NumSizeClasses; i++) {
                s = c->alloc[i];
                if(s != &emptymspan) {
                        runtime·MCentral_UncacheSpan(&runtime·mheap.central[i], s);
                        c->alloc[i] = &emptymspan;
                }
                l = &c->free[i];
                if(l->nlist > 0) {
                        runtime·MCentral_FreeList(&runtime·mheap.central[i], l->list);
                        l->list = nil;
                        l->nlist = 0;
                }
        }
}

/* [<][>][^][v][top][bottom][index][help] */