mirror of
https://github.com/golang/go
synced 2024-11-26 13:28:27 -07:00
context: add WithoutCancel
WithoutCancel returns a copy of parent that is not canceled when parent is canceled. The returned context returns no Deadline or Err, and its Done channel is nil. Calling Cause on the returned context returns nil. API changes: +pkg context, func WithoutCancel(Context) Context Fixes #40221 Change-Id: Ide29631c08881176a2c2a58409fed9ca6072e65d Reviewed-on: https://go-review.googlesource.com/c/go/+/479918 Run-TryBot: Sameer Ajmani <sameer@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
c292397160
commit
1844b54166
1
api/next/40221.txt
Normal file
1
api/next/40221.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
pkg context, func WithoutCancel(Context) Context #40221
|
@ -474,6 +474,40 @@ func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithoutCancel returns a copy of parent that is not canceled when parent is canceled.
|
||||||
|
// The returned context returns no Deadline or Err, and its Done channel is nil.
|
||||||
|
// Calling Cause on the returned context returns nil.
|
||||||
|
func WithoutCancel(parent Context) Context {
|
||||||
|
if parent == nil {
|
||||||
|
panic("cannot create context from nil parent")
|
||||||
|
}
|
||||||
|
return withoutCancelCtx{parent}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withoutCancelCtx struct {
|
||||||
|
c Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (withoutCancelCtx) Done() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (withoutCancelCtx) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c withoutCancelCtx) Value(key any) any {
|
||||||
|
return value(c, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c withoutCancelCtx) String() string {
|
||||||
|
return contextName(c.c) + ".WithoutCancel"
|
||||||
|
}
|
||||||
|
|
||||||
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
@ -645,6 +679,13 @@ func value(c Context, key any) any {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
c = ctx.Context
|
c = ctx.Context
|
||||||
|
case withoutCancelCtx:
|
||||||
|
if key == &cancelCtxKey {
|
||||||
|
// This implements Cause(ctx) == nil
|
||||||
|
// when ctx is created using WithoutCancel.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c = ctx.c
|
||||||
case *timerCtx:
|
case *timerCtx:
|
||||||
if key == &cancelCtxKey {
|
if key == &cancelCtxKey {
|
||||||
return &ctx.cancelCtx
|
return &ctx.cancelCtx
|
||||||
|
@ -981,6 +981,36 @@ func XTestCause(t testingT) {
|
|||||||
err: Canceled,
|
err: Canceled,
|
||||||
cause: finishedEarly,
|
cause: finishedEarly,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "WithoutCancel",
|
||||||
|
ctx: func() Context {
|
||||||
|
return WithoutCancel(Background())
|
||||||
|
}(),
|
||||||
|
err: nil,
|
||||||
|
cause: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "WithoutCancel canceled",
|
||||||
|
ctx: func() Context {
|
||||||
|
ctx, cancel := WithCancelCause(Background())
|
||||||
|
ctx = WithoutCancel(ctx)
|
||||||
|
cancel(finishedEarly)
|
||||||
|
return ctx
|
||||||
|
}(),
|
||||||
|
err: nil,
|
||||||
|
cause: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "WithoutCancel timeout",
|
||||||
|
ctx: func() Context {
|
||||||
|
ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
|
||||||
|
ctx = WithoutCancel(ctx)
|
||||||
|
cancel()
|
||||||
|
return ctx
|
||||||
|
}(),
|
||||||
|
err: nil,
|
||||||
|
cause: nil,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
if got, want := test.ctx.Err(), test.err; want != got {
|
if got, want := test.ctx.Err(), test.err; want != got {
|
||||||
t.Errorf("%s: ctx.Err() = %v want %v", test.name, got, want)
|
t.Errorf("%s: ctx.Err() = %v want %v", test.name, got, want)
|
||||||
@ -1009,3 +1039,21 @@ func XTestCauseRace(t testingT) {
|
|||||||
runtime.Gosched()
|
runtime.Gosched()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func XTestWithoutCancel(t testingT) {
|
||||||
|
key, value := "key", "value"
|
||||||
|
ctx := WithValue(Background(), key, value)
|
||||||
|
ctx = WithoutCancel(ctx)
|
||||||
|
if d, ok := ctx.Deadline(); !d.IsZero() || ok != false {
|
||||||
|
t.Errorf("ctx.Deadline() = %v, %v want zero, false", d, ok)
|
||||||
|
}
|
||||||
|
if done := ctx.Done(); done != nil {
|
||||||
|
t.Errorf("ctx.Deadline() = %v want nil", done)
|
||||||
|
}
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
t.Errorf("ctx.Err() = %v want nil", err)
|
||||||
|
}
|
||||||
|
if v := ctx.Value(key); v != value {
|
||||||
|
t.Errorf("ctx.Value(%q) = %q want %q", key, v, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -31,3 +31,4 @@ func TestDeadlineExceededSupportsTimeout(t *testing.T) { XTestDeadlineExceededSu
|
|||||||
func TestCustomContextGoroutines(t *testing.T) { XTestCustomContextGoroutines(t) }
|
func TestCustomContextGoroutines(t *testing.T) { XTestCustomContextGoroutines(t) }
|
||||||
func TestCause(t *testing.T) { XTestCause(t) }
|
func TestCause(t *testing.T) { XTestCause(t) }
|
||||||
func TestCauseRace(t *testing.T) { XTestCauseRace(t) }
|
func TestCauseRace(t *testing.T) { XTestCauseRace(t) }
|
||||||
|
func TestWithoutCancel(t *testing.T) { XTestWithoutCancel(t) }
|
||||||
|
Loading…
Reference in New Issue
Block a user