diff options
| author | Austin Clements <austin@google.com> | 2014-10-27 17:17:06 -0400 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2014-10-27 17:17:06 -0400 |
| commit | 5a653089ef756ecda170e4ee030480d547496362 (patch) | |
| tree | fe2c3550eb05fe487b5870dfef3d06972582c1a9 /src | |
| parent | 32c75a2d3d121f31ace325d48d9fcbdde58cc042 (diff) | |
| parent | 3e62d2184ab2d2ac6053e3f4af5e3f99902c1e32 (diff) | |
| download | go-5a653089ef756ecda170e4ee030480d547496362.tar.xz | |
[dev.power64] all: merge default into dev.power64
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/164110043
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/gc/walk.c | 8 | ||||
| -rw-r--r-- | src/cmd/go/build.go | 1 | ||||
| -rw-r--r-- | src/cmd/go/get.go | 11 | ||||
| -rw-r--r-- | src/cmd/go/vcs.go | 50 | ||||
| -rw-r--r-- | src/encoding/csv/writer.go | 16 | ||||
| -rw-r--r-- | src/encoding/csv/writer_test.go | 11 | ||||
| -rw-r--r-- | src/net/http/pprof/pprof.go | 4 | ||||
| -rw-r--r-- | src/net/lookup.go | 51 | ||||
| -rw-r--r-- | src/net/singleflight.go | 66 | ||||
| -rw-r--r-- | src/runtime/symtab.go | 11 | ||||
| -rw-r--r-- | src/unsafe/unsafe.go | 3 |
11 files changed, 186 insertions, 46 deletions
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 2520343bfd..eaa0440552 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -614,7 +614,7 @@ walkexpr(Node **np, NodeList **init) if(oaslit(n, init)) goto ret; - if(n->right == N) + if(n->right == N || iszero(n->right) && !flag_race) goto ret; switch(n->right->op) { @@ -1390,12 +1390,6 @@ walkexpr(Node **np, NodeList **init) case OMAPLIT: case OSTRUCTLIT: case OPTRLIT: - // NOTE(rsc): Race detector cannot handle seeing - // a STRUCTLIT or ARRAYLIT representing a zero value, - // so make a temporary for those always in race mode. - // Otherwise, leave zero values in place. - if(iszero(n) && !flag_race) - goto ret; var = temp(n->type); anylit(0, n, var, init); n = var; diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 49b84709e2..79a27116a1 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1945,6 +1945,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] } ldflags = append(ldflags, afiles...) ldflags = append(ldflags, cgoldflags...) + ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) ldflags = append(ldflags, p.CgoLDFLAGS...) if usesCgo && goos == "linux" { ldflags = append(ldflags, "-Wl,-E") diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index 2640339414..b8eac5c1ef 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -272,8 +272,15 @@ func downloadPackage(p *Package) error { dir := filepath.Join(p.build.SrcRoot, rootPath) if remote, err := vcs.remoteRepo(vcs, dir); err == nil { if rr, err := repoRootForImportPath(p.ImportPath); err == nil { - if remote != rr.repo { - return fmt.Errorf("%s is from %s, should be from %s", dir, remote, rr.repo) + repo := rr.repo + if rr.vcs.resolveRepo != nil { + resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) + if err == nil { + repo = resolved + } + } + if remote != repo { + return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo) } } } diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 0834a7d192..1cac613388 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -34,7 +34,8 @@ type vcsCmd struct { scheme []string pingCmd string - remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error) + remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error) + resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) } // A tagCmd describes a command to list available tags @@ -164,8 +165,51 @@ var vcsBzr = &vcsCmd{ tagSyncCmd: "update -r {tag}", tagSyncDefault: "update -r revno:-1", - scheme: []string{"https", "http", "bzr", "bzr+ssh"}, - pingCmd: "info {scheme}://{repo}", + scheme: []string{"https", "http", "bzr", "bzr+ssh"}, + pingCmd: "info {scheme}://{repo}", + remoteRepo: bzrRemoteRepo, + resolveRepo: bzrResolveRepo, +} + +func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "config parent_location") + if err != nil { + return "", err + } + return strings.TrimSpace(string(outb)), nil +} + +func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo) + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // ... + // (branch root|repository branch): <URL> + // ... + + found := false + for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} { + i := strings.Index(out, prefix) + if i >= 0 { + out = out[i+len(prefix):] + found = true + break + } + } + if !found { + return "", fmt.Errorf("unable to parse output of bzr info") + } + + i := strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of bzr info") + } + out = out[:i] + return strings.TrimSpace(string(out)), nil } // vcsSvn describes how to use Subversion. diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go index 1faecb6648..17e7bb7f5c 100644 --- a/src/encoding/csv/writer.go +++ b/src/encoding/csv/writer.go @@ -115,10 +115,22 @@ func (w *Writer) WriteAll(records [][]string) (err error) { } // fieldNeedsQuotes returns true if our field must be enclosed in quotes. -// Empty fields, files with a Comma, fields with a quote or newline, and +// Fields with a Comma, fields with a quote or newline, and // fields which start with a space must be enclosed in quotes. +// We used to quote empty strings, but we do not anymore (as of Go 1.4). +// The two representations should be equivalent, but Postgres distinguishes +// quoted vs non-quoted empty string during database imports, and it has +// an option to force the quoted behavior for non-quoted CSV but it has +// no option to force the non-quoted behavior for quoted CSV, making +// CSV with quoted empty strings strictly less useful. +// Not quoting the empty string also makes this package match the behavior +// of Microsoft Excel and Google Drive. +// For Postgres, quote the data termating string `\.`. func (w *Writer) fieldNeedsQuotes(field string) bool { - if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 { + if field == "" { + return false + } + if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 { return true } diff --git a/src/encoding/csv/writer_test.go b/src/encoding/csv/writer_test.go index 22b740c074..8ddca0abe0 100644 --- a/src/encoding/csv/writer_test.go +++ b/src/encoding/csv/writer_test.go @@ -28,6 +28,17 @@ var writeTests = []struct { {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true}, {Input: [][]string{{"abc\rdef"}}, Output: "\"abcdef\"\r\n", UseCRLF: true}, {Input: [][]string{{"abc\rdef"}}, Output: "\"abc\rdef\"\n", UseCRLF: false}, + {Input: [][]string{{""}}, Output: "\n"}, + {Input: [][]string{{"", ""}}, Output: ",\n"}, + {Input: [][]string{{"", "", ""}}, Output: ",,\n"}, + {Input: [][]string{{"", "", "a"}}, Output: ",,a\n"}, + {Input: [][]string{{"", "a", ""}}, Output: ",a,\n"}, + {Input: [][]string{{"", "a", "a"}}, Output: ",a,a\n"}, + {Input: [][]string{{"a", "", ""}}, Output: "a,,\n"}, + {Input: [][]string{{"a", "", "a"}}, Output: "a,,a\n"}, + {Input: [][]string{{"a", "a", ""}}, Output: "a,a,\n"}, + {Input: [][]string{{"a", "a", "a"}}, Output: "a,a,a\n"}, + {Input: [][]string{{`\.`}}, Output: "\"\\.\"\n"}, } func TestWrite(t *testing.T) { diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go index 0c7548e3ef..a23f1bc4bc 100644 --- a/src/net/http/pprof/pprof.go +++ b/src/net/http/pprof/pprof.go @@ -162,6 +162,10 @@ func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Unknown profile: %s\n", name) return } + gc, _ := strconv.Atoi(r.FormValue("gc")) + if name == "heap" && gc > 0 { + runtime.GC() + } p.WriteTo(w, debug) return } diff --git a/src/net/lookup.go b/src/net/lookup.go index 20f20578cd..aeffe6c9b7 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -40,10 +40,16 @@ func lookupIPMerge(host string) (addrs []IP, err error) { addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) { return lookupIP(host) }) + return lookupIPReturn(addrsi, err, shared) +} + +// lookupIPReturn turns the return values from singleflight.Do into +// the return values from LookupIP. +func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) { if err != nil { return nil, err } - addrs = addrsi.([]IP) + addrs := addrsi.([]IP) if shared { clone := make([]IP, len(addrs)) copy(clone, addrs) @@ -52,41 +58,40 @@ func lookupIPMerge(host string) (addrs []IP, err error) { return addrs, nil } +// lookupIPDeadline looks up a hostname with a deadline. func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) { if deadline.IsZero() { return lookupIPMerge(host) } - // TODO(bradfitz): consider pushing the deadline down into the - // name resolution functions. But that involves fixing it for - // the native Go resolver, cgo, Windows, etc. - // - // In the meantime, just use a goroutine. Most users affected - // by http://golang.org/issue/2631 are due to TCP connections - // to unresponsive hosts, not DNS. + // We could push the deadline down into the name resolution + // functions. However, the most commonly used implementation + // calls getaddrinfo, which has no timeout. + timeout := deadline.Sub(time.Now()) if timeout <= 0 { - err = errTimeout - return + return nil, errTimeout } t := time.NewTimer(timeout) defer t.Stop() - type res struct { - addrs []IP - err error - } - resc := make(chan res, 1) - go func() { - a, err := lookupIPMerge(host) - resc <- res{a, err} - }() + + ch := lookupGroup.DoChan(host, func() (interface{}, error) { + return lookupIP(host) + }) + select { case <-t.C: - err = errTimeout - case r := <-resc: - addrs, err = r.addrs, r.err + // The DNS lookup timed out for some reason. Force + // future requests to start the DNS lookup again + // rather than waiting for the current lookup to + // complete. See issue 8602. + lookupGroup.Forget(host) + + return nil, errTimeout + + case r := <-ch: + return lookupIPReturn(r.v, r.err, r.shared) } - return } // LookupPort looks up the port for the given network and service. diff --git a/src/net/singleflight.go b/src/net/singleflight.go index dc58affdaa..bf599f0cc9 100644 --- a/src/net/singleflight.go +++ b/src/net/singleflight.go @@ -8,10 +8,18 @@ import "sync" // call is an in-flight or completed singleflight.Do call type call struct { - wg sync.WaitGroup - val interface{} - err error - dups int + wg sync.WaitGroup + + // These fields are written once before the WaitGroup is done + // and are only read after the WaitGroup is done. + val interface{} + err error + + // These fields are read and written with the singleflight + // mutex held before the WaitGroup is done, and are read but + // not written after the WaitGroup is done. + dups int + chans []chan<- singleflightResult } // singleflight represents a class of work and forms a namespace in @@ -21,6 +29,14 @@ type singleflight struct { m map[string]*call // lazily initialized } +// singleflightResult holds the results of Do, so they can be passed +// on a channel. +type singleflightResult struct { + v interface{} + err error + shared bool +} + // Do executes and returns the results of the given function, making // sure that only one execution is in-flight for a given key at a // time. If a duplicate comes in, the duplicate caller waits for the @@ -42,12 +58,52 @@ func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interfa g.m[key] = c g.mu.Unlock() + g.doCall(c, key, fn) + return c.val, c.err, c.dups > 0 +} + +// DoChan is like Do but returns a channel that will receive the +// results when they are ready. +func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult { + ch := make(chan singleflightResult, 1) + g.mu.Lock() + if g.m == nil { + g.m = make(map[string]*call) + } + if c, ok := g.m[key]; ok { + c.dups++ + c.chans = append(c.chans, ch) + g.mu.Unlock() + return ch + } + c := &call{chans: []chan<- singleflightResult{ch}} + c.wg.Add(1) + g.m[key] = c + g.mu.Unlock() + + go g.doCall(c, key, fn) + + return ch +} + +// doCall handles the single call for a key. +func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) { c.val, c.err = fn() c.wg.Done() g.mu.Lock() delete(g.m, key) + for _, ch := range c.chans { + ch <- singleflightResult{c.val, c.err, c.dups > 0} + } g.mu.Unlock() +} - return c.val, c.err, c.dups > 0 +// Forget tells the singleflight to forget about a key. Future calls +// to Do for this key will call the function rather than waiting for +// an earlier call to complete. +func (g *singleflight) Forget(key string) { + g.mu.Lock() + delete(g.m, key) + g.mu.Unlock() } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 48d4023b9a..45d107b777 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -84,10 +84,13 @@ func symtabinit() { } } - // file table follows ftab. + // The ftab ends with a half functab consisting only of + // 'entry', followed by a uint32 giving the pcln-relative + // offset of the file table. sp = (*sliceStruct)(unsafe.Pointer(&filetab)) - p = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff)) - sp.array = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff)) + end := unsafe.Pointer(&ftab[nftab].funcoff) // just beyond ftab + fileoffset := *(*uint32)(end) + sp.array = unsafe.Pointer(&pclntable[fileoffset]) // length is in first element of array. // set len to 1 so we can get first element. sp.len = 1 @@ -224,7 +227,7 @@ func funcline(f *_func, targetpc uintptr, file *string) int32 { func funcspdelta(f *_func, targetpc uintptr) int32 { x := pcvalue(f, f.pcsp, targetpc, true) if x&(ptrSize-1) != 0 { - print("invalid spdelta ", f.pcsp, " ", x, "\n") + print("invalid spdelta ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") } return x } diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go index 83b2e14052..79499b2955 100644 --- a/src/unsafe/unsafe.go +++ b/src/unsafe/unsafe.go @@ -4,6 +4,9 @@ /* Package unsafe contains operations that step around the type safety of Go programs. + + Packages that import unsafe may be non-portable and are not protected by the + Go 1 compatibility guidelines. */ package unsafe |
