summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/mgc0.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/mgc0.c')
-rw-r--r--src/pkg/runtime/mgc0.c53
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);
}