blob: d47d83a5a4885987bd5d676f7a75ac62903b586e [file] [log] [blame]
// +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:
}
}
}