LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 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 // Garbage collector -- step 0. | 5 // Garbage collector -- step 0. |
6 // | 6 // |
7 // Stop the world, mark and sweep garbage collector. | 7 // Stop the world, mark and sweep garbage collector. |
8 // NOT INTENDED FOR PRODUCTION USE. | 8 // NOT INTENDED FOR PRODUCTION USE. |
9 // | 9 // |
10 // A mark and sweep collector provides a way to exercise | 10 // A mark and sweep collector provides a way to exercise |
11 // and test the memory allocator and the stack walking machinery | 11 // and test the memory allocator and the stack walking machinery |
12 // without also needing to get reference counting | 12 // without also needing to get reference counting |
13 // exactly right. | 13 // exactly right. |
14 | 14 |
15 #include "runtime.h" | 15 #include "runtime.h" |
16 #include "malloc.h" | 16 #include "malloc.h" |
17 | 17 |
18 enum { | 18 enum { |
19 Debug = 0 | 19 Debug = 0 |
20 }; | 20 }; |
21 | 21 |
22 extern byte data[]; | 22 extern byte data[]; |
23 extern byte etext[]; | 23 extern byte etext[]; |
24 extern byte end[]; | 24 extern byte end[]; |
25 | 25 |
| 26 static G *fing; |
26 static Finalizer *finq; | 27 static Finalizer *finq; |
27 static void sweepblock(byte*, int64, uint32*, int32); | 28 static void sweepblock(byte*, int64, uint32*, int32); |
28 static void runfinq(void*); | 29 static void runfinq(void); |
29 | 30 |
30 enum { | 31 enum { |
31 PtrSize = sizeof(void*) | 32 PtrSize = sizeof(void*) |
32 }; | 33 }; |
33 | 34 |
34 static void | 35 static void |
35 scanblock(int32 depth, byte *b, int64 n) | 36 scanblock(int32 depth, byte *b, int64 n) |
36 { | 37 { |
37 int32 off; | 38 int32 off; |
38 void *obj; | 39 void *obj; |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 if(mheap.Lock.key != 0) | 293 if(mheap.Lock.key != 0) |
293 throw("mheap locked during gc"); | 294 throw("mheap locked during gc"); |
294 if(force || mstats.heap_alloc >= mstats.next_gc) { | 295 if(force || mstats.heap_alloc >= mstats.next_gc) { |
295 mark(); | 296 mark(); |
296 sweep(); | 297 sweep(); |
297 stealcache(); | 298 stealcache(); |
298 mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/1
00; | 299 mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/1
00; |
299 } | 300 } |
300 m->gcing = 0; | 301 m->gcing = 0; |
301 | 302 |
302 // kick off goroutines to run queued finalizers | |
303 m->locks++; // disable gc during the mallocs in newproc | 303 m->locks++; // disable gc during the mallocs in newproc |
304 fp = finq; | 304 fp = finq; |
305 » if(fp != nil) | 305 » if(fp != nil) { |
306 » » newproc1((byte*)runfinq, (byte*)&fp, sizeof(fp), 0); | 306 » » // kick off or wake up goroutine to run queued finalizers |
307 » finq = nil; | 307 » » if(fing == nil) |
| 308 » » » fing = newproc1((byte*)runfinq, nil, 0, 0); |
| 309 » » else if(fing->status == Gwaiting) |
| 310 » » » ready(fing); |
| 311 » } |
308 m->locks--; | 312 m->locks--; |
309 | 313 |
310 t1 = nanotime(); | 314 t1 = nanotime(); |
311 mstats.numgc++; | 315 mstats.numgc++; |
312 mstats.pause_ns += t1 - t0; | 316 mstats.pause_ns += t1 - t0; |
313 if(mstats.debuggc) | 317 if(mstats.debuggc) |
314 printf("pause %D\n", t1-t0); | 318 printf("pause %D\n", t1-t0); |
315 semrelease(&gcsema); | 319 semrelease(&gcsema); |
316 starttheworld(); | 320 starttheworld(); |
317 ········ | 321 ········ |
318 // give the queued finalizers, if any, a chance to run | 322 // give the queued finalizers, if any, a chance to run |
319 if(fp != nil) | 323 if(fp != nil) |
320 gosched(); | 324 gosched(); |
321 } | 325 } |
322 | 326 |
323 static void | 327 static void |
324 runfinq(void *v) | 328 runfinq(void) |
325 { | 329 { |
326 Finalizer *f, *next; | 330 Finalizer *f, *next; |
327 byte *frame; | 331 byte *frame; |
328 »······· | 332 |
329 » f = v; | 333 » for(;;) { |
330 » for(; f; f=next) { | 334 » » // There's no need for a lock in this section |
331 » » next = f->next; | 335 » » // because it only conflicts with the garbage |
332 » » frame = mal(sizeof(uintptr) + f->nret); | 336 » » // collector, and the garbage collector only |
333 » » *(void**)frame = f->arg; | 337 » » // runs when everyone else is stopped, and |
334 » » reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret); | 338 » » // runfinq only stops at the gosched() or |
335 » » free(frame); | 339 » » // during the calls in the for loop. |
336 » » f->fn = nil; | 340 » » f = finq; |
337 » » f->arg = nil; | 341 » » finq = nil; |
338 » » f->next = nil; | 342 » » if(f == nil) { |
339 » } | 343 » » » g->status = Gwaiting; |
340 » gc(1);» // force another gc to clean up the finalizer entries | 344 » » » gosched(); |
341 } | 345 » » » continue; |
| 346 » » } |
| 347 » » for(; f; f=next) { |
| 348 » » » next = f->next; |
| 349 » » » frame = mal(sizeof(uintptr) + f->nret); |
| 350 » » » *(void**)frame = f->arg; |
| 351 » » » reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->n
ret); |
| 352 » » » free(frame); |
| 353 » » » f->fn = nil; |
| 354 » » » f->arg = nil; |
| 355 » » » f->next = nil; |
| 356 » » } |
| 357 » » gc(1);» // trigger another gc to clean up the finalized objects,
if possible |
| 358 » } |
| 359 } |
LEFT | RIGHT |