diff options
Diffstat (limited to 'src/pkg/runtime/mgc0.c')
-rw-r--r-- | src/pkg/runtime/mgc0.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 78daa7836..e043864c1 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -52,6 +52,21 @@ enum { #define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial) +// Holding worldsema grants an M the right to try to stop the world. +// The procedure is: +// +// runtime·semacquire(&runtime·worldsema); +// m->gcing = 1; +// runtime·stoptheworld(); +// +// ... do stuff ... +// +// m->gcing = 0; +// runtime·semrelease(&runtime·worldsema); +// runtime·starttheworld(); +// +uint32 runtime·worldsema = 1; + // TODO: Make these per-M. static uint64 nhandoff; @@ -85,7 +100,7 @@ struct FinBlock extern byte data[]; extern byte etext[]; -extern byte end[]; +extern byte ebss[]; static G *fing; static FinBlock *finq; // list of finalizers that are to be executed @@ -630,10 +645,7 @@ mark(void (*scan)(byte*, int64)) FinBlock *fb; // mark data+bss. - // skip runtime·mheap itself, which has no interesting pointers - // and is mostly zeroed and would not otherwise be paged in. - scan(data, (byte*)&runtime·mheap - data); - scan((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1)); + scan(data, ebss - data); // mark stacks for(gp=runtime·allg; gp!=nil; gp=gp->alllink) { @@ -716,8 +728,10 @@ sweep(void) byte *p; MCache *c; byte *arena_start; + int64 now; arena_start = runtime·mheap.arena_start; + now = runtime·nanotime(); for(;;) { s = work.spans; @@ -726,6 +740,11 @@ sweep(void) if(!runtime·casp(&work.spans, s, s->allnext)) continue; + // Stamp newly unused spans. The scavenger will use that + // info to potentially give back some pages to the OS. + if(s->state == MSpanFree && s->unusedsince == 0) + s->unusedsince = now; + if(s->state != MSpanInUse) continue; @@ -812,11 +831,6 @@ runtime·gchelper(void) runtime·notewakeup(&work.alldone); } -// Semaphore, not Lock, so that the goroutine -// reschedules when there is contention rather -// than spinning. -static uint32 gcsema = 1; - // Initialized from $GOGC. GOGC=off means no gc. // // Next gc is after we've allocated an extra amount of @@ -899,9 +913,9 @@ runtime·gc(int32 force) if(gcpercent < 0) return; - runtime·semacquire(&gcsema); + runtime·semacquire(&runtime·worldsema); if(!force && mstats.heap_alloc < mstats.next_gc) { - runtime·semrelease(&gcsema); + runtime·semrelease(&runtime·worldsema); return; } @@ -963,6 +977,7 @@ runtime·gc(int32 force) obj1 = mstats.nmalloc - mstats.nfree; t3 = runtime·nanotime(); + mstats.last_gc = t3; mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t3 - t0; mstats.pause_total_ns += t3 - t0; mstats.numgc++; @@ -976,8 +991,9 @@ runtime·gc(int32 force) mstats.nmalloc, mstats.nfree, nhandoff); } - - runtime·semrelease(&gcsema); + + runtime·MProf_GC(); + runtime·semrelease(&runtime·worldsema); // If we could have used another helper proc, start one now, // in the hope that it will be available next time. @@ -997,18 +1013,19 @@ runtime·gc(int32 force) } void -runtime·UpdateMemStats(void) +runtime·ReadMemStats(MStats *stats) { - // Have to acquire gcsema to stop the world, + // Have to acquire worldsema to stop the world, // because stoptheworld can only be used by // one goroutine at a time, and there might be // a pending garbage collection already calling it. - runtime·semacquire(&gcsema); + runtime·semacquire(&runtime·worldsema); m->gcing = 1; runtime·stoptheworld(); cachestats(); + *stats = mstats; m->gcing = 0; - runtime·semrelease(&gcsema); + runtime·semrelease(&runtime·worldsema); runtime·starttheworld(false); } |