5757 gcMallocs uint64 // total number of allocations
5858 gcFrees uint64 // total number of objects freed
5959 gcFreedBlocks uint64 // total number of freed blocks
60+ gcLock task.PMutex // lock to avoid race conditions on multicore systems
6061)
6162
6263// zeroSizedAlloc is just a sentinel that gets returned when allocating 0 bytes.
@@ -283,6 +284,10 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
283284 runtimePanicAt (returnAddress (0 ), "heap alloc in interrupt" )
284285 }
285286
287+ // Make sure there are no concurrent allocations. The heap is not currently
288+ // designed for concurrent alloc/GC.
289+ gcLock .Lock ()
290+
286291 gcTotalAlloc += uint64 (size )
287292 gcMallocs ++
288293
@@ -365,6 +370,9 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
365370 i .setState (blockStateTail )
366371 }
367372
373+ // We've claimed this allocation, now we can unlock the heap.
374+ gcLock .Unlock ()
375+
368376 // Return a pointer to this allocation.
369377 pointer := thisAlloc .pointer ()
370378 if preciseHeap {
@@ -410,7 +418,9 @@ func free(ptr unsafe.Pointer) {
410418
411419// GC performs a garbage collection cycle.
412420func GC () {
421+ gcLock .Lock ()
413422 runGC ()
423+ gcLock .Unlock ()
414424}
415425
416426// runGC performs a garbage collection cycle. It is the internal implementation
@@ -679,6 +689,7 @@ func dumpHeap() {
679689// The returned memory statistics are up to date as of the
680690// call to ReadMemStats. This would not do GC implicitly for you.
681691func ReadMemStats (m * MemStats ) {
692+ gcLock .Lock ()
682693 m .HeapIdle = 0
683694 m .HeapInuse = 0
684695 for block := gcBlock (0 ); block < endBlock ; block ++ {
@@ -698,6 +709,7 @@ func ReadMemStats(m *MemStats) {
698709 m .Sys = uint64 (heapEnd - heapStart )
699710 m .HeapAlloc = (gcTotalBlocks - gcFreedBlocks ) * uint64 (bytesPerBlock )
700711 m .Alloc = m .HeapAlloc
712+ gcLock .Unlock ()
701713}
702714
703715func SetFinalizer (obj interface {}, finalizer interface {}) {
0 commit comments