Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3634)

Delta Between Two Patch Sets: src/pkg/runtime/stack.c

Issue 10136043: code review 10136043: runtime: refactor mallocgc (Closed)
Left Patch Set: diff -r 71375a634b9a https://dvyukov%40google.com@code.google.com/p/go/ Created 11 years, 9 months ago
Right Patch Set: diff -r 654ca7de0282 https://dvyukov%40google.com@code.google.com/p/go/ Created 11 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/runtime/proc.c ('k') | src/pkg/runtime/string.goc » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2013 The Go Authors. All rights reserved. 1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 #include "runtime.h" 5 #include "runtime.h"
6 #include "arch_GOARCH.h" 6 #include "arch_GOARCH.h"
7 #include "malloc.h" 7 #include "malloc.h"
8 #include "stack.h" 8 #include "stack.h"
9
10 enum
11 {
12 StackDebug = 0,
13 };
9 14
10 typedef struct StackCacheNode StackCacheNode; 15 typedef struct StackCacheNode StackCacheNode;
11 struct StackCacheNode 16 struct StackCacheNode
12 { 17 {
13 StackCacheNode *next; 18 StackCacheNode *next;
14 void* batch[StackCacheBatch-1]; 19 void* batch[StackCacheBatch-1];
15 }; 20 };
16 21
17 static StackCacheNode *stackcache; 22 static StackCacheNode *stackcache;
18 static Lock stackcachemu; 23 static Lock stackcachemu;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 if(m->stackcachecnt == 0) 98 if(m->stackcachecnt == 0)
94 stackcacherefill(); 99 stackcacherefill();
95 pos = m->stackcachepos; 100 pos = m->stackcachepos;
96 pos = (pos - 1) % StackCacheSize; 101 pos = (pos - 1) % StackCacheSize;
97 v = m->stackcache[pos]; 102 v = m->stackcache[pos];
98 m->stackcachepos = pos; 103 m->stackcachepos = pos;
99 m->stackcachecnt--; 104 m->stackcachecnt--;
100 m->stackinuse++; 105 m->stackinuse++;
101 return v; 106 return v;
102 } 107 }
103 » return runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZeroize|Fla gNoInvokeGC); 108 » return runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZero|FlagNo InvokeGC);
104 } 109 }
105 110
106 void 111 void
107 runtime·stackfree(void *v, uintptr n) 112 runtime·stackfree(void *v, uintptr n)
108 { 113 {
109 uint32 pos; 114 uint32 pos;
110 115
111 if(n == FixedStack || m->mallocing || m->gcing) { 116 if(n == FixedStack || m->mallocing || m->gcing) {
112 if(m->stackcachecnt == StackCacheSize) 117 if(m->stackcachecnt == StackCacheSize)
113 stackcacherelease(); 118 stackcacherelease();
114 pos = m->stackcachepos; 119 pos = m->stackcachepos;
115 m->stackcache[pos] = v; 120 m->stackcache[pos] = v;
116 m->stackcachepos = (pos + 1) % StackCacheSize; 121 m->stackcachepos = (pos + 1) % StackCacheSize;
117 m->stackcachecnt++; 122 m->stackcachecnt++;
118 m->stackinuse--; 123 m->stackinuse--;
119 return; 124 return;
120 } 125 }
121 runtime·free(v); 126 runtime·free(v);
122 } 127 }
123 128
124 // Called from runtime·lessstack when returning from a function which 129 // Called from runtime·lessstack when returning from a function which
125 // allocated a new stack segment. The function's return value is in 130 // allocated a new stack segment. The function's return value is in
126 // m->cret. 131 // m->cret.
127 void 132 void
128 runtime·oldstack(void) 133 runtime·oldstack(void)
129 { 134 {
130 Stktop *top; 135 Stktop *top;
131 Gobuf label;
132 uint32 argsize; 136 uint32 argsize;
133 byte *sp, *old; 137 byte *sp, *old;
134 uintptr *src, *dst, *dstend; 138 uintptr *src, *dst, *dstend;
135 G *gp; 139 G *gp;
136 int64 goid; 140 int64 goid;
137 141 » int32 oldstatus;
138 //printf("oldstack m->cret=%p\n", m->cret);
139 142
140 gp = m->curg; 143 gp = m->curg;
141 top = (Stktop*)gp->stackbase; 144 top = (Stktop*)gp->stackbase;
142 old = (byte*)gp->stackguard - StackGuard; 145 old = (byte*)gp->stackguard - StackGuard;
143 sp = (byte*)top; 146 sp = (byte*)top;
144 argsize = top->argsize; 147 argsize = top->argsize;
148
149 if(StackDebug) {
150 runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret =%p argsize=%p\n",
151 top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, m->cret, (u intptr)argsize);
152 }
153
154 // gp->status is usually Grunning, but it could be Gsyscall if a stack s plit
155 // happens during a function call inside entersyscall.
156 oldstatus = gp->status;
157 ········
158 gp->sched = top->gobuf;
159 gp->sched.ret = m->cret;
160 m->cret = 0; // drop reference
161 gp->status = Gwaiting;
162 gp->waitreason = "stack unsplit";
163
145 if(argsize > 0) { 164 if(argsize > 0) {
146 sp -= argsize; 165 sp -= argsize;
147 dst = (uintptr*)top->argp; 166 dst = (uintptr*)top->argp;
148 dstend = dst + argsize/sizeof(*dst); 167 dstend = dst + argsize/sizeof(*dst);
149 src = (uintptr*)sp; 168 src = (uintptr*)sp;
150 while(dst < dstend) 169 while(dst < dstend)
151 *dst++ = *src++; 170 *dst++ = *src++;
152 } 171 }
153 goid = top->gobuf.g->goid; // fault if g is bad, before gogo 172 goid = top->gobuf.g->goid; // fault if g is bad, before gogo
154 USED(goid); 173 USED(goid);
155 174
156 label = top->gobuf;
157 gp->stackbase = top->stackbase; 175 gp->stackbase = top->stackbase;
158 gp->stackguard = top->stackguard; 176 gp->stackguard = top->stackguard;
159 gp->stackguard0 = gp->stackguard; 177 gp->stackguard0 = gp->stackguard;
178
160 if(top->free != 0) 179 if(top->free != 0)
161 runtime·stackfree(old, top->free); 180 runtime·stackfree(old, top->free);
162 181
163 » label.ret = m->cret; 182 » gp->status = oldstatus;
164 » m->cret = 0; // drop reference 183 » runtime·gogo(&gp->sched);
165 » runtime·gogo(&label);
166 } 184 }
167 185
168 // Called from reflect·call or from runtime·morestack when a new 186 // Called from reflect·call or from runtime·morestack when a new
169 // stack segment is needed. Allocate a new stack big enough for 187 // stack segment is needed. Allocate a new stack big enough for
170 // m->moreframesize bytes, copy m->moreargsize bytes to the new frame, 188 // m->moreframesize bytes, copy m->moreargsize bytes to the new frame,
171 // and then act as though runtime·lessstack called the function at 189 // and then act as though runtime·lessstack called the function at
172 // m->morepc. 190 // m->morepc.
173 void 191 void
174 runtime·newstack(void) 192 runtime·newstack(void)
175 { 193 {
176 » int32 framesize, minalloc, argsize; 194 » int32 framesize, argsize, oldstatus;
177 Stktop *top; 195 Stktop *top;
178 byte *stk; 196 byte *stk;
179 uintptr sp; 197 uintptr sp;
180 uintptr *src, *dst, *dstend; 198 uintptr *src, *dst, *dstend;
181 G *gp; 199 G *gp;
182 Gobuf label; 200 Gobuf label;
183 bool reflectcall; 201 bool reflectcall;
184 uintptr free; 202 uintptr free;
185 203
204 // gp->status is usually Grunning, but it could be Gsyscall if a stack s plit
205 // happens during a function call inside entersyscall.
206 gp = m->curg;
207 oldstatus = gp->status;
208
186 framesize = m->moreframesize; 209 framesize = m->moreframesize;
187 argsize = m->moreargsize; 210 argsize = m->moreargsize;
188 » gp = m->curg; 211 » gp->status = Gwaiting;
189 212 » gp->waitreason = "stack split";
190 » if(m->morebuf.sp < gp->stackguard - StackGuard) { 213 » reflectcall = framesize==1;
191 » » runtime·printf("runtime: split stack overflow: %p < %p\n", m->mo rebuf.sp, gp->stackguard - StackGuard); 214 » if(reflectcall)
215 » » framesize = 0;
216
217 » // For reflectcall the context already points to beginning of reflect·ca ll.
218 » if(!reflectcall)
219 » » runtime·rewindmorestack(&gp->sched);
220
221 » sp = gp->sched.sp;
222 » if(thechar == '6' || thechar == '8') {
223 » » // The call to morestack cost a word.
224 » » sp -= sizeof(uintptr);
225 » }
226 » if(StackDebug || sp < gp->stackguard - StackGuard) {
227 » » runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p stack=[%p, %p]\n"
228 » » » "\tmorebuf={pc:%p sp:%p lr:%p}\n"
229 » » » "\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
230 » » » (uintptr)framesize, (uintptr)argsize, sp, gp->stackguard - StackGuard, gp->stackbase,
231 » » » m->morebuf.pc, m->morebuf.sp, m->morebuf.lr,
232 » » » gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt );
233 » }
234 » if(sp < gp->stackguard - StackGuard) {
235 » » runtime·printf("runtime: split stack overflow: %p < %p\n", sp, g p->stackguard - StackGuard);
192 runtime·throw("runtime: split stack overflow"); 236 runtime·throw("runtime: split stack overflow");
193 } 237 }
238
194 if(argsize % sizeof(uintptr) != 0) { 239 if(argsize % sizeof(uintptr) != 0) {
195 runtime·printf("runtime: stack split with misaligned argsize %d\ n", argsize); 240 runtime·printf("runtime: stack split with misaligned argsize %d\ n", argsize);
196 runtime·throw("runtime: stack split argsize"); 241 runtime·throw("runtime: stack split argsize");
197 } 242 }
198 243
199 » minalloc = 0; 244 » if(gp->stackguard0 == (uintptr)StackPreempt) {
200 » reflectcall = framesize==1; 245 » » if(gp == m->g0)
201 » if(reflectcall) { 246 » » » runtime·throw("runtime: preempt g0");
202 » » framesize = 0; 247 » » if(oldstatus == Grunning && m->p == nil)
203 » » // moreframesize_minalloc is only set in runtime·gc(), 248 » » » runtime·throw("runtime: g is running but p is not");
204 » » // that calls newstack via reflect·call(). 249 » » // Be conservative about where we preempt.
205 » » minalloc = m->moreframesize_minalloc; 250 » » // We are interested in preempting user Go code, not runtime cod e.
206 » » m->moreframesize_minalloc = 0; 251 » » if(oldstatus != Grunning || m->locks || m->mallocing || m->gcing || m->p->status != Prunning) {
207 » » if(framesize < minalloc) 252 » » » // Let the goroutine keep running for now.
208 » » » framesize = minalloc; 253 » » » // gp->preempt is set, so it will be preempted next time .
209 » } 254 » » » gp->stackguard0 = gp->stackguard;
210 255 » » » gp->status = oldstatus;
211 » if(reflectcall && minalloc == 0 && m->morebuf.sp - sizeof(Stktop) - args ize - 32 > gp->stackguard) { 256 » » » runtime·gogo(&gp->sched);» // never return
257 » » }
258 » » // Act like goroutine called runtime.Gosched.
259 » » gp->status = oldstatus;
260 » » runtime·gosched0(gp);» // never return
261 » }
262
263 » if(reflectcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > gp->st ackguard) {
212 // special case: called from reflect.call (framesize==1) 264 // special case: called from reflect.call (framesize==1)
213 // to call code with an arbitrary argument size, 265 // to call code with an arbitrary argument size,
214 // and we have enough space on the current stack. 266 // and we have enough space on the current stack.
215 // the new Stktop* is necessary to unwind, but 267 // the new Stktop* is necessary to unwind, but
216 // we don't need to create a new segment. 268 // we don't need to create a new segment.
217 top = (Stktop*)(m->morebuf.sp - sizeof(*top)); 269 top = (Stktop*)(m->morebuf.sp - sizeof(*top));
218 stk = (byte*)gp->stackguard - StackGuard; 270 stk = (byte*)gp->stackguard - StackGuard;
219 free = 0; 271 free = 0;
220 } else { 272 } else {
221 // allocate new segment. 273 // allocate new segment.
222 framesize += argsize; 274 framesize += argsize;
223 framesize += StackExtra; // room for more functions, Stkt op. 275 framesize += StackExtra; // room for more functions, Stkt op.
224 if(framesize < StackMin) 276 if(framesize < StackMin)
225 framesize = StackMin; 277 framesize = StackMin;
226 framesize += StackSystem; 278 framesize += StackSystem;
227 stk = runtime·stackalloc(framesize); 279 stk = runtime·stackalloc(framesize);
228 top = (Stktop*)(stk+framesize-sizeof(*top)); 280 top = (Stktop*)(stk+framesize-sizeof(*top));
229 free = framesize; 281 free = framesize;
230 } 282 }
231 283
232 » if(0) { 284 » if(StackDebug) {
233 » » runtime·printf("newstack framesize=%d argsize=%d morepc=%p morea rgp=%p gobuf=%p, %p top=%p old=%p\n", 285 » » runtime·printf("\t-> new stack [%p, %p]\n", stk, top);
234 » » » framesize, argsize, m->morepc, m->moreargp, m->morebuf.p c, m->morebuf.sp, top, gp->stackbase);
235 } 286 }
236 287
237 top->stackbase = gp->stackbase; 288 top->stackbase = gp->stackbase;
238 top->stackguard = gp->stackguard; 289 top->stackguard = gp->stackguard;
239 top->gobuf = m->morebuf; 290 top->gobuf = m->morebuf;
240 top->argp = m->moreargp; 291 top->argp = m->moreargp;
241 top->argsize = argsize; 292 top->argsize = argsize;
242 top->free = free; 293 top->free = free;
243 m->moreargp = nil; 294 m->moreargp = nil;
244 m->morebuf.pc = (uintptr)nil; 295 m->morebuf.pc = (uintptr)nil;
296 m->morebuf.lr = (uintptr)nil;
245 m->morebuf.sp = (uintptr)nil; 297 m->morebuf.sp = (uintptr)nil;
246 298
247 // copy flag from panic 299 // copy flag from panic
248 top->panic = gp->ispanic; 300 top->panic = gp->ispanic;
249 gp->ispanic = false; 301 gp->ispanic = false;
250 302
251 gp->stackbase = (uintptr)top; 303 gp->stackbase = (uintptr)top;
252 gp->stackguard = (uintptr)stk + StackGuard; 304 gp->stackguard = (uintptr)stk + StackGuard;
253 gp->stackguard0 = gp->stackguard; 305 gp->stackguard0 = gp->stackguard;
254 306
(...skipping 12 matching lines...) Expand all
267 *(void**)sp = nil; 319 *(void**)sp = nil;
268 } 320 }
269 321
270 // Continue as if lessstack had just called m->morepc 322 // Continue as if lessstack had just called m->morepc
271 // (the PC that decided to grow the stack). 323 // (the PC that decided to grow the stack).
272 runtime·memclr((byte*)&label, sizeof label); 324 runtime·memclr((byte*)&label, sizeof label);
273 label.sp = sp; 325 label.sp = sp;
274 label.pc = (uintptr)runtime·lessstack; 326 label.pc = (uintptr)runtime·lessstack;
275 label.g = m->curg; 327 label.g = m->curg;
276 if(reflectcall) 328 if(reflectcall)
277 » » runtime·gostartcallfn(&label, (FuncVal*)m->morepc); 329 » » runtime·gostartcallfn(&label, (FuncVal*)m->cret);
278 else { 330 else {
279 » » // The stack growth code saves ctxt (not ret) in m->cret. 331 » » runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sch ed.ctxt);
280 » » runtime·gostartcall(&label, m->morepc, (void*)m->cret); 332 » » gp->sched.ctxt = nil;
281 » » m->cret = 0; 333 » }
282 » } 334 » gp->status = oldstatus;
283 runtime·gogo(&label); 335 runtime·gogo(&label);
284 336
285 *(int32*)345 = 123; // never return 337 *(int32*)345 = 123; // never return
286 } 338 }
287 339
288 // adjust Gobuf as if it executed a call to fn 340 // adjust Gobuf as if it executed a call to fn
289 // and then did an immediate gosave. 341 // and then did an immediate gosave.
290 void 342 void
291 runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv) 343 runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv)
292 { 344 {
293 runtime·gostartcall(gobuf, fv->fn, fv); 345 runtime·gostartcall(gobuf, fv->fn, fv);
294 } 346 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b