in ctxtool/merge.go [66:103]
func MergeCancellation(parent, other canceller) (context.Context, context.CancelFunc) {
ctx := FromCanceller(parent)
err := ctx.Err()
if err == nil {
err = other.Err()
}
if err != nil {
// at least one context is already cancelled
return &cancelledContext{Context: ctx, err: err}, func() {}
}
if ctx.Done() == nil {
if other.Done() == nil {
// context is never cancelled.
return ctx, func() {}
}
return &cancelOverwriteContext{ctx: ctx, cancel: other}, func() {}
}
chDone := make(chan struct{})
merged := &mergeCancelCtx{
Context: ctx,
cancel: other,
ch: chDone,
}
go merged.waitCancel(chDone)
canceller := func() {
merged.mu.Lock()
defer merged.mu.Unlock()
if merged.err == nil {
merged.err = context.Canceled
close(chDone)
}
}
return merged, canceller
}