diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-03-06 16:19:05 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-03-06 16:19:05 +0000 |
commit | c271e224c2e6bcda1068754def0b0cfd6a2b2958 (patch) | |
tree | 122e64d46042099f2d5b39e31532f3d0358b5ad3 /libgo/go/runtime | |
parent | 81b0d9065c3c832af6621e79e9d9b3c2bc684122 (diff) | |
download | gcc-c271e224c2e6bcda1068754def0b0cfd6a2b2958.zip gcc-c271e224c2e6bcda1068754def0b0cfd6a2b2958.tar.gz gcc-c271e224c2e6bcda1068754def0b0cfd6a2b2958.tar.bz2 |
libgo: Upgrade to Go 1.4.2 release.
From-SVN: r221245
Diffstat (limited to 'libgo/go/runtime')
-rw-r--r-- | libgo/go/runtime/crash_cgo_test.go | 68 | ||||
-rw-r--r-- | libgo/go/runtime/hashmap.go | 35 | ||||
-rw-r--r-- | libgo/go/runtime/hashmap_fast.go | 12 | ||||
-rw-r--r-- | libgo/go/runtime/mprof.go | 14 | ||||
-rw-r--r-- | libgo/go/runtime/os_plan9.go | 2 | ||||
-rw-r--r-- | libgo/go/runtime/sigqueue.go | 9 | ||||
-rw-r--r-- | libgo/go/runtime/syscall_windows.go | 12 |
7 files changed, 119 insertions, 33 deletions
diff --git a/libgo/go/runtime/crash_cgo_test.go b/libgo/go/runtime/crash_cgo_test.go index 972eedc..29f90fa 100644 --- a/libgo/go/runtime/crash_cgo_test.go +++ b/libgo/go/runtime/crash_cgo_test.go @@ -7,6 +7,7 @@ package runtime_test import ( + "os/exec" "runtime" "strings" "testing" @@ -50,6 +51,30 @@ func TestCgoExternalThreadPanic(t *testing.T) { } } +func TestCgoExternalThreadSIGPROF(t *testing.T) { + // issue 9456. + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("no pthreads on %s", runtime.GOOS) + case "darwin": + // static constructor needs external linking, but we don't support + // external linking on OS X 10.6. + out, err := exec.Command("uname", "-r").Output() + if err != nil { + t.Fatalf("uname -r failed: %v", err) + } + // OS X 10.6 == Darwin 10.x + if strings.HasPrefix(string(out), "10.") { + t.Skipf("no external linking on OS X 10.6") + } + } + got := executeTest(t, cgoExternalThreadSIGPROFSource, nil) + want := "OK\n" + if got != want { + t.Fatalf("expected %q, but got %q", want, got) + } +} + const cgoSignalDeadlockSource = ` package main @@ -194,3 +219,46 @@ start(void) printf("_beginthreadex failed\n"); } ` + +const cgoExternalThreadSIGPROFSource = ` +package main + +/* +#include <stdint.h> +#include <signal.h> +#include <pthread.h> + +volatile int32_t spinlock; + +static void *thread1(void *p) { + (void)p; + while (spinlock == 0) + ; + pthread_kill(pthread_self(), SIGPROF); + spinlock = 0; + return NULL; +} +__attribute__((constructor)) void issue9456() { + pthread_t tid; + pthread_create(&tid, 0, thread1, NULL); +} +*/ +import "C" + +import ( + "runtime" + "sync/atomic" + "unsafe" +) + +func main() { + // This test intends to test that sending SIGPROF to foreign threads + // before we make any cgo call will not abort the whole process, so + // we cannot make any cgo call here. See http://golang.org/issue/9456. + atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1) + for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 { + runtime.Gosched() + } + println("OK") +} +` diff --git a/libgo/go/runtime/hashmap.go b/libgo/go/runtime/hashmap.go index b4e6244..791af8c 100644 --- a/libgo/go/runtime/hashmap.go +++ b/libgo/go/runtime/hashmap.go @@ -117,12 +117,12 @@ type hmap struct { // A bucket for a Go map. type bmap struct { - tophash [bucketCnt]uint8 - overflow *bmap + tophash [bucketCnt]uint8 // Followed by bucketCnt keys and then bucketCnt values. // NOTE: packing all the keys together and then all the values together makes the // code a bit more complicated than alternating key/value/key/value/... but it allows // us to eliminate padding which would be needed for, e.g., map[int64]int8. + // Followed by an overflow pointer. } // A hash iteration structure. @@ -149,6 +149,13 @@ func evacuated(b *bmap) bool { return h > empty && h < minTopHash } +func (b *bmap) overflow(t *maptype) *bmap { + return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) +} +func (b *bmap) setoverflow(t *maptype, ovf *bmap) { + *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) = ovf +} + func makemap(t *maptype, hint int64) *hmap { if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) { gothrow("bad hmap size") @@ -275,7 +282,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { return v } } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero) } @@ -323,7 +330,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) return v, true } } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero), false } @@ -366,7 +373,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe return k, v } } - b = b.overflow + b = b.overflow(t) if b == nil { return nil, nil } @@ -437,10 +444,11 @@ again: memmove(v2, val, uintptr(t.elem.size)) return } - if b.overflow == nil { + ovf := b.overflow(t) + if ovf == nil { break } - b = b.overflow + b = ovf } // did not find mapping for key. Allocate new cell & add entry. @@ -455,7 +463,7 @@ again: memstats.next_gc = memstats.heap_alloc } newb := (*bmap)(newobject(t.bucket)) - b.overflow = newb + b.setoverflow(t, newb) inserti = &newb.tophash[0] insertk = add(unsafe.Pointer(newb), dataOffset) insertv = add(insertk, bucketCnt*uintptr(t.keysize)) @@ -525,7 +533,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { h.count-- return } - b = b.overflow + b = b.overflow(t) if b == nil { return } @@ -720,7 +728,7 @@ next: return } } - b = b.overflow + b = b.overflow(t) i = 0 goto next } @@ -778,7 +786,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { yk := add(unsafe.Pointer(y), dataOffset) xv := add(xk, bucketCnt*uintptr(t.keysize)) yv := add(yk, bucketCnt*uintptr(t.keysize)) - for ; b != nil; b = b.overflow { + for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) v := add(k, bucketCnt*uintptr(t.keysize)) for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) { @@ -828,7 +836,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { memstats.next_gc = memstats.heap_alloc } newx := (*bmap)(newobject(t.bucket)) - x.overflow = newx + x.setoverflow(t, newx) x = newx xi = 0 xk = add(unsafe.Pointer(x), dataOffset) @@ -855,7 +863,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { memstats.next_gc = memstats.heap_alloc } newy := (*bmap)(newobject(t.bucket)) - y.overflow = newy + y.setoverflow(t, newy) y = newy yi = 0 yk = add(unsafe.Pointer(y), dataOffset) @@ -881,7 +889,6 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { // Unlink the overflow buckets & clear key/value to help GC. if h.flags&oldIterator == 0 { b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) - b.overflow = nil memclr(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset) } } diff --git a/libgo/go/runtime/hashmap_fast.go b/libgo/go/runtime/hashmap_fast.go index 8e21e02..afa6ecc 100644 --- a/libgo/go/runtime/hashmap_fast.go +++ b/libgo/go/runtime/hashmap_fast.go @@ -43,7 +43,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { } return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)) } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero) } @@ -85,7 +85,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { } return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)), true } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero), false } @@ -127,7 +127,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { } return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)) } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero) } @@ -169,7 +169,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { } return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)), true } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero), false } @@ -271,7 +271,7 @@ dohash: return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)) } } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero) } @@ -371,7 +371,7 @@ dohash: return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true } } - b = b.overflow + b = b.overflow(t) if b == nil { return unsafe.Pointer(t.elem.zero), false } diff --git a/libgo/go/runtime/mprof.go b/libgo/go/runtime/mprof.go index d409c6c..f4da45f 100644 --- a/libgo/go/runtime/mprof.go +++ b/libgo/go/runtime/mprof.go @@ -575,20 +575,16 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) { // If all is true, Stack formats stack traces of all other goroutines // into buf after the trace for the current goroutine. func Stack(buf []byte, all bool) int { - mp := acquirem() - gp := mp.curg if all { semacquire(&worldsema, false) - mp.gcing = 1 - releasem(mp) + gp := getg() + gp.m.gcing = 1 onM(stoptheworld) - if mp != acquirem() { - gothrow("Stack: rescheduled") - } } n := 0 if len(buf) > 0 { + gp := getg() sp := getcallersp(unsafe.Pointer(&buf)) pc := getcallerpc(unsafe.Pointer(&buf)) onM(func() { @@ -605,11 +601,11 @@ func Stack(buf []byte, all bool) int { } if all { - mp.gcing = 0 + gp := getg() + gp.m.gcing = 0 semrelease(&worldsema) onM(starttheworld) } - releasem(mp) return n } diff --git a/libgo/go/runtime/os_plan9.go b/libgo/go/runtime/os_plan9.go index 20e47bf..10e5531 100644 --- a/libgo/go/runtime/os_plan9.go +++ b/libgo/go/runtime/os_plan9.go @@ -6,6 +6,8 @@ package runtime import "unsafe" +const _SIGPROF = 0 // dummy value for badsignal + func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 func seek(fd int32, offset int64, whence int32) int64 diff --git a/libgo/go/runtime/sigqueue.go b/libgo/go/runtime/sigqueue.go index 2d9c24d..fed4560 100644 --- a/libgo/go/runtime/sigqueue.go +++ b/libgo/go/runtime/sigqueue.go @@ -154,6 +154,15 @@ func signal_disable(s uint32) { // This runs on a foreign stack, without an m or a g. No stack split. //go:nosplit func badsignal(sig uintptr) { + // Some external libraries, for example, OpenBLAS, create worker threads in + // a global constructor. If we're doing cpu profiling, and the SIGPROF signal + // comes to one of the foreign threads before we make our first cgo call, the + // call to cgocallback below will bring down the whole process. + // It's better to miss a few SIGPROF signals than to abort in this case. + // See http://golang.org/issue/9456. + if _SIGPROF != 0 && sig == _SIGPROF && needextram != 0 { + return + } cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) } diff --git a/libgo/go/runtime/syscall_windows.go b/libgo/go/runtime/syscall_windows.go index efbcab5..51004b7 100644 --- a/libgo/go/runtime/syscall_windows.go +++ b/libgo/go/runtime/syscall_windows.go @@ -8,6 +8,8 @@ import ( "unsafe" ) +const _SIGPROF = 0 // dummy value for badsignal + type callbacks struct { lock mutex ctxt [cb_max]*wincallbackcontext @@ -52,11 +54,13 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { panic("compilecallback: output parameter size is wrong") } argsize := uintptr(0) - for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] { - if (*t).size > uintptrSize { - panic("compilecallback: input parameter size is wrong") + if len(ft.in) > 0 { + for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] { + if (*t).size > uintptrSize { + panic("compilecallback: input parameter size is wrong") + } + argsize += uintptrSize } - argsize += uintptrSize } lock(&cbs.lock) |