diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 22:14:32 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 22:14:32 -0700 |
commit | f76df0afd043e05c4b013ab2982e32020839d259 (patch) | |
tree | 447b7688d9af57fad497e61a1cf6789f237c98e9 /src | |
parent | f971d23c25b6660e666da64eedec69e77b9abbd7 (diff) | |
parent | 90ad8a7e5881be7834909c649f994b6b5244c965 (diff) | |
download | golang-f76df0afd043e05c4b013ab2982e32020839d259.tar.gz |
Merge tag 'upstream/1.4.1' into debian-experimental
* tag 'upstream/1.4.1':
Imported Upstream version 1.4.1
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/dist/build.c | 100 | ||||
-rw-r--r-- | src/cmd/gc/reflect.c | 30 | ||||
-rw-r--r-- | src/cmd/go/get.go | 2 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 15 | ||||
-rw-r--r-- | src/cmd/ld/ldelf.c | 5 | ||||
-rw-r--r-- | src/reflect/type.go | 31 | ||||
-rw-r--r-- | src/runtime/cgo/gcc_openbsd_386.c | 40 | ||||
-rw-r--r-- | src/runtime/cgo/gcc_openbsd_amd64.c | 40 | ||||
-rw-r--r-- | src/runtime/crash_cgo_test.go | 68 | ||||
-rw-r--r-- | src/runtime/defs_windows.go | 1 | ||||
-rw-r--r-- | src/runtime/hashmap.go | 35 | ||||
-rw-r--r-- | src/runtime/hashmap_fast.go | 12 | ||||
-rw-r--r-- | src/runtime/mprof.go | 14 | ||||
-rw-r--r-- | src/runtime/os_plan9.go | 2 | ||||
-rw-r--r-- | src/runtime/sigqueue.go | 9 | ||||
-rw-r--r-- | src/runtime/syscall_windows.go | 2 | ||||
-rw-r--r-- | src/syscall/route_openbsd.go | 6 |
17 files changed, 285 insertions, 127 deletions
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c index d638ae4eb..b6c61b491 100644 --- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -235,24 +235,65 @@ chomp(Buf *b) b->len--; } +static char* +branchtag(char *branch, bool *precise) +{ + char *tag, *p, *q; + int i; + Buf b, arg; + Vec tags; + + binit(&b); + binit(&arg); + vinit(&tags); + + bprintf(&arg, "master..%s", branch); + run(&b, goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", bstr(&arg), nil); + + splitlines(&tags, bstr(&b)); + tag = branch; + for(i=0; i < tags.len; i++) { + // Each line is either blank, or looks like + // (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4) + // We need to find an element starting with refs/tags/. + p = xstrstr(tags.p[i], " refs/tags/"); + if(p == nil) + continue; + p += xstrlen(" refs/tags/"); + // The tag name ends at a comma or paren (prefer the first). + q = xstrstr(p, ","); + if(q == nil) + q = xstrstr(p, ")"); + if(q == nil) + continue; // malformed line; ignore it + *q = '\0'; + tag = xstrdup(p); + if(i == 0) + *precise = 1; // tag denotes HEAD + break; + } + + bfree(&b); + bfree(&arg); + vfree(&tags); + return tag; +} // findgoversion determines the Go version to use in the version string. static char* findgoversion(void) { - char *tag, *rev, *p; - int i, nrev; + char *tag, *p; + bool precise; Buf b, path, bmore, branch; - Vec tags; binit(&b); binit(&path); binit(&bmore); binit(&branch); - vinit(&tags); // The $GOROOT/VERSION file takes priority, for distributions - // without the Mercurial repo. + // without the source repo. bpathf(&path, "%s/VERSION", goroot); if(isfile(bstr(&path))) { readfile(&b, bstr(&path)); @@ -266,7 +307,7 @@ findgoversion(void) } // The $GOROOT/VERSION.cache file is a cache to avoid invoking - // hg every time we run this command. Unlike VERSION, it gets + // git every time we run this command. Unlike VERSION, it gets // deleted by the clean command. bpathf(&path, "%s/VERSION.cache", goroot); if(isfile(bstr(&path))) { @@ -275,49 +316,27 @@ findgoversion(void) goto done; } - // Otherwise, use Mercurial. + // Otherwise, use Git. // What is the current branch? - run(&branch, goroot, CheckExit, "hg", "identify", "-b", nil); + run(&branch, goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD", nil); chomp(&branch); // What are the tags along the current branch? tag = "devel"; - rev = "."; - run(&b, goroot, CheckExit, "hg", "log", "-b", bstr(&branch), "-r", ".:0", "--template", "{tags} + ", nil); - splitfields(&tags, bstr(&b)); - nrev = 0; - for(i=0; i<tags.len; i++) { - p = tags.p[i]; - if(streq(p, "+")) - nrev++; - // Only show the beta tag for the exact revision. - if(hasprefix(p, "go") && (!contains(p, "beta") || nrev == 0)) { - tag = xstrdup(p); - // If this tag matches the current checkout - // exactly (no "+" yet), don't show extra - // revision information. - if(nrev == 0) - rev = ""; - break; - } - } + precise = 0; - if(tag[0] == '\0') { - // Did not find a tag; use branch name. - bprintf(&b, "branch.%s", bstr(&branch)); - tag = btake(&b); - } - - if(rev[0]) { - // Tag is before the revision we're building. - // Add extra information. - run(&bmore, goroot, CheckExit, "hg", "log", "--template", " +{node|short} {date|date}", "-r", rev, nil); - chomp(&bmore); - } + // If we're on a release branch, use the closest matching tag + // that is on the release branch (and not on the master branch). + if(hasprefix(bstr(&branch), "release-branch.")) + tag = branchtag(bstr(&branch), &precise); bprintf(&b, "%s", tag); - if(bmore.len > 0) + if(!precise) { + // Tag does not point at HEAD; add hash and date to version. + run(&bmore, goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD", nil); + chomp(&bmore); bwriteb(&b, &bmore); + } // Cache version. writefile(&b, bstr(&path), 0); @@ -330,7 +349,6 @@ done: bfree(&path); bfree(&bmore); bfree(&branch); - vfree(&tags); return p; } diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index b2ff2fbc5..8788a678b 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -143,18 +143,6 @@ mapbucket(Type *t) // We don't need to encode it as GC doesn't care about it. offset = BUCKETSIZE * 1; - overflowfield = typ(TFIELD); - overflowfield->type = ptrto(bucket); - overflowfield->width = offset; // "width" is offset in structure - overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name - overflowfield->sym->name = "overflow"; - offset += widthptr; - - // The keys are padded to the native integer alignment. - // This is usually the same as widthptr; the exception (as usual) is nacl/amd64. - if(widthreg > widthptr) - offset += widthreg - widthptr; - keysfield = typ(TFIELD); keysfield->type = typ(TARRAY); keysfield->type->type = keytype; @@ -175,11 +163,23 @@ mapbucket(Type *t) valuesfield->sym->name = "values"; offset += BUCKETSIZE * valtype->width; + overflowfield = typ(TFIELD); + overflowfield->type = ptrto(bucket); + overflowfield->width = offset; // "width" is offset in structure + overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name + overflowfield->sym->name = "overflow"; + offset += widthptr; + + // Pad to the native integer alignment. + // This is usually the same as widthptr; the exception (as usual) is nacl/amd64. + if(widthreg > widthptr) + offset += widthreg - widthptr; + // link up fields - bucket->type = overflowfield; - overflowfield->down = keysfield; + bucket->type = keysfield; keysfield->down = valuesfield; - valuesfield->down = T; + valuesfield->down = overflowfield; + overflowfield->down = T; bucket->width = offset; bucket->local = t->local; diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index 86e169761..50e0ca93b 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -290,7 +290,7 @@ func downloadPackage(p *Package) error { } } if remote != repo { - return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo) + return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote) } } } diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index a3ba52325..dfe515c3c 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -1281,12 +1281,19 @@ synthesizemaptypes(DWDie *die) fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys"); newrefattr(fld, DW_AT_type, dwhk); - newmemberoffsetattr(fld, BucketSize + PtrSize); + newmemberoffsetattr(fld, BucketSize); fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values"); newrefattr(fld, DW_AT_type, dwhv); - newmemberoffsetattr(fld, BucketSize + PtrSize + BucketSize * keysize); - newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + PtrSize + BucketSize * keysize + BucketSize * valsize, 0); - substitutetype(dwhb, "overflow", defptrto(dwhb)); + newmemberoffsetattr(fld, BucketSize + BucketSize * keysize); + fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow"); + newrefattr(fld, DW_AT_type, defptrto(dwhb)); + newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize)); + if(RegSize > PtrSize) { + fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad"); + newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); + newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize) + PtrSize); + } + newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + BucketSize * keysize + BucketSize * valsize + RegSize, 0); // Construct hash<K,V> dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index b5d081949..dd5fa0d2a 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -539,7 +539,10 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) s->type = SRODATA; break; case ElfSectFlagAlloc + ElfSectFlagWrite: - s->type = SNOPTRDATA; + if(sect->type == ElfSectNobits) + s->type = SNOPTRBSS; + else + s->type = SNOPTRDATA; break; case ElfSectFlagAlloc + ElfSectFlagExec: s->type = STEXT; diff --git a/src/reflect/type.go b/src/reflect/type.go index c0ddfcad0..6fd6894cf 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1498,8 +1498,9 @@ func MapOf(key, elem Type) Type { // gcProg is a helper type for generatation of GC pointer info. type gcProg struct { - gc []byte - size uintptr // size of type in bytes + gc []byte + size uintptr // size of type in bytes + hasPtr bool } func (gc *gcProg) append(v byte) { @@ -1560,11 +1561,14 @@ func (gc *gcProg) appendWord(v byte) { gc.gc[nptr/2] &= ^(3 << ((nptr%2)*4 + 2)) gc.gc[nptr/2] |= v << ((nptr%2)*4 + 2) gc.size += ptrsize + if v == bitsPointer { + gc.hasPtr = true + } } -func (gc *gcProg) finalize() unsafe.Pointer { +func (gc *gcProg) finalize() (unsafe.Pointer, bool) { if gc.size == 0 { - return nil + return nil, false } ptrsize := unsafe.Sizeof(uintptr(0)) gc.align(ptrsize) @@ -1579,7 +1583,7 @@ func (gc *gcProg) finalize() unsafe.Pointer { gc.appendWord(extractGCWord(gc.gc, i)) } } - return unsafe.Pointer(&gc.gc[0]) + return unsafe.Pointer(&gc.gc[0]), gc.hasPtr } func extractGCWord(gc []byte, i uintptr) byte { @@ -1624,10 +1628,6 @@ func bucketOf(ktyp, etyp *rtype) *rtype { for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ { gc.append(bitsScalar) } - gc.append(bitsPointer) // overflow - if runtime.GOARCH == "amd64p32" { - gc.append(bitsScalar) - } // keys for i := 0; i < bucketSize; i++ { gc.appendProg(ktyp) @@ -1636,10 +1636,15 @@ func bucketOf(ktyp, etyp *rtype) *rtype { for i := 0; i < bucketSize; i++ { gc.appendProg(etyp) } + // overflow + gc.append(bitsPointer) + if runtime.GOARCH == "amd64p32" { + gc.append(bitsScalar) + } b := new(rtype) b.size = gc.size - b.gc[0] = gc.finalize() + b.gc[0], _ = gc.finalize() s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" b.string = &s return b @@ -1840,7 +1845,11 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin // build dummy rtype holding gc program x := new(rtype) x.size = gc.size - x.gc[0] = gc.finalize() + var hasPtr bool + x.gc[0], hasPtr = gc.finalize() + if !hasPtr { + x.kind |= kindNoPointers + } var s string if rcvr != nil { s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")" diff --git a/src/runtime/cgo/gcc_openbsd_386.c b/src/runtime/cgo/gcc_openbsd_386.c index 582e943f3..c4be9a009 100644 --- a/src/runtime/cgo/gcc_openbsd_386.c +++ b/src/runtime/cgo/gcc_openbsd_386.c @@ -65,12 +65,39 @@ thread_start_wrapper(void *arg) return args.func(args.arg); } +static void init_pthread_wrapper(void) { + void *handle; + + // Locate symbol for the system pthread_create function. + handle = dlopen("libpthread.so", RTLD_LAZY); + if(handle == NULL) { + fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror()); + abort(); + } + sys_pthread_create = dlsym(handle, "pthread_create"); + if(sys_pthread_create == NULL) { + fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror()); + abort(); + } + dlclose(handle); +} + +static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT; + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { struct thread_args *p; + // we must initialize our wrapper in pthread_create, because it is valid to call + // pthread_create in a static constructor, and in fact, our test for issue 9456 + // does just that. + if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) { + fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n"); + abort(); + } + p = malloc(sizeof(*p)); if(p == NULL) { errno = ENOMEM; @@ -87,7 +114,6 @@ x_cgo_init(G *g, void (*setg)(void*)) { pthread_attr_t attr; size_t size; - void *handle; setg_gcc = setg; pthread_attr_init(&attr); @@ -95,18 +121,10 @@ x_cgo_init(G *g, void (*setg)(void*)) g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); - // Locate symbol for the system pthread_create function. - handle = dlopen("libpthread.so", RTLD_LAZY); - if(handle == NULL) { - fprintf(stderr, "dlopen: failed to load libpthread: %s\n", dlerror()); - abort(); - } - sys_pthread_create = dlsym(handle, "pthread_create"); - if(sys_pthread_create == NULL) { - fprintf(stderr, "dlsym: failed to find pthread_create: %s\n", dlerror()); + if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) { + fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n"); abort(); } - dlclose(handle); tcb_fixup(1); } diff --git a/src/runtime/cgo/gcc_openbsd_amd64.c b/src/runtime/cgo/gcc_openbsd_amd64.c index 35b359bba..8522cd48c 100644 --- a/src/runtime/cgo/gcc_openbsd_amd64.c +++ b/src/runtime/cgo/gcc_openbsd_amd64.c @@ -65,12 +65,39 @@ thread_start_wrapper(void *arg) return args.func(args.arg); } +static void init_pthread_wrapper(void) { + void *handle; + + // Locate symbol for the system pthread_create function. + handle = dlopen("libpthread.so", RTLD_LAZY); + if(handle == NULL) { + fprintf(stderr, "runtime/cgo: dlopen failed to load libpthread: %s\n", dlerror()); + abort(); + } + sys_pthread_create = dlsym(handle, "pthread_create"); + if(sys_pthread_create == NULL) { + fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror()); + abort(); + } + dlclose(handle); +} + +static pthread_once_t init_pthread_wrapper_once = PTHREAD_ONCE_INIT; + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { struct thread_args *p; + // we must initialize our wrapper in pthread_create, because it is valid to call + // pthread_create in a static constructor, and in fact, our test for issue 9456 + // does just that. + if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) { + fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n"); + abort(); + } + p = malloc(sizeof(*p)); if(p == NULL) { errno = ENOMEM; @@ -87,7 +114,6 @@ x_cgo_init(G *g, void (*setg)(void*)) { pthread_attr_t attr; size_t size; - void *handle; setg_gcc = setg; pthread_attr_init(&attr); @@ -95,18 +121,10 @@ x_cgo_init(G *g, void (*setg)(void*)) g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); - // Locate symbol for the system pthread_create function. - handle = dlopen("libpthread.so", RTLD_LAZY); - if(handle == NULL) { - fprintf(stderr, "dlopen: failed to load libpthread: %s\n", dlerror()); - abort(); - } - sys_pthread_create = dlsym(handle, "pthread_create"); - if(sys_pthread_create == NULL) { - fprintf(stderr, "dlsym: failed to find pthread_create: %s\n", dlerror()); + if(pthread_once(&init_pthread_wrapper_once, init_pthread_wrapper) != 0) { + fprintf(stderr, "runtime/cgo: failed to initialize pthread_create wrapper\n"); abort(); } - dlclose(handle); tcb_fixup(1); } diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 972eedc62..29f90fa36 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/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/src/runtime/defs_windows.go b/src/runtime/defs_windows.go index 7ce679741..5dfb83a7c 100644 --- a/src/runtime/defs_windows.go +++ b/src/runtime/defs_windows.go @@ -41,6 +41,7 @@ const ( DUPLICATE_SAME_ACCESS = C.DUPLICATE_SAME_ACCESS THREAD_PRIORITY_HIGHEST = C.THREAD_PRIORITY_HIGHEST + SIGPROF = 0 // dummy value for badsignal SIGINT = C.SIGINT CTRL_C_EVENT = C.CTRL_C_EVENT CTRL_BREAK_EVENT = C.CTRL_BREAK_EVENT diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index b4e624423..791af8cf3 100644 --- a/src/runtime/hashmap.go +++ b/src/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/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go index 8e21e02d6..afa6ecc99 100644 --- a/src/runtime/hashmap_fast.go +++ b/src/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/src/runtime/mprof.go b/src/runtime/mprof.go index d409c6c30..f4da45f5c 100644 --- a/src/runtime/mprof.go +++ b/src/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/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 20e47bf42..10e5531ec 100644 --- a/src/runtime/os_plan9.go +++ b/src/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/src/runtime/sigqueue.go b/src/runtime/sigqueue.go index 2d9c24d2d..fed4560fe 100644 --- a/src/runtime/sigqueue.go +++ b/src/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/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index efbcab510..5b76ad573 100644 --- a/src/runtime/syscall_windows.go +++ b/src/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 diff --git a/src/syscall/route_openbsd.go b/src/syscall/route_openbsd.go index 19f902db7..e5086400c 100644 --- a/src/syscall/route_openbsd.go +++ b/src/syscall/route_openbsd.go @@ -12,16 +12,16 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { switch any.Type { case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE: p := (*RouteMessage)(unsafe.Pointer(any)) - return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]} + return &RouteMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]} case RTM_IFINFO: p := (*InterfaceMessage)(unsafe.Pointer(any)) - return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]} + return &InterfaceMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]} case RTM_IFANNOUNCE: p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any)) return &InterfaceAnnounceMessage{Header: p.Header} case RTM_NEWADDR, RTM_DELADDR: p := (*InterfaceAddrMessage)(unsafe.Pointer(any)) - return &InterfaceAddrMessage{Header: p.Header, Data: b[SizeofIfaMsghdr:any.Msglen]} + return &InterfaceAddrMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]} } return nil } |