blob: ff0c2d11ad32ed6e22da3514d54e09478923602a [file] [log] [blame]
Russ Coxe29ce172008-12-18 15:42:28 -08001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Central free lists.
6//
7// See malloc.h for an overview.
8//
9// The MCentral doesn't actually contain the list of free objects; the MSpan does.
10// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
11// and those that are completely allocated (c->empty).
12//
13// TODO(rsc): tcmalloc uses a "transfer cache" to split the list
14// into sections of class_to_transfercount[sizeclass] objects
15// so that it is faster to move those lists between MCaches and MCentrals.
16
17#include "runtime.h"
Russ Cox851f3012011-12-16 15:33:58 -050018#include "arch_GOARCH.h"
Russ Coxe29ce172008-12-18 15:42:28 -080019#include "malloc.h"
20
21static bool MCentral_Grow(MCentral *c);
22static void* MCentral_Alloc(MCentral *c);
23static void MCentral_Free(MCentral *c, void *v);
24
25// Initialize a single central free list.
26void
Russ Cox68b42552010-11-04 14:00:19 -040027runtime·MCentral_Init(MCentral *c, int32 sizeclass)
Russ Coxe29ce172008-12-18 15:42:28 -080028{
29 c->sizeclass = sizeclass;
Russ Cox68b42552010-11-04 14:00:19 -040030 runtime·MSpanList_Init(&c->nonempty);
31 runtime·MSpanList_Init(&c->empty);
Russ Coxe29ce172008-12-18 15:42:28 -080032}
33
34// Allocate up to n objects from the central free list.
35// Return the number of objects allocated.
36// The objects are linked together by their first words.
37// On return, *pstart points at the first object and *pend at the last.
38int32
Russ Cox68b42552010-11-04 14:00:19 -040039runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
Russ Coxe29ce172008-12-18 15:42:28 -080040{
Russ Coxda0a7d72008-12-19 03:13:39 -080041 MLink *first, *last, *v;
Russ Coxe29ce172008-12-18 15:42:28 -080042 int32 i;
43
Russ Cox68b42552010-11-04 14:00:19 -040044 runtime·lock(c);
Russ Coxe29ce172008-12-18 15:42:28 -080045 // Replenish central list if empty.
Russ Cox68b42552010-11-04 14:00:19 -040046 if(runtime·MSpanList_IsEmpty(&c->nonempty)) {
Russ Coxe29ce172008-12-18 15:42:28 -080047 if(!MCentral_Grow(c)) {
Russ Cox68b42552010-11-04 14:00:19 -040048 runtime·unlock(c);
Russ Coxda0a7d72008-12-19 03:13:39 -080049 *pfirst = nil;
Russ Coxe29ce172008-12-18 15:42:28 -080050 return 0;
51 }
52 }
53
54 // Copy from list, up to n.
Russ Coxda0a7d72008-12-19 03:13:39 -080055 // First one is guaranteed to work, because we just grew the list.
56 first = MCentral_Alloc(c);
57 last = first;
58 for(i=1; i<n && (v = MCentral_Alloc(c)) != nil; i++) {
59 last->next = v;
60 last = v;
Russ Coxe29ce172008-12-18 15:42:28 -080061 }
Russ Coxda0a7d72008-12-19 03:13:39 -080062 last->next = nil;
Russ Coxe29ce172008-12-18 15:42:28 -080063 c->nfree -= i;
64
Russ Cox68b42552010-11-04 14:00:19 -040065 runtime·unlock(c);
Russ Coxda0a7d72008-12-19 03:13:39 -080066 *pfirst = first;
Russ Coxe29ce172008-12-18 15:42:28 -080067 return i;
68}
69
70// Helper: allocate one object from the central free list.
71static void*
72MCentral_Alloc(MCentral *c)
73{
74 MSpan *s;
Russ Coxda0a7d72008-12-19 03:13:39 -080075 MLink *v;
Russ Coxe29ce172008-12-18 15:42:28 -080076
Russ Cox68b42552010-11-04 14:00:19 -040077 if(runtime·MSpanList_IsEmpty(&c->nonempty))
Russ Coxe29ce172008-12-18 15:42:28 -080078 return nil;
79 s = c->nonempty.next;
Russ Coxda0a7d72008-12-19 03:13:39 -080080 s->ref++;
Russ Coxe29ce172008-12-18 15:42:28 -080081 v = s->freelist;
Russ Coxda0a7d72008-12-19 03:13:39 -080082 s->freelist = v->next;
Russ Coxe29ce172008-12-18 15:42:28 -080083 if(s->freelist == nil) {
Russ Cox68b42552010-11-04 14:00:19 -040084 runtime·MSpanList_Remove(s);
85 runtime·MSpanList_Insert(&c->empty, s);
Russ Coxe29ce172008-12-18 15:42:28 -080086 }
Russ Coxe29ce172008-12-18 15:42:28 -080087 return v;
88}
89
90// Free n objects back into the central free list.
91// Return the number of objects allocated.
92// The objects are linked together by their first words.
93// On return, *pstart points at the first object and *pend at the last.
94void
Russ Cox68b42552010-11-04 14:00:19 -040095runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *start)
Russ Coxe29ce172008-12-18 15:42:28 -080096{
Russ Coxda0a7d72008-12-19 03:13:39 -080097 MLink *v, *next;
Russ Coxe29ce172008-12-18 15:42:28 -080098
Russ Coxda0a7d72008-12-19 03:13:39 -080099 // Assume next == nil marks end of list.
Russ Coxe29ce172008-12-18 15:42:28 -0800100 // n and end would be useful if we implemented
101 // the transfer cache optimization in the TODO above.
102 USED(n);
Russ Coxe29ce172008-12-18 15:42:28 -0800103
Russ Cox68b42552010-11-04 14:00:19 -0400104 runtime·lock(c);
Russ Coxe29ce172008-12-18 15:42:28 -0800105 for(v=start; v; v=next) {
Russ Coxda0a7d72008-12-19 03:13:39 -0800106 next = v->next;
Russ Coxe29ce172008-12-18 15:42:28 -0800107 MCentral_Free(c, v);
108 }
Russ Cox68b42552010-11-04 14:00:19 -0400109 runtime·unlock(c);
Russ Coxe29ce172008-12-18 15:42:28 -0800110}
111
112// Helper: free one object back into the central free list.
113static void
114MCentral_Free(MCentral *c, void *v)
115{
116 MSpan *s;
Russ Cox1e063b32011-02-02 23:03:47 -0500117 MLink *p;
Russ Coxf25586a2010-02-10 00:00:12 -0800118 int32 size;
Russ Coxe29ce172008-12-18 15:42:28 -0800119
120 // Find span for v.
Russ Cox4608feb2011-01-28 15:03:26 -0500121 s = runtime·MHeap_Lookup(&runtime·mheap, v);
Russ Coxe29ce172008-12-18 15:42:28 -0800122 if(s == nil || s->ref == 0)
Russ Cox68b42552010-11-04 14:00:19 -0400123 runtime·throw("invalid free");
Russ Coxe29ce172008-12-18 15:42:28 -0800124
125 // Move to nonempty if necessary.
126 if(s->freelist == nil) {
Russ Cox68b42552010-11-04 14:00:19 -0400127 runtime·MSpanList_Remove(s);
128 runtime·MSpanList_Insert(&c->nonempty, s);
Russ Coxe29ce172008-12-18 15:42:28 -0800129 }
130
131 // Add v back to s's free list.
Russ Coxda0a7d72008-12-19 03:13:39 -0800132 p = v;
133 p->next = s->freelist;
134 s->freelist = p;
Russ Coxe29ce172008-12-18 15:42:28 -0800135 c->nfree++;
136
137 // If s is completely freed, return it to the heap.
138 if(--s->ref == 0) {
Russ Cox68b42552010-11-04 14:00:19 -0400139 size = runtime·class_to_size[c->sizeclass];
140 runtime·MSpanList_Remove(s);
Russ Cox1e063b32011-02-02 23:03:47 -0500141 runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
142 *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing
Russ Coxda0a7d72008-12-19 03:13:39 -0800143 s->freelist = nil;
Russ Coxf25586a2010-02-10 00:00:12 -0800144 c->nfree -= (s->npages << PageShift) / size;
Russ Cox68b42552010-11-04 14:00:19 -0400145 runtime·unlock(c);
146 runtime·MHeap_Free(&runtime·mheap, s, 0);
147 runtime·lock(c);
Russ Coxe29ce172008-12-18 15:42:28 -0800148 }
149}
150
Russ Coxfb94be52010-02-10 14:59:39 -0800151void
Russ Cox1e063b32011-02-02 23:03:47 -0500152runtime·MGetSizeClassInfo(int32 sizeclass, uintptr *sizep, int32 *npagesp, int32 *nobj)
Russ Coxfb94be52010-02-10 14:59:39 -0800153{
154 int32 size;
155 int32 npages;
156
Russ Cox68b42552010-11-04 14:00:19 -0400157 npages = runtime·class_to_allocnpages[sizeclass];
158 size = runtime·class_to_size[sizeclass];
Russ Coxfb94be52010-02-10 14:59:39 -0800159 *npagesp = npages;
160 *sizep = size;
Russ Cox1e063b32011-02-02 23:03:47 -0500161 *nobj = (npages << PageShift) / size;
Russ Coxfb94be52010-02-10 14:59:39 -0800162}
163
Russ Coxe29ce172008-12-18 15:42:28 -0800164// Fetch a new span from the heap and
165// carve into objects for the free list.
166static bool
167MCentral_Grow(MCentral *c)
168{
Russ Cox1e063b32011-02-02 23:03:47 -0500169 int32 i, n, npages;
170 uintptr size;
Russ Coxda0a7d72008-12-19 03:13:39 -0800171 MLink **tailp, *v;
Russ Cox1ce17912009-01-26 17:37:05 -0800172 byte *p;
Russ Coxe29ce172008-12-18 15:42:28 -0800173 MSpan *s;
174
Russ Cox68b42552010-11-04 14:00:19 -0400175 runtime·unlock(c);
176 runtime·MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
177 s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0);
Russ Coxe29ce172008-12-18 15:42:28 -0800178 if(s == nil) {
179 // TODO(rsc): Log out of memory
Russ Cox68b42552010-11-04 14:00:19 -0400180 runtime·lock(c);
Russ Coxe29ce172008-12-18 15:42:28 -0800181 return false;
182 }
183
184 // Carve span into sequence of blocks.
Russ Coxda0a7d72008-12-19 03:13:39 -0800185 tailp = &s->freelist;
Russ Coxe29ce172008-12-18 15:42:28 -0800186 p = (byte*)(s->start << PageShift);
Russ Cox1e063b32011-02-02 23:03:47 -0500187 s->limit = p + size*n;
Russ Cox1ce17912009-01-26 17:37:05 -0800188 for(i=0; i<n; i++) {
Russ Coxda0a7d72008-12-19 03:13:39 -0800189 v = (MLink*)p;
190 *tailp = v;
191 tailp = &v->next;
Russ Cox1ce17912009-01-26 17:37:05 -0800192 p += size;
Russ Coxe29ce172008-12-18 15:42:28 -0800193 }
Russ Coxda0a7d72008-12-19 03:13:39 -0800194 *tailp = nil;
Russ Cox1e063b32011-02-02 23:03:47 -0500195 runtime·markspan((byte*)(s->start<<PageShift), size, n, size*n < (s->npages<<PageShift));
Russ Coxe29ce172008-12-18 15:42:28 -0800196
Russ Cox68b42552010-11-04 14:00:19 -0400197 runtime·lock(c);
Russ Coxe29ce172008-12-18 15:42:28 -0800198 c->nfree += n;
Russ Cox68b42552010-11-04 14:00:19 -0400199 runtime·MSpanList_Insert(&c->nonempty, s);
Russ Coxe29ce172008-12-18 15:42:28 -0800200 return true;
201}