From: Dmitriy Vyukov Date: Wed, 22 May 2013 19:04:46 +0000 (+0400) Subject: runtime: properly synchronize GC and finalizer goroutine X-Git-Tag: go1.2rc2~1440 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=72c4ee1a9daba7b952c9440851d3b9ebbaa58458;p=gostls13.git runtime: properly synchronize GC and finalizer goroutine This is needed for preemptive scheduler, because the goroutine can be preempted at surprising points. R=golang-dev, iant CC=golang-dev https://golang.org/cl/9376043 --- diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 28cc4353ef..1ea3a1482e 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -2030,18 +2030,6 @@ gc(struct gc_args *args) mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100; m->gcing = 0; - if(finq != nil) { - m->locks++; // disable gc during the mallocs in newproc - // kick off or wake up goroutine to run queued finalizers - if(fing == nil) - fing = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc); - else if(fingwait) { - fingwait = 0; - runtime·ready(fing); - } - m->locks--; - } - heap1 = mstats.heap_alloc; obj1 = mstats.nmalloc - mstats.nfree; @@ -2089,9 +2077,19 @@ gc(struct gc_args *args) runtime·semrelease(&runtime·worldsema); runtime·starttheworld(); - // give the queued finalizers, if any, a chance to run - if(finq != nil) + if(finq != nil) { + runtime·lock(&finlock); + // kick off or wake up goroutine to run queued finalizers + if(fing == nil) + fing = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc); + else if(fingwait) { + fingwait = 0; + runtime·ready(fing); + } + runtime·unlock(&finlock); + // give the queued finalizers, if any, a chance to run runtime·gosched(); + } } void @@ -2176,19 +2174,15 @@ runfinq(void) frame = nil; framecap = 0; for(;;) { - // There's no need for a lock in this section - // because it only conflicts with the garbage - // collector, and the garbage collector only - // runs when everyone else is stopped, and - // runfinq only stops at the gosched() or - // during the calls in the for loop. + runtime·lock(&finlock); fb = finq; finq = nil; if(fb == nil) { fingwait = 1; - runtime·park(nil, nil, "finalizer wait"); + runtime·park(runtime·unlock, &finlock, "finalizer wait"); continue; } + runtime·unlock(&finlock); if(raceenabled) runtime·racefingo(); for(; fb; fb=next) {