summaryrefslogtreecommitdiff
path: root/src/lib/runtime/mcache.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-06-06 22:04:39 -0700
committerRuss Cox <rsc@golang.org>2009-06-06 22:04:39 -0700
commit8257be5f9d4a4bdbb0ff096756a0e48401d620c8 (patch)
tree1195452c472b99bfd365ee1cc057e870178e63e0 /src/lib/runtime/mcache.c
parentaf9643dcc1336bcb6e6ed0817e68a9c2db2c5613 (diff)
downloadgolang-8257be5f9d4a4bdbb0ff096756a0e48401d620c8.tar.gz
move src/runtime -> src/lib/runtime;
only automatic g4 mv here. R=r OCL=30002 CL=30007
Diffstat (limited to 'src/lib/runtime/mcache.c')
-rw-r--r--src/lib/runtime/mcache.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/lib/runtime/mcache.c b/src/lib/runtime/mcache.c
new file mode 100644
index 000000000..ae2594023
--- /dev/null
+++ b/src/lib/runtime/mcache.c
@@ -0,0 +1,105 @@
+// 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-thread (in Go, per-M) malloc cache for small objects.
+//
+// See malloc.h for an overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+MCache_Alloc(MCache *c, int32 sizeclass, uintptr size)
+{
+ MCacheList *l;
+ MLink *first, *v;
+ int32 n;
+
+ // Allocate from list.
+ l = &c->list[sizeclass];
+ if(l->list == nil) {
+ // Replenish using central lists.
+ n = MCentral_AllocList(&mheap.central[sizeclass],
+ class_to_transfercount[sizeclass], &first);
+ l->list = first;
+ l->nlist = n;
+ c->size += n*size;
+ }
+ v = l->list;
+ l->list = v->next;
+ l->nlist--;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= size;
+
+ // v is zeroed except for the link pointer
+ // that we used above; zero that.
+ v->next = nil;
+ return v;
+}
+
+// Take n elements off l and return them to the central free list.
+static void
+ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
+{
+ MLink *first, **lp;
+ int32 i;
+
+ // Cut off first n elements.
+ first = l->list;
+ lp = &l->list;
+ for(i=0; i<n; i++)
+ lp = &(*lp)->next;
+ l->list = *lp;
+ *lp = nil;
+ l->nlist -= n;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= n*class_to_size[sizeclass];
+
+ // Return them to central free list.
+ MCentral_FreeList(&mheap.central[sizeclass], n, first);
+}
+
+void
+MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+{
+ int32 i, n;
+ MCacheList *l;
+ MLink *p;
+
+ // Put back on list.
+ l = &c->list[sizeclass];
+ p = v;
+ p->next = l->list;
+ l->list = p;
+ l->nlist++;
+ c->size += size;
+
+ if(l->nlist >= MaxMCacheListLen) {
+ // Release a chunk back.
+ ReleaseN(c, l, class_to_transfercount[sizeclass], sizeclass);
+ }
+
+ if(c->size >= MaxMCacheSize) {
+ // Scavenge.
+ for(i=0; i<NumSizeClasses; i++) {
+ l = &c->list[i];
+ n = l->nlistmin;
+
+ // n is the minimum number of elements we've seen on
+ // the list since the last scavenge. If n > 0, it means that
+ // we could have gotten by with n fewer elements
+ // without needing to consult the central free list.
+ // Move toward that situation by releasing n/2 of them.
+ if(n > 0) {
+ if(n > 1)
+ n /= 2;
+ ReleaseN(c, l, n, i);
+ }
+ l->nlistmin = l->nlist;
+ }
+ }
+}
+