#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;
Finalizer fin[1];
};
-
static G *fing;
static FinBlock *finq; // list of finalizers that are to be executed
static FinBlock *finc; // cache of free blocks
scanblock(v, size);
}
-struct root_list {
- struct root_list *next;
- struct root {
- void *decl;
- size_t size;
- } roots[];
-};
-
static struct root_list* roots;
void
byte *p;
MCache *c;
byte *arena_start;
+ int64 now;
m = runtime_m();
arena_start = runtime_mheap.arena_start;
+ now = runtime_nanotime();
for(;;) {
s = work.spans;
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;
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
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;
}
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++;
(unsigned long long) mstats.nmalloc, (unsigned long long)mstats.nfree,
(unsigned long long) 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.
{
M *m;
- // 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 = runtime_m();
m->gcing = 1;
runtime_stoptheworld();
cachestats();
*stats = mstats;
m->gcing = 0;
- runtime_semrelease(&gcsema);
+ runtime_semrelease(&runtime_worldsema);
runtime_starttheworld(false);
}