// +build !go1.7 package tomb import ( "golang.org/x/net/context" ) // WithContext returns a new tomb that is killed when the provided parent // context is canceled, and a copy of parent with a replaced Done channel // that is closed when either the tomb is dying or the parent is canceled. // The returned context may also be obtained via the tomb's Context method. func WithContext(parent context.Context) (*Tomb, context.Context) { var t Tomb t.init() if parent.Done() != nil { go func() { select { case <-t.Dying(): case <-parent.Done(): t.Kill(parent.Err()) } }() } t.parent = parent child, cancel := context.WithCancel(parent) t.addChild(parent, child, cancel) return &t, child } // Context returns a context that is a copy of the provided parent context with // a replaced Done channel that is closed when either the tomb is dying or the // parent is cancelled. // // If parent is nil, it defaults to the parent provided via WithContext, or an // empty background parent if the tomb wasn't created via WithContext. func (t *Tomb) Context(parent context.Context) context.Context { t.init() t.m.Lock() defer t.m.Unlock() if parent == nil { if t.parent == nil { t.parent = context.Background() } parent = t.parent.(context.Context) } if child, ok := t.child[parent]; ok { return child.context.(context.Context) } child, cancel := context.WithCancel(parent) t.addChild(parent, child, cancel) return child } func (t *Tomb) addChild(parent context.Context, child context.Context, cancel func()) { if t.reason != ErrStillAlive { cancel() return } if t.child == nil { t.child = make(map[interface{}]childContext) } t.child[parent] = childContext{child, cancel, child.Done()} for parent, child := range t.child { select { case <-child.done: delete(t.child, parent) default: } } }