aboutsummaryrefslogtreecommitdiff
path: root/src/context
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2022-11-28 10:33:04 -0800
committerGopher Robot <gobot@golang.org>2022-11-28 19:33:02 +0000
commit61f5a672edd6cce959a47e20dcfb59eaaa5ebd56 (patch)
tree35430adaf709b79ddef9d521e171d8c23a62a214 /src/context
parentfd22b0bf89e83aabce915ae86a677c10513de20f (diff)
downloadgo-61f5a672edd6cce959a47e20dcfb59eaaa5ebd56.tar.xz
context: add lock in Cause to avoid race
Change-Id: I8d970e8db859bdd17390cfbc22cc2ba0d326ed0c Reviewed-on: https://go-review.googlesource.com/c/go/+/453735 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Sameer Ajmani <sameer@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
Diffstat (limited to 'src/context')
-rw-r--r--src/context/context.go2
-rw-r--r--src/context/context_test.go20
-rw-r--r--src/context/x_test.go1
3 files changed, 23 insertions, 0 deletions
diff --git a/src/context/context.go b/src/context/context.go
index f39abe91e2..f3fe1a474e 100644
--- a/src/context/context.go
+++ b/src/context/context.go
@@ -285,6 +285,8 @@ func withCancel(parent Context) *cancelCtx {
// Cause returns nil if c has not been canceled yet.
func Cause(c Context) error {
if cc, ok := c.Value(&cancelCtxKey).(*cancelCtx); ok {
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
return cc.cause
}
return nil
diff --git a/src/context/context_test.go b/src/context/context_test.go
index 593a7b1521..eb5a86b3c6 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -5,6 +5,7 @@
package context
import (
+ "errors"
"fmt"
"math/rand"
"runtime"
@@ -934,3 +935,22 @@ func XTestCause(t testingT) {
}
}
}
+
+func XTestCauseRace(t testingT) {
+ cause := errors.New("TestCauseRace")
+ ctx, cancel := WithCancelCause(Background())
+ go func() {
+ cancel(cause)
+ }()
+ for {
+ // Poll Cause, rather than waiting for Done, to test that
+ // access to the underlying cause is synchronized properly.
+ if err := Cause(ctx); err != nil {
+ if err != cause {
+ t.Errorf("Cause returned %v, want %v", err, cause)
+ }
+ break
+ }
+ runtime.Gosched()
+ }
+}
diff --git a/src/context/x_test.go b/src/context/x_test.go
index d3adb381d6..a2d814f8ea 100644
--- a/src/context/x_test.go
+++ b/src/context/x_test.go
@@ -30,3 +30,4 @@ func TestInvalidDerivedFail(t *testing.T) { XTestInvalidDerivedFail
func TestDeadlineExceededSupportsTimeout(t *testing.T) { XTestDeadlineExceededSupportsTimeout(t) }
func TestCustomContextGoroutines(t *testing.T) { XTestCustomContextGoroutines(t) }
func TestCause(t *testing.T) { XTestCause(t) }
+func TestCauseRace(t *testing.T) { XTestCauseRace(t) }