OSDN Git Service

Add Go frontend, libgo library, and Go testsuite.
[pf3gnuchains/gcc-fork.git] / libgo / runtime / mcentral.c
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 "malloc.h"
19
20 static bool MCentral_Grow(MCentral *c);
21 static void* MCentral_Alloc(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         runtime_initlock(c);
29         c->sizeclass = sizeclass;
30         runtime_MSpanList_Init(&c->nonempty);
31         runtime_MSpanList_Init(&c->empty);
32 }
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.
38 int32
39 runtime_MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
40 {
41         MLink *first, *last, *v;
42         int32 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
54         // Copy from list, up to n.
55         // 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;
61         }
62         last->next = nil;
63         c->nfree -= i;
64
65         runtime_unlock(c);
66         *pfirst = first;
67         return i;
68 }
69
70 // Helper: allocate one object from the central free list.
71 static void*
72 MCentral_Alloc(MCentral *c)
73 {
74         MSpan *s;
75         MLink *v;
76
77         if(runtime_MSpanList_IsEmpty(&c->nonempty))
78                 return nil;
79         s = c->nonempty.next;
80         s->ref++;
81         v = s->freelist;
82         s->freelist = v->next;
83         if(s->freelist == nil) {
84                 runtime_MSpanList_Remove(s);
85                 runtime_MSpanList_Insert(&c->empty, s);
86         }
87         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.
94 void
95 runtime_MCentral_FreeList(MCentral *c, int32 n, MLink *start)
96 {
97         MLink *v, *next;
98
99         // Assume next == nil marks end of list.
100         // n and end would be useful if we implemented
101         // the transfer cache optimization in the TODO above.
102         USED(n);
103
104         runtime_lock(c);
105         for(v=start; v; v=next) {
106                 next = v->next;
107                 MCentral_Free(c, v);
108         }
109         runtime_unlock(c);
110 }
111
112 // Helper: free one object back into the central free list.
113 static void
114 MCentral_Free(MCentral *c, void *v)
115 {
116         MSpan *s;
117         PageID page;
118         MLink *p, *next;
119         int32 size;
120
121         // Find span for v.
122         page = (uintptr)v >> PageShift;
123         s = runtime_MHeap_Lookup(&runtime_mheap, page);
124         if(s == nil || s->ref == 0)
125                 runtime_throw("invalid free");
126
127         // Move to nonempty if necessary.
128         if(s->freelist == nil) {
129                 runtime_MSpanList_Remove(s);
130                 runtime_MSpanList_Insert(&c->nonempty, s);
131         }
132
133         // Add v back to s's free list.
134         p = v;
135         p->next = s->freelist;
136         s->freelist = p;
137         c->nfree++;
138
139         // If s is completely freed, return it to the heap.
140         if(--s->ref == 0) {
141                 size = runtime_class_to_size[c->sizeclass];
142                 runtime_MSpanList_Remove(s);
143                 // The second word of each freed block indicates
144                 // whether it needs to be zeroed.  The first word
145                 // is the link pointer and must always be cleared.
146                 for(p=s->freelist; p; p=next) {
147                         next = p->next;
148                         if(size > (int32)sizeof(uintptr) && ((uintptr*)p)[1] != 0)
149                                 runtime_memclr((byte*)p, size);
150                         else
151                                 p->next = nil;
152                 }
153                 s->freelist = nil;
154                 c->nfree -= (s->npages << PageShift) / size;
155                 runtime_unlock(c);
156                 runtime_MHeap_Free(&runtime_mheap, s, 0);
157                 runtime_lock(c);
158         }
159 }
160
161 void
162 runtime_MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
163 {
164         int32 size;
165         int32 npages;
166
167         npages = runtime_class_to_allocnpages[sizeclass];
168         size = runtime_class_to_size[sizeclass];
169         *npagesp = npages;
170         *sizep = size;
171         *nobj = (npages << PageShift) / (size + RefcountOverhead);
172 }
173
174 // Fetch a new span from the heap and
175 // carve into objects for the free list.
176 static bool
177 MCentral_Grow(MCentral *c)
178 {
179         int32 i, n, npages, size;
180         MLink **tailp, *v;
181         byte *p;
182         MSpan *s;
183
184         runtime_unlock(c);
185         runtime_MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
186         s = runtime_MHeap_Alloc(&runtime_mheap, npages, c->sizeclass, 0);
187         if(s == nil) {
188                 // TODO(rsc): Log out of memory
189                 runtime_lock(c);
190                 return false;
191         }
192
193         // Carve span into sequence of blocks.
194         tailp = &s->freelist;
195         p = (byte*)(s->start << PageShift);
196         s->gcref = (uint32*)(p + size*n);
197         for(i=0; i<n; i++) {
198                 v = (MLink*)p;
199                 *tailp = v;
200                 tailp = &v->next;
201                 p += size;
202         }
203         *tailp = nil;
204
205         runtime_lock(c);
206         c->nfree += n;
207         runtime_MSpanList_Insert(&c->nonempty, s);
208         return true;
209 }