diff options
author | Ian Lance Taylor <iant@golang.org> | 2017-01-14 00:05:42 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-01-14 00:05:42 +0000 |
commit | c2047754c300b68c05d65faa8dc2925fe67b71b4 (patch) | |
tree | e183ae81a1f48a02945cb6de463a70c5be1b06f6 /libgo/go/context | |
parent | 829afb8f05602bb31c9c597b24df7377fed4f059 (diff) | |
download | gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.zip gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.gz gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.bz2 |
libgo: update to Go 1.8 release candidate 1
Compiler changes:
* Change map assignment to use mapassign and assign value directly.
* Change string iteration to use decoderune, faster for ASCII strings.
* Change makeslice to take int, and use makeslice64 for larger values.
* Add new noverflow field to hmap struct used for maps.
Unresolved problems, to be fixed later:
* Commented out test in go/types/sizes_test.go that doesn't compile.
* Commented out reflect.TestStructOf test for padding after zero-sized field.
Reviewed-on: https://go-review.googlesource.com/35231
gotools/:
Updates for Go 1.8rc1.
* Makefile.am (go_cmd_go_files): Add bug.go.
(s-zdefaultcc): Write defaultPkgConfig.
* Makefile.in: Rebuild.
From-SVN: r244456
Diffstat (limited to 'libgo/go/context')
-rw-r--r-- | libgo/go/context/benchmark_test.go | 44 | ||||
-rw-r--r-- | libgo/go/context/context.go | 26 | ||||
-rw-r--r-- | libgo/go/context/context_test.go | 88 | ||||
-rw-r--r-- | libgo/go/context/example_test.go | 116 | ||||
-rw-r--r-- | libgo/go/context/net_test.go | 21 | ||||
-rw-r--r-- | libgo/go/context/withtimeout_test.go | 35 | ||||
-rw-r--r-- | libgo/go/context/x_test.go | 29 |
7 files changed, 288 insertions, 71 deletions
diff --git a/libgo/go/context/benchmark_test.go b/libgo/go/context/benchmark_test.go new file mode 100644 index 0000000..b792327 --- /dev/null +++ b/libgo/go/context/benchmark_test.go @@ -0,0 +1,44 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context_test + +import ( + . "context" + "fmt" + "testing" +) + +func BenchmarkContextCancelTree(b *testing.B) { + depths := []int{1, 10, 100, 1000} + for _, d := range depths { + b.Run(fmt.Sprintf("depth=%d", d), func(b *testing.B) { + b.Run("Root=Background", func(b *testing.B) { + for i := 0; i < b.N; i++ { + buildContextTree(Background(), d) + } + }) + b.Run("Root=OpenCanceler", func(b *testing.B) { + for i := 0; i < b.N; i++ { + ctx, cancel := WithCancel(Background()) + buildContextTree(ctx, d) + cancel() + } + }) + b.Run("Root=ClosedCanceler", func(b *testing.B) { + for i := 0; i < b.N; i++ { + ctx, cancel := WithCancel(Background()) + cancel() + buildContextTree(ctx, d) + } + }) + }) + } +} + +func buildContextTree(root Context, depth int) { + for d := 0; d < depth; d++ { + root, _ = WithCancel(root) + } +} diff --git a/libgo/go/context/context.go b/libgo/go/context/context.go index f8ce9cc..0aa7c24 100644 --- a/libgo/go/context/context.go +++ b/libgo/go/context/context.go @@ -159,9 +159,9 @@ var DeadlineExceeded error = deadlineExceededError{} type deadlineExceededError struct{} -func (deadlineExceededError) Error() string { return "context deadline exceeded" } - -func (deadlineExceededError) Timeout() bool { return true } +func (deadlineExceededError) Error() string { return "context deadline exceeded" } +func (deadlineExceededError) Timeout() bool { return true } +func (deadlineExceededError) Temporary() bool { return true } // An emptyCtx is never canceled, has no values, and has no deadline. It is not // struct{}, since vars of this type must have distinct addresses. @@ -252,9 +252,9 @@ func propagateCancel(parent Context, child canceler) { child.cancel(false, p.err) } else { if p.children == nil { - p.children = make(map[canceler]bool) + p.children = make(map[canceler]struct{}) } - p.children[child] = true + p.children[child] = struct{}{} } p.mu.Unlock() } else { @@ -314,8 +314,8 @@ type cancelCtx struct { done chan struct{} // closed by the first cancel call. mu sync.Mutex - children map[canceler]bool // set to nil by the first cancel call - err error // set to non-nil by the first cancel call + children map[canceler]struct{} // set to nil by the first cancel call + err error // set to non-nil by the first cancel call } func (c *cancelCtx) Done() <-chan struct{} { @@ -376,7 +376,7 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { deadline: deadline, } propagateCancel(parent, c) - d := deadline.Sub(time.Now()) + d := time.Until(deadline) if d <= 0 { c.cancel(true, DeadlineExceeded) // deadline has already passed return c, func() { c.cancel(true, Canceled) } @@ -406,7 +406,7 @@ func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { } func (c *timerCtx) String() string { - return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) + return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, time.Until(c.deadline)) } func (c *timerCtx) cancel(removeFromParent bool, err error) { @@ -443,7 +443,13 @@ func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. // -// The provided key must be comparable. +// The provided key must be comparable and should not be of type +// string or any other built-in type to avoid collisions between +// packages using context. Users of WithValue should define their own +// types for keys. To avoid allocating when assigning to an +// interface{}, context keys often have concrete type +// struct{}. Alternatively, exported context key variables' static +// type should be a pointer or interface. func WithValue(parent Context, key, val interface{}) Context { if key == nil { panic("nil key") diff --git a/libgo/go/context/context_test.go b/libgo/go/context/context_test.go index cdfec07..b5e599f 100644 --- a/libgo/go/context/context_test.go +++ b/libgo/go/context/context_test.go @@ -10,10 +10,26 @@ import ( "runtime" "strings" "sync" - "testing" "time" ) +type testingT interface { + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Fail() + FailNow() + Failed() bool + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Log(args ...interface{}) + Logf(format string, args ...interface{}) + Name() string + Skip(args ...interface{}) + SkipNow() + Skipf(format string, args ...interface{}) + Skipped() bool +} + // otherContext is a Context that's not one of the types defined in context.go. // This lets us test code paths that differ based on the underlying type of the // Context. @@ -21,7 +37,7 @@ type otherContext struct { Context } -func TestBackground(t *testing.T) { +func XTestBackground(t testingT) { c := Background() if c == nil { t.Fatalf("Background returned nil") @@ -36,7 +52,7 @@ func TestBackground(t *testing.T) { } } -func TestTODO(t *testing.T) { +func XTestTODO(t testingT) { c := TODO() if c == nil { t.Fatalf("TODO returned nil") @@ -51,7 +67,7 @@ func TestTODO(t *testing.T) { } } -func TestWithCancel(t *testing.T) { +func XTestWithCancel(t testingT) { c1, cancel := WithCancel(Background()) if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want { @@ -92,7 +108,12 @@ func TestWithCancel(t *testing.T) { } } -func TestParentFinishesChild(t *testing.T) { +func contains(m map[canceler]struct{}, key canceler) bool { + _, ret := m[key] + return ret +} + +func XTestParentFinishesChild(t testingT) { // Context tree: // parent -> cancelChild // parent -> valueChild -> timerChild @@ -120,7 +141,7 @@ func TestParentFinishesChild(t *testing.T) { cc := cancelChild.(*cancelCtx) tc := timerChild.(*timerCtx) pc.mu.Lock() - if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] { + if len(pc.children) != 2 || !contains(pc.children, cc) || !contains(pc.children, tc) { t.Errorf("bad linkage: pc.children = %v, want %v and %v", pc.children, cc, tc) } @@ -169,7 +190,7 @@ func TestParentFinishesChild(t *testing.T) { } } -func TestChildFinishesFirst(t *testing.T) { +func XTestChildFinishesFirst(t testingT) { cancelable, stop := WithCancel(Background()) defer stop() for _, parent := range []Context{Background(), cancelable} { @@ -191,7 +212,7 @@ func TestChildFinishesFirst(t *testing.T) { if pcok { pc.mu.Lock() - if len(pc.children) != 1 || !pc.children[cc] { + if len(pc.children) != 1 || !contains(pc.children, cc) { t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc) } pc.mu.Unlock() @@ -229,7 +250,7 @@ func TestChildFinishesFirst(t *testing.T) { } } -func testDeadline(c Context, name string, failAfter time.Duration, t *testing.T) { +func testDeadline(c Context, name string, failAfter time.Duration, t testingT) { select { case <-time.After(failAfter): t.Fatalf("%s: context should have timed out", name) @@ -240,7 +261,7 @@ func testDeadline(c Context, name string, failAfter time.Duration, t *testing.T) } } -func TestDeadline(t *testing.T) { +func XTestDeadline(t testingT) { c, _ := WithDeadline(Background(), time.Now().Add(50*time.Millisecond)) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) @@ -263,7 +284,7 @@ func TestDeadline(t *testing.T) { testDeadline(c, "WithDeadline+now", time.Second, t) } -func TestTimeout(t *testing.T) { +func XTestTimeout(t testingT) { c, _ := WithTimeout(Background(), 50*time.Millisecond) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) @@ -280,7 +301,7 @@ func TestTimeout(t *testing.T) { testDeadline(c, "WithTimeout+otherContext+WithTimeout", 2*time.Second, t) } -func TestCanceledTimeout(t *testing.T) { +func XTestCanceledTimeout(t testingT) { c, _ := WithTimeout(Background(), time.Second) o := otherContext{c} c, cancel := WithTimeout(o, 2*time.Second) @@ -303,7 +324,7 @@ var k1 = key1(1) var k2 = key2(1) // same int as k1, different type var k3 = key2(3) // same type as k2, different int -func TestValues(t *testing.T) { +func XTestValues(t testingT) { check := func(c Context, nm, v1, v2, v3 string) { if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 { t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0) @@ -351,7 +372,7 @@ func TestValues(t *testing.T) { check(o4, "o4", "", "c2k2", "") } -func TestAllocs(t *testing.T) { +func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(int, func()) float64) { bg := Background() for _, test := range []struct { desc string @@ -411,16 +432,16 @@ func TestAllocs(t *testing.T) { limit = test.gccgoLimit } numRuns := 100 - if testing.Short() { + if testingShort() { numRuns = 10 } - if n := testing.AllocsPerRun(numRuns, test.f); n > limit { + if n := testingAllocsPerRun(numRuns, test.f); n > limit { t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit)) } } } -func TestSimultaneousCancels(t *testing.T) { +func XTestSimultaneousCancels(t testingT) { root, cancel := WithCancel(Background()) m := map[Context]CancelFunc{root: cancel} q := []Context{root} @@ -468,7 +489,7 @@ func TestSimultaneousCancels(t *testing.T) { } } -func TestInterlockedCancels(t *testing.T) { +func XTestInterlockedCancels(t testingT) { parent, cancelParent := WithCancel(Background()) child, cancelChild := WithCancel(parent) go func() { @@ -485,15 +506,15 @@ func TestInterlockedCancels(t *testing.T) { } } -func TestLayersCancel(t *testing.T) { +func XTestLayersCancel(t testingT) { testLayers(t, time.Now().UnixNano(), false) } -func TestLayersTimeout(t *testing.T) { +func XTestLayersTimeout(t testingT) { testLayers(t, time.Now().UnixNano(), true) } -func testLayers(t *testing.T, seed int64, testTimeout bool) { +func testLayers(t testingT, seed int64, testTimeout bool) { rand.Seed(seed) errorf := func(format string, a ...interface{}) { t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...) @@ -562,7 +583,7 @@ func testLayers(t *testing.T, seed int64, testTimeout bool) { } } -func TestCancelRemoves(t *testing.T) { +func XTestCancelRemoves(t testingT) { checkChildren := func(when string, ctx Context, want int) { if got := len(ctx.(*cancelCtx).children); got != want { t.Errorf("%s: context has %d children, want %d", when, got, want) @@ -574,17 +595,32 @@ func TestCancelRemoves(t *testing.T) { _, cancel := WithCancel(ctx) checkChildren("with WithCancel child ", ctx, 1) cancel() - checkChildren("after cancelling WithCancel child", ctx, 0) + checkChildren("after canceling WithCancel child", ctx, 0) ctx, _ = WithCancel(Background()) checkChildren("after creation", ctx, 0) _, cancel = WithTimeout(ctx, 60*time.Minute) checkChildren("with WithTimeout child ", ctx, 1) cancel() - checkChildren("after cancelling WithTimeout child", ctx, 0) + checkChildren("after canceling WithTimeout child", ctx, 0) +} + +func XTestWithCancelCanceledParent(t testingT) { + parent, pcancel := WithCancel(Background()) + pcancel() + + c, _ := WithCancel(parent) + select { + case <-c.Done(): + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for Done") + } + if got, want := c.Err(), Canceled; got != want { + t.Errorf("child not cancelled; got = %v, want = %v", got, want) + } } -func TestWithValueChecksKey(t *testing.T) { +func XTestWithValueChecksKey(t testingT) { panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") }) if panicVal == nil { t.Error("expected panic") @@ -601,7 +637,7 @@ func recoveredValue(fn func()) (v interface{}) { return } -func TestDeadlineExceededSupportsTimeout(t *testing.T) { +func XTestDeadlineExceededSupportsTimeout(t testingT) { i, ok := DeadlineExceeded.(interface { Timeout() bool }) diff --git a/libgo/go/context/example_test.go b/libgo/go/context/example_test.go new file mode 100644 index 0000000..2d48d4e --- /dev/null +++ b/libgo/go/context/example_test.go @@ -0,0 +1,116 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context_test + +import ( + "context" + "fmt" + "time" +) + +// This example demonstrates the use of a cancelable context to prevent a +// goroutine leak. By the end of the example function, the goroutine started +// by gen will return without leaking. +func ExampleWithCancel() { + // gen generates integers in a separate goroutine and + // sends them to the returned channel. + // The callers of gen need to cancel the context once + // they are done consuming generated integers not to leak + // the internal goroutine started by gen. + gen := func(ctx context.Context) <-chan int { + dst := make(chan int) + n := 1 + go func() { + for { + select { + case <-ctx.Done(): + return // returning not to leak the goroutine + case dst <- n: + n++ + } + } + }() + return dst + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // cancel when we are finished consuming integers + + for n := range gen(ctx) { + fmt.Println(n) + if n == 5 { + break + } + } + // Output: + // 1 + // 2 + // 3 + // 4 + // 5 +} + +// This example passes a context with a arbitrary deadline to tell a blocking +// function that it should abandon its work as soon as it gets to it. +func ExampleWithDeadline() { + d := time.Now().Add(50 * time.Millisecond) + ctx, cancel := context.WithDeadline(context.Background(), d) + + // Even though ctx will be expired, it is good practice to call its + // cancelation function in any case. Failure to do so may keep the + // context and its parent alive longer than necessary. + defer cancel() + + select { + case <-time.After(1 * time.Second): + fmt.Println("overslept") + case <-ctx.Done(): + fmt.Println(ctx.Err()) + } + + // Output: + // context deadline exceeded +} + +// This example passes a context with a timeout to tell a blocking function that +// it should abandon its work after the timeout elapses. +func ExampleWithTimeout() { + // Pass a context with a timeout to tell a blocking function that it + // should abandon its work after the timeout elapses. + ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancel() + + select { + case <-time.After(1 * time.Second): + fmt.Println("overslept") + case <-ctx.Done(): + fmt.Println(ctx.Err()) // prints "context deadline exceeded" + } + + // Output: + // context deadline exceeded +} + +func ExampleWithValue() { + type favContextKey string + + f := func(ctx context.Context, k favContextKey) { + if v := ctx.Value(k); v != nil { + fmt.Println("found value:", v) + return + } + fmt.Println("key not found:", k) + } + + k := favContextKey("language") + ctx := context.WithValue(context.Background(), k, "Go") + + f(ctx, k) + f(ctx, favContextKey("color")) + + // Output: + // found value: Go + // key not found: color +} diff --git a/libgo/go/context/net_test.go b/libgo/go/context/net_test.go new file mode 100644 index 0000000..a007689 --- /dev/null +++ b/libgo/go/context/net_test.go @@ -0,0 +1,21 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context_test + +import ( + "context" + "net" + "testing" +) + +func TestDeadlineExceededIsNetError(t *testing.T) { + err, ok := context.DeadlineExceeded.(net.Error) + if !ok { + t.Fatal("DeadlineExceeded does not implement net.Error") + } + if !err.Timeout() || !err.Temporary() { + t.Fatalf("Timeout() = %v, Temporary() = %v, want true, true", err.Timeout(), err.Temporary()) + } +} diff --git a/libgo/go/context/withtimeout_test.go b/libgo/go/context/withtimeout_test.go deleted file mode 100644 index c74600b..0000000 --- a/libgo/go/context/withtimeout_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package context_test - -import ( - "context" - "fmt" - "time" -) - -func ExampleWithTimeout() { - // Pass a context with a timeout to tell a blocking function that it - // should abandon its work after the timeout elapses. - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) - - select { - case <-time.After(1 * time.Second): - fmt.Println("overslept") - case <-ctx.Done(): - fmt.Println(ctx.Err()) // prints "context deadline exceeded" - } - - // Even though ctx should have expired already, it is good - // practice to call its cancelation function in any case. - // Failure to do so may keep the context and its parent alive - // longer than necessary. - cancel() - - // Output: - // context deadline exceeded -} diff --git a/libgo/go/context/x_test.go b/libgo/go/context/x_test.go new file mode 100644 index 0000000..d14b6f1 --- /dev/null +++ b/libgo/go/context/x_test.go @@ -0,0 +1,29 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context_test + +import ( + . "context" + "testing" +) + +func TestBackground(t *testing.T) { XTestBackground(t) } +func TestTODO(t *testing.T) { XTestTODO(t) } +func TestWithCancel(t *testing.T) { XTestWithCancel(t) } +func TestParentFinishesChild(t *testing.T) { XTestParentFinishesChild(t) } +func TestChildFinishesFirst(t *testing.T) { XTestChildFinishesFirst(t) } +func TestDeadline(t *testing.T) { XTestDeadline(t) } +func TestTimeout(t *testing.T) { XTestTimeout(t) } +func TestCanceledTimeout(t *testing.T) { XTestCanceledTimeout(t) } +func TestValues(t *testing.T) { XTestValues(t) } +func TestAllocs(t *testing.T) { XTestAllocs(t, testing.Short, testing.AllocsPerRun) } +func TestSimultaneousCancels(t *testing.T) { XTestSimultaneousCancels(t) } +func TestInterlockedCancels(t *testing.T) { XTestInterlockedCancels(t) } +func TestLayersCancel(t *testing.T) { XTestLayersCancel(t) } +func TestLayersTimeout(t *testing.T) { XTestLayersTimeout(t) } +func TestCancelRemoves(t *testing.T) { XTestCancelRemoves(t) } +func TestWithCancelCanceledParent(t *testing.T) { XTestWithCancelCanceledParent(t) } +func TestWithValueChecksKey(t *testing.T) { XTestWithValueChecksKey(t) } +func TestDeadlineExceededSupportsTimeout(t *testing.T) { XTestDeadlineExceededSupportsTimeout(t) } |