]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR go/60931 (libgo has issues when page size is not 4k)
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 25 Apr 2014 04:29:07 +0000 (04:29 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 25 Apr 2014 04:29:07 +0000 (04:29 +0000)
PR go/60931

runtime: Fix garbage collector issue with non 4kB system page size

The go garbage collector tracks memory in terms of 4kB pages.
Most of the code checks getpagesize() at runtime and does the
right thing.

On a 64kB ppc64 box I see SEGVs in long running processes
which has been diagnosed as a bug in scavengelist.
scavengelist does a madvise(MADV_DONTNEED) without rounding
the arguments to the system page size.  A strace of one of the
failures shows the problem:

madvise(0xc211030000, 4096, MADV_DONTNEED) = 0

The kernel rounds the length up to 64kB and we mark 60kB of
valid data as no longer needed.

Round start up to a system page and end down before calling
madvise.

From-SVN: r209777

libgo/runtime/mheap.c

index fee493c1367f09f9495c2d3fc689b89ef1ddfb3c..1b8ab79160610b9cbb5b7acd069fd69949786457 100644 (file)
@@ -387,7 +387,7 @@ forcegchelper(void *vnote)
 static uintptr
 scavengelist(MSpan *list, uint64 now, uint64 limit)
 {
-       uintptr released, sumreleased;
+       uintptr released, sumreleased, start, end, pagesize;
        MSpan *s;
 
        if(runtime_MSpanList_IsEmpty(list))
@@ -400,7 +400,17 @@ scavengelist(MSpan *list, uint64 now, uint64 limit)
                        mstats.heap_released += released;
                        sumreleased += released;
                        s->npreleased = s->npages;
-                       runtime_SysUnused((void*)(s->start << PageShift), s->npages << PageShift);
+
+                       start = s->start << PageShift;
+                       end = start + (s->npages << PageShift);
+
+                       // Round start up and end down to ensure we
+                       // are acting on entire pages.
+                       pagesize = getpagesize();
+                       start = ROUND(start, pagesize);
+                       end &= ~(pagesize - 1);
+                       if(end > start)
+                               runtime_SysUnused((void*)start, end - start);
                }
        }
        return sumreleased;