5858 gcMallocs uint64 // total number of allocations
5959 gcFrees uint64 // total number of objects freed
6060 gcFreedBlocks uint64 // total number of freed blocks
61+ gcLock task.PMutex // lock to avoid race conditions on multicore systems
6162)
6263
6364// zeroSizedAlloc is just a sentinel that gets returned when allocating 0 bytes.
@@ -318,6 +319,10 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
318319 runtimePanicAt (returnAddress (0 ), "heap alloc in interrupt" )
319320 }
320321
322+ // Make sure there are no concurrent allocations. The heap is not currently
323+ // designed for concurrent alloc/GC.
324+ gcLock .Lock ()
325+
321326 gcTotalAlloc += uint64 (size )
322327 gcMallocs ++
323328
@@ -400,6 +405,9 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
400405 i .setState (blockStateTail )
401406 }
402407
408+ // We've claimed this allocation, now we can unlock the heap.
409+ gcLock .Unlock ()
410+
403411 // Return a pointer to this allocation.
404412 pointer := thisAlloc .pointer ()
405413 if preciseHeap {
@@ -445,7 +453,9 @@ func free(ptr unsafe.Pointer) {
445453
446454// GC performs a garbage collection cycle.
447455func GC () {
456+ gcLock .Lock ()
448457 runGC ()
458+ gcLock .Unlock ()
449459}
450460
451461// runGC performs a garbage collection cycle. It is the internal implementation
@@ -721,6 +731,7 @@ func dumpHeap() {
721731// The returned memory statistics are up to date as of the
722732// call to ReadMemStats. This would not do GC implicitly for you.
723733func ReadMemStats (m * MemStats ) {
734+ gcLock .Lock ()
724735 m .HeapIdle = 0
725736 m .HeapInuse = 0
726737 for block := gcBlock (0 ); block < endBlock ; block ++ {
@@ -740,6 +751,7 @@ func ReadMemStats(m *MemStats) {
740751 m .Sys = uint64 (heapEnd - heapStart )
741752 m .HeapAlloc = (gcTotalBlocks - gcFreedBlocks ) * uint64 (bytesPerBlock )
742753 m .Alloc = m .HeapAlloc
754+ gcLock .Unlock ()
743755}
744756
745757func SetFinalizer (obj interface {}, finalizer interface {}) {
0 commit comments