github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/mcentral.c (about) 1 // 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" 18 #include "arch_GOARCH.h" 19 #include "malloc.h" 20 21 static bool MCentral_Grow(MCentral *c); 22 static void MCentral_Free(MCentral *c, void *v); 23 24 // Initialize a single central free list. 25 void 26 runtime·MCentral_Init(MCentral *c, int32 sizeclass) 27 { 28 c->sizeclass = sizeclass; 29 runtime·MSpanList_Init(&c->nonempty); 30 runtime·MSpanList_Init(&c->empty); 31 } 32 33 // Allocate up to n objects from the central free list. 34 // Return the number of objects allocated. 35 // The objects are linked together by their first words. 36 // On return, *pstart points at the first object. 37 int32 38 runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst) 39 { 40 MSpan *s; 41 MLink *first, *last; 42 int32 cap, avail, i; 43 44 runtime·lock(c); 45 // Replenish central list if empty. 46 if(runtime·MSpanList_IsEmpty(&c->nonempty)) { 47 if(!MCentral_Grow(c)) { 48 runtime·unlock(c); 49 *pfirst = nil; 50 return 0; 51 } 52 } 53 s = c->nonempty.next; 54 cap = (s->npages << PageShift) / s->elemsize; 55 avail = cap - s->ref; 56 if(avail < n) 57 n = avail; 58 59 // First one is guaranteed to work, because we just grew the list. 60 first = s->freelist; 61 last = first; 62 for(i=1; i<n; i++) { 63 last = last->next; 64 } 65 s->freelist = last->next; 66 last->next = nil; 67 s->ref += n; 68 c->nfree -= n; 69 70 if(n == avail) { 71 if(s->freelist != nil || s->ref != cap) { 72 runtime·throw("invalid freelist"); 73 } 74 runtime·MSpanList_Remove(s); 75 runtime·MSpanList_Insert(&c->empty, s); 76 } 77 78 runtime·unlock(c); 79 *pfirst = first; 80 return n; 81 } 82 83 // Free n objects back into the central free list. 84 void 85 runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *start) 86 { 87 MLink *v, *next; 88 89 // Assume next == nil marks end of list. 90 // n and end would be useful if we implemented 91 // the transfer cache optimization in the TODO above. 92 USED(n); 93 94 runtime·lock(c); 95 for(v=start; v; v=next) { 96 next = v->next; 97 MCentral_Free(c, v); 98 } 99 runtime·unlock(c); 100 } 101 102 // Helper: free one object back into the central free list. 103 static void 104 MCentral_Free(MCentral *c, void *v) 105 { 106 MSpan *s; 107 MLink *p; 108 int32 size; 109 110 // Find span for v. 111 s = runtime·MHeap_Lookup(runtime·mheap, v); 112 if(s == nil || s->ref == 0) 113 runtime·throw("invalid free"); 114 115 // Move to nonempty if necessary. 116 if(s->freelist == nil) { 117 runtime·MSpanList_Remove(s); 118 runtime·MSpanList_Insert(&c->nonempty, s); 119 } 120 121 // Add v back to s's free list. 122 p = v; 123 p->next = s->freelist; 124 s->freelist = p; 125 c->nfree++; 126 127 // If s is completely freed, return it to the heap. 128 if(--s->ref == 0) { 129 size = runtime·class_to_size[c->sizeclass]; 130 runtime·MSpanList_Remove(s); 131 runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift); 132 *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing 133 s->freelist = nil; 134 c->nfree -= (s->npages << PageShift) / size; 135 runtime·unlock(c); 136 runtime·MHeap_Free(runtime·mheap, s, 0); 137 runtime·lock(c); 138 } 139 } 140 141 // Free n objects from a span s back into the central free list c. 142 // Called from GC. 143 void 144 runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end) 145 { 146 int32 size; 147 148 runtime·lock(c); 149 150 // Move to nonempty if necessary. 151 if(s->freelist == nil) { 152 runtime·MSpanList_Remove(s); 153 runtime·MSpanList_Insert(&c->nonempty, s); 154 } 155 156 // Add the objects back to s's free list. 157 end->next = s->freelist; 158 s->freelist = start; 159 s->ref -= n; 160 c->nfree += n; 161 162 // If s is completely freed, return it to the heap. 163 if(s->ref == 0) { 164 size = runtime·class_to_size[c->sizeclass]; 165 runtime·MSpanList_Remove(s); 166 *(uintptr*)(s->start<<PageShift) = 1; // needs zeroing 167 s->freelist = nil; 168 c->nfree -= (s->npages << PageShift) / size; 169 runtime·unlock(c); 170 runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift); 171 runtime·MHeap_Free(runtime·mheap, s, 0); 172 } else { 173 runtime·unlock(c); 174 } 175 } 176 177 void 178 runtime·MGetSizeClassInfo(int32 sizeclass, uintptr *sizep, int32 *npagesp, int32 *nobj) 179 { 180 int32 size; 181 int32 npages; 182 183 npages = runtime·class_to_allocnpages[sizeclass]; 184 size = runtime·class_to_size[sizeclass]; 185 *npagesp = npages; 186 *sizep = size; 187 *nobj = (npages << PageShift) / size; 188 } 189 190 // Fetch a new span from the heap and 191 // carve into objects for the free list. 192 static bool 193 MCentral_Grow(MCentral *c) 194 { 195 int32 i, n, npages; 196 uintptr size; 197 MLink **tailp, *v; 198 byte *p; 199 MSpan *s; 200 201 runtime·unlock(c); 202 runtime·MGetSizeClassInfo(c->sizeclass, &size, &npages, &n); 203 s = runtime·MHeap_Alloc(runtime·mheap, npages, c->sizeclass, 0, 1); 204 if(s == nil) { 205 // TODO(rsc): Log out of memory 206 runtime·lock(c); 207 return false; 208 } 209 210 // Carve span into sequence of blocks. 211 tailp = &s->freelist; 212 p = (byte*)(s->start << PageShift); 213 s->limit = p + size*n; 214 for(i=0; i<n; i++) { 215 v = (MLink*)p; 216 *tailp = v; 217 tailp = &v->next; 218 p += size; 219 } 220 *tailp = nil; 221 runtime·markspan((byte*)(s->start<<PageShift), size, n, size*n < (s->npages<<PageShift)); 222 223 runtime·lock(c); 224 c->nfree += n; 225 runtime·MSpanList_Insert(&c->nonempty, s); 226 return true; 227 }