summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTianon Gravi <admwiggin@gmail.com>2015-01-15 22:14:32 -0700
committerTianon Gravi <admwiggin@gmail.com>2015-01-15 22:14:32 -0700
commitf76df0afd043e05c4b013ab2982e32020839d259 (patch)
tree447b7688d9af57fad497e61a1cf6789f237c98e9 /src
parentf971d23c25b6660e666da64eedec69e77b9abbd7 (diff)
parent90ad8a7e5881be7834909c649f994b6b5244c965 (diff)
downloadgolang-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.c100
-rw-r--r--src/cmd/gc/reflect.c30
-rw-r--r--src/cmd/go/get.go2
-rw-r--r--src/cmd/ld/dwarf.c15
-rw-r--r--src/cmd/ld/ldelf.c5
-rw-r--r--src/reflect/type.go31
-rw-r--r--src/runtime/cgo/gcc_openbsd_386.c40
-rw-r--r--src/runtime/cgo/gcc_openbsd_amd64.c40
-rw-r--r--src/runtime/crash_cgo_test.go68
-rw-r--r--src/runtime/defs_windows.go1
-rw-r--r--src/runtime/hashmap.go35
-rw-r--r--src/runtime/hashmap_fast.go12
-rw-r--r--src/runtime/mprof.go14
-rw-r--r--src/runtime/os_plan9.go2
-rw-r--r--src/runtime/sigqueue.go9
-rw-r--r--src/runtime/syscall_windows.go2
-rw-r--r--src/syscall/route_openbsd.go6
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
}