forked from TrueCloudLab/restic
Vendor gopkg.in/tomb.v2
This commit is contained in:
parent
1af96fc6dd
commit
c703d21d55
9 changed files with 961 additions and 1 deletions
8
Gopkg.lock
generated
8
Gopkg.lock
generated
|
@ -235,6 +235,12 @@
|
||||||
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
|
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
|
name = "gopkg.in/tomb.v2"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "d5d1b5820637886def9eef33e03a27a9f166942c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
@ -244,6 +250,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "a270b39954b9dad18c46f097be5816ca58ae1f387940b673b387d30934ce4ed4"
|
inputs-digest = "44a8f2ed127a6eaa38c1449b97d298fc703c961617bd93565b89bcc6c9a41483"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
29
vendor/gopkg.in/tomb.v2/LICENSE
generated
vendored
Normal file
29
vendor/gopkg.in/tomb.v2/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
tomb - support for clean goroutine termination in Go.
|
||||||
|
|
||||||
|
Copyright (c) 2010-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
4
vendor/gopkg.in/tomb.v2/README.md
generated
vendored
Normal file
4
vendor/gopkg.in/tomb.v2/README.md
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Installation and usage
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
See [gopkg.in/tomb.v2](https://gopkg.in/tomb.v2) for documentation and usage details.
|
74
vendor/gopkg.in/tomb.v2/context.go
generated
vendored
Normal file
74
vendor/gopkg.in/tomb.v2/context.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package tomb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
vendor/gopkg.in/tomb.v2/context16.go
generated
vendored
Normal file
74
vendor/gopkg.in/tomb.v2/context16.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// +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:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
177
vendor/gopkg.in/tomb.v2/context16_test.go
generated
vendored
Normal file
177
vendor/gopkg.in/tomb.v2/context16_test.go
generated
vendored
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package tomb_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"gopkg.in/tomb.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithContext(t *testing.T) {
|
||||||
|
parent1, cancel1 := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
tb, child1 := tomb.WithContext(parent1)
|
||||||
|
|
||||||
|
if !tb.Alive() {
|
||||||
|
t.Fatalf("WithContext returned dead tomb")
|
||||||
|
}
|
||||||
|
if tb.Context(parent1) != child1 {
|
||||||
|
t.Fatalf("Context returned different context for same parent")
|
||||||
|
}
|
||||||
|
if tb.Context(nil) != child1 {
|
||||||
|
t.Fatalf("Context returned different context for nil parent")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child1.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
parent2, cancel2 := context.WithCancel(context.WithValue(context.Background(), "parent", "parent2"))
|
||||||
|
child2 := tb.Context(parent2)
|
||||||
|
|
||||||
|
if tb.Context(parent2) != child2 {
|
||||||
|
t.Fatalf("Context returned different context for same parent")
|
||||||
|
}
|
||||||
|
if child2.Value("parent") != "parent2" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel2()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatalf("Tomb's child context didn't die after parent was canceled")
|
||||||
|
}
|
||||||
|
if !tb.Alive() {
|
||||||
|
t.Fatalf("Canceling unrelated parent context killed tomb")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent3 := context.WithValue(context.Background(), "parent", "parent3")
|
||||||
|
child3 := tb.Context(parent3)
|
||||||
|
|
||||||
|
if child3.Value("parent") != "parent3" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel1()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-tb.Dying():
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatalf("Canceling parent context did not kill tomb")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tb.Err() != context.Canceled {
|
||||||
|
t.Fatalf("tomb should be %v, got %v", context.Canceled, tb.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
if tb.Context(parent1) == child1 || tb.Context(parent3) == child3 {
|
||||||
|
t.Fatalf("Tomb is dead and shouldn't be tracking children anymore")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatalf("Child context didn't die after tomb's death")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent4 := context.WithValue(context.Background(), "parent", "parent4")
|
||||||
|
child4 := tb.Context(parent4)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child4.Done():
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
|
||||||
|
childnil := tb.Context(nil)
|
||||||
|
select {
|
||||||
|
case <-childnil.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextNoParent(t *testing.T) {
|
||||||
|
var tb tomb.Tomb
|
||||||
|
|
||||||
|
parent2, cancel2 := context.WithCancel(context.WithValue(context.Background(), "parent", "parent2"))
|
||||||
|
child2 := tb.Context(parent2)
|
||||||
|
|
||||||
|
if tb.Context(parent2) != child2 {
|
||||||
|
t.Fatalf("Context returned different context for same parent")
|
||||||
|
}
|
||||||
|
if child2.Value("parent") != "parent2" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel2()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Tomb's child context didn't die after parent was canceled")
|
||||||
|
}
|
||||||
|
if !tb.Alive() {
|
||||||
|
t.Fatalf("Canceling unrelated parent context killed tomb")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent3 := context.WithValue(context.Background(), "parent", "parent3")
|
||||||
|
child3 := tb.Context(parent3)
|
||||||
|
|
||||||
|
if child3.Value("parent") != "parent3" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
tb.Kill(nil)
|
||||||
|
|
||||||
|
if tb.Context(parent3) == child3 {
|
||||||
|
t.Fatalf("Tomb is dead and shouldn't be tracking children anymore")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context didn't die after tomb's death")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent4 := context.WithValue(context.Background(), "parent", "parent4")
|
||||||
|
child4 := tb.Context(parent4)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child4.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
|
||||||
|
childnil := tb.Context(nil)
|
||||||
|
select {
|
||||||
|
case <-childnil.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
}
|
176
vendor/gopkg.in/tomb.v2/context_test.go
generated
vendored
Normal file
176
vendor/gopkg.in/tomb.v2/context_test.go
generated
vendored
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package tomb_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/tomb.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithContext(t *testing.T) {
|
||||||
|
parent1, cancel1 := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
tb, child1 := tomb.WithContext(parent1)
|
||||||
|
|
||||||
|
if !tb.Alive() {
|
||||||
|
t.Fatalf("WithContext returned dead tomb")
|
||||||
|
}
|
||||||
|
if tb.Context(parent1) != child1 {
|
||||||
|
t.Fatalf("Context returned different context for same parent")
|
||||||
|
}
|
||||||
|
if tb.Context(nil) != child1 {
|
||||||
|
t.Fatalf("Context returned different context for nil parent")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child1.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
parent2, cancel2 := context.WithCancel(context.WithValue(context.Background(), "parent", "parent2"))
|
||||||
|
child2 := tb.Context(parent2)
|
||||||
|
|
||||||
|
if tb.Context(parent2) != child2 {
|
||||||
|
t.Fatalf("Context returned different context for same parent")
|
||||||
|
}
|
||||||
|
if child2.Value("parent") != "parent2" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel2()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Tomb's child context didn't die after parent was canceled")
|
||||||
|
}
|
||||||
|
if !tb.Alive() {
|
||||||
|
t.Fatalf("Canceling unrelated parent context killed tomb")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent3 := context.WithValue(context.Background(), "parent", "parent3")
|
||||||
|
child3 := tb.Context(parent3)
|
||||||
|
|
||||||
|
if child3.Value("parent") != "parent3" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel1()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-tb.Dying():
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatalf("Canceling parent context did not kill tomb")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tb.Err() != context.Canceled {
|
||||||
|
t.Fatalf("tomb should be %v, got %v", context.Canceled, tb.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
if tb.Context(parent1) == child1 || tb.Context(parent3) == child3 {
|
||||||
|
t.Fatalf("Tomb is dead and shouldn't be tracking children anymore")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context didn't die after tomb's death")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent4 := context.WithValue(context.Background(), "parent", "parent4")
|
||||||
|
child4 := tb.Context(parent4)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child4.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
|
||||||
|
childnil := tb.Context(nil)
|
||||||
|
select {
|
||||||
|
case <-childnil.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextNoParent(t *testing.T) {
|
||||||
|
var tb tomb.Tomb
|
||||||
|
|
||||||
|
parent2, cancel2 := context.WithCancel(context.WithValue(context.Background(), "parent", "parent2"))
|
||||||
|
child2 := tb.Context(parent2)
|
||||||
|
|
||||||
|
if tb.Context(parent2) != child2 {
|
||||||
|
t.Fatalf("Context returned different context for same parent")
|
||||||
|
}
|
||||||
|
if child2.Value("parent") != "parent2" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel2()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child2.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Tomb's child context didn't die after parent was canceled")
|
||||||
|
}
|
||||||
|
if !tb.Alive() {
|
||||||
|
t.Fatalf("Canceling unrelated parent context killed tomb")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent3 := context.WithValue(context.Background(), "parent", "parent3")
|
||||||
|
child3 := tb.Context(parent3)
|
||||||
|
|
||||||
|
if child3.Value("parent") != "parent3" {
|
||||||
|
t.Fatalf("Child context didn't inherit its parent's properties")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
t.Fatalf("Tomb's child context was born dead")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
tb.Kill(nil)
|
||||||
|
|
||||||
|
if tb.Context(parent3) == child3 {
|
||||||
|
t.Fatalf("Tomb is dead and shouldn't be tracking children anymore")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-child3.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context didn't die after tomb's death")
|
||||||
|
}
|
||||||
|
|
||||||
|
parent4 := context.WithValue(context.Background(), "parent", "parent4")
|
||||||
|
child4 := tb.Context(parent4)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-child4.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
|
||||||
|
childnil := tb.Context(nil)
|
||||||
|
select {
|
||||||
|
case <-childnil.Done():
|
||||||
|
default:
|
||||||
|
t.Fatalf("Child context should be born canceled")
|
||||||
|
}
|
||||||
|
}
|
237
vendor/gopkg.in/tomb.v2/tomb.go
generated
vendored
Normal file
237
vendor/gopkg.in/tomb.v2/tomb.go
generated
vendored
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
// Copyright (c) 2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of the copyright holder nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// The tomb package handles clean goroutine tracking and termination.
|
||||||
|
//
|
||||||
|
// The zero value of a Tomb is ready to handle the creation of a tracked
|
||||||
|
// goroutine via its Go method, and then any tracked goroutine may call
|
||||||
|
// the Go method again to create additional tracked goroutines at
|
||||||
|
// any point.
|
||||||
|
//
|
||||||
|
// If any of the tracked goroutines returns a non-nil error, or the
|
||||||
|
// Kill or Killf method is called by any goroutine in the system (tracked
|
||||||
|
// or not), the tomb Err is set, Alive is set to false, and the Dying
|
||||||
|
// channel is closed to flag that all tracked goroutines are supposed
|
||||||
|
// to willingly terminate as soon as possible.
|
||||||
|
//
|
||||||
|
// Once all tracked goroutines terminate, the Dead channel is closed,
|
||||||
|
// and Wait unblocks and returns the first non-nil error presented
|
||||||
|
// to the tomb via a result or an explicit Kill or Killf method call,
|
||||||
|
// or nil if there were no errors.
|
||||||
|
//
|
||||||
|
// It is okay to create further goroutines via the Go method while
|
||||||
|
// the tomb is in a dying state. The final dead state is only reached
|
||||||
|
// once all tracked goroutines terminate, at which point calling
|
||||||
|
// the Go method again will cause a runtime panic.
|
||||||
|
//
|
||||||
|
// Tracked functions and methods that are still running while the tomb
|
||||||
|
// is in dying state may choose to return ErrDying as their error value.
|
||||||
|
// This preserves the well established non-nil error convention, but is
|
||||||
|
// understood by the tomb as a clean termination. The Err and Wait
|
||||||
|
// methods will still return nil if all observed errors were either
|
||||||
|
// nil or ErrDying.
|
||||||
|
//
|
||||||
|
// For background and a detailed example, see the following blog post:
|
||||||
|
//
|
||||||
|
// http://blog.labix.org/2011/10/09/death-of-goroutines-under-control
|
||||||
|
//
|
||||||
|
package tomb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Tomb tracks the lifecycle of one or more goroutines as alive,
|
||||||
|
// dying or dead, and the reason for their death.
|
||||||
|
//
|
||||||
|
// See the package documentation for details.
|
||||||
|
type Tomb struct {
|
||||||
|
m sync.Mutex
|
||||||
|
alive int
|
||||||
|
dying chan struct{}
|
||||||
|
dead chan struct{}
|
||||||
|
reason error
|
||||||
|
|
||||||
|
// context.Context is available in Go 1.7+.
|
||||||
|
parent interface{}
|
||||||
|
child map[interface{}]childContext
|
||||||
|
}
|
||||||
|
|
||||||
|
type childContext struct {
|
||||||
|
context interface{}
|
||||||
|
cancel func()
|
||||||
|
done <-chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrStillAlive = errors.New("tomb: still alive")
|
||||||
|
ErrDying = errors.New("tomb: dying")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *Tomb) init() {
|
||||||
|
t.m.Lock()
|
||||||
|
if t.dead == nil {
|
||||||
|
t.dead = make(chan struct{})
|
||||||
|
t.dying = make(chan struct{})
|
||||||
|
t.reason = ErrStillAlive
|
||||||
|
}
|
||||||
|
t.m.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dead returns the channel that can be used to wait until
|
||||||
|
// all goroutines have finished running.
|
||||||
|
func (t *Tomb) Dead() <-chan struct{} {
|
||||||
|
t.init()
|
||||||
|
return t.dead
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dying returns the channel that can be used to wait until
|
||||||
|
// t.Kill is called.
|
||||||
|
func (t *Tomb) Dying() <-chan struct{} {
|
||||||
|
t.init()
|
||||||
|
return t.dying
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait blocks until all goroutines have finished running, and
|
||||||
|
// then returns the reason for their death.
|
||||||
|
func (t *Tomb) Wait() error {
|
||||||
|
t.init()
|
||||||
|
<-t.dead
|
||||||
|
t.m.Lock()
|
||||||
|
reason := t.reason
|
||||||
|
t.m.Unlock()
|
||||||
|
return reason
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go runs f in a new goroutine and tracks its termination.
|
||||||
|
//
|
||||||
|
// If f returns a non-nil error, t.Kill is called with that
|
||||||
|
// error as the death reason parameter.
|
||||||
|
//
|
||||||
|
// It is f's responsibility to monitor the tomb and return
|
||||||
|
// appropriately once it is in a dying state.
|
||||||
|
//
|
||||||
|
// It is safe for the f function to call the Go method again
|
||||||
|
// to create additional tracked goroutines. Once all tracked
|
||||||
|
// goroutines return, the Dead channel is closed and the
|
||||||
|
// Wait method unblocks and returns the death reason.
|
||||||
|
//
|
||||||
|
// Calling the Go method after all tracked goroutines return
|
||||||
|
// causes a runtime panic. For that reason, calling the Go
|
||||||
|
// method a second time out of a tracked goroutine is unsafe.
|
||||||
|
func (t *Tomb) Go(f func() error) {
|
||||||
|
t.init()
|
||||||
|
t.m.Lock()
|
||||||
|
defer t.m.Unlock()
|
||||||
|
select {
|
||||||
|
case <-t.dead:
|
||||||
|
panic("tomb.Go called after all goroutines terminated")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
t.alive++
|
||||||
|
go t.run(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tomb) run(f func() error) {
|
||||||
|
err := f()
|
||||||
|
t.m.Lock()
|
||||||
|
defer t.m.Unlock()
|
||||||
|
t.alive--
|
||||||
|
if t.alive == 0 || err != nil {
|
||||||
|
t.kill(err)
|
||||||
|
if t.alive == 0 {
|
||||||
|
close(t.dead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill puts the tomb in a dying state for the given reason,
|
||||||
|
// closes the Dying channel, and sets Alive to false.
|
||||||
|
//
|
||||||
|
// Althoguh Kill may be called multiple times, only the first
|
||||||
|
// non-nil error is recorded as the death reason.
|
||||||
|
//
|
||||||
|
// If reason is ErrDying, the previous reason isn't replaced
|
||||||
|
// even if nil. It's a runtime error to call Kill with ErrDying
|
||||||
|
// if t is not in a dying state.
|
||||||
|
func (t *Tomb) Kill(reason error) {
|
||||||
|
t.init()
|
||||||
|
t.m.Lock()
|
||||||
|
defer t.m.Unlock()
|
||||||
|
t.kill(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tomb) kill(reason error) {
|
||||||
|
if reason == ErrStillAlive {
|
||||||
|
panic("tomb: Kill with ErrStillAlive")
|
||||||
|
}
|
||||||
|
if reason == ErrDying {
|
||||||
|
if t.reason == ErrStillAlive {
|
||||||
|
panic("tomb: Kill with ErrDying while still alive")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if t.reason == ErrStillAlive {
|
||||||
|
t.reason = reason
|
||||||
|
close(t.dying)
|
||||||
|
for _, child := range t.child {
|
||||||
|
child.cancel()
|
||||||
|
}
|
||||||
|
t.child = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if t.reason == nil {
|
||||||
|
t.reason = reason
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Killf calls the Kill method with an error built providing the received
|
||||||
|
// parameters to fmt.Errorf. The generated error is also returned.
|
||||||
|
func (t *Tomb) Killf(f string, a ...interface{}) error {
|
||||||
|
err := fmt.Errorf(f, a...)
|
||||||
|
t.Kill(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns the death reason, or ErrStillAlive if the tomb
|
||||||
|
// is not in a dying or dead state.
|
||||||
|
func (t *Tomb) Err() (reason error) {
|
||||||
|
t.init()
|
||||||
|
t.m.Lock()
|
||||||
|
reason = t.reason
|
||||||
|
t.m.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alive returns true if the tomb is not in a dying or dead state.
|
||||||
|
func (t *Tomb) Alive() bool {
|
||||||
|
return t.Err() == ErrStillAlive
|
||||||
|
}
|
183
vendor/gopkg.in/tomb.v2/tomb_test.go
generated
vendored
Normal file
183
vendor/gopkg.in/tomb.v2/tomb_test.go
generated
vendored
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
package tomb_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"gopkg.in/tomb.v2"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func nothing() error { return nil }
|
||||||
|
|
||||||
|
func TestNewTomb(t *testing.T) {
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
checkState(t, tb, false, false, tomb.ErrStillAlive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGo(t *testing.T) {
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
alive := make(chan bool)
|
||||||
|
tb.Go(func() error {
|
||||||
|
alive <- true
|
||||||
|
tb.Go(func() error {
|
||||||
|
alive <- true
|
||||||
|
<-tb.Dying()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
<-tb.Dying()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
<-alive
|
||||||
|
<-alive
|
||||||
|
checkState(t, tb, false, false, tomb.ErrStillAlive)
|
||||||
|
tb.Kill(nil)
|
||||||
|
tb.Wait()
|
||||||
|
checkState(t, tb, true, true, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoErr(t *testing.T) {
|
||||||
|
first := errors.New("first error")
|
||||||
|
second := errors.New("first error")
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
alive := make(chan bool)
|
||||||
|
tb.Go(func() error {
|
||||||
|
alive <- true
|
||||||
|
tb.Go(func() error {
|
||||||
|
alive <- true
|
||||||
|
return first
|
||||||
|
})
|
||||||
|
<-tb.Dying()
|
||||||
|
return second
|
||||||
|
})
|
||||||
|
<-alive
|
||||||
|
<-alive
|
||||||
|
tb.Wait()
|
||||||
|
checkState(t, tb, true, true, first)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoPanic(t *testing.T) {
|
||||||
|
// ErrDying being used properly, after a clean death.
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
tb.Go(nothing)
|
||||||
|
tb.Wait()
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != "tomb.Go called after all goroutines terminated" {
|
||||||
|
t.Fatalf("Wrong panic on post-death tomb.Go call: %v", err)
|
||||||
|
}
|
||||||
|
checkState(t, tb, true, true, nil)
|
||||||
|
}()
|
||||||
|
tb.Go(nothing)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKill(t *testing.T) {
|
||||||
|
// a nil reason flags the goroutine as dying
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
tb.Kill(nil)
|
||||||
|
checkState(t, tb, true, false, nil)
|
||||||
|
|
||||||
|
// a non-nil reason now will override Kill
|
||||||
|
err := errors.New("some error")
|
||||||
|
tb.Kill(err)
|
||||||
|
checkState(t, tb, true, false, err)
|
||||||
|
|
||||||
|
// another non-nil reason won't replace the first one
|
||||||
|
tb.Kill(errors.New("ignore me"))
|
||||||
|
checkState(t, tb, true, false, err)
|
||||||
|
|
||||||
|
tb.Go(nothing)
|
||||||
|
tb.Wait()
|
||||||
|
checkState(t, tb, true, true, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKillf(t *testing.T) {
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
|
||||||
|
err := tb.Killf("BO%s", "OM")
|
||||||
|
if s := err.Error(); s != "BOOM" {
|
||||||
|
t.Fatalf(`Killf("BO%s", "OM"): want "BOOM", got %q`, s)
|
||||||
|
}
|
||||||
|
checkState(t, tb, true, false, err)
|
||||||
|
|
||||||
|
// another non-nil reason won't replace the first one
|
||||||
|
tb.Killf("ignore me")
|
||||||
|
checkState(t, tb, true, false, err)
|
||||||
|
|
||||||
|
tb.Go(nothing)
|
||||||
|
tb.Wait()
|
||||||
|
checkState(t, tb, true, true, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrDying(t *testing.T) {
|
||||||
|
// ErrDying being used properly, after a clean death.
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
tb.Kill(nil)
|
||||||
|
tb.Kill(tomb.ErrDying)
|
||||||
|
checkState(t, tb, true, false, nil)
|
||||||
|
|
||||||
|
// ErrDying being used properly, after an errorful death.
|
||||||
|
err := errors.New("some error")
|
||||||
|
tb.Kill(err)
|
||||||
|
tb.Kill(tomb.ErrDying)
|
||||||
|
checkState(t, tb, true, false, err)
|
||||||
|
|
||||||
|
// ErrDying being used badly, with an alive tomb.
|
||||||
|
tb = &tomb.Tomb{}
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != "tomb: Kill with ErrDying while still alive" {
|
||||||
|
t.Fatalf("Wrong panic on Kill(ErrDying): %v", err)
|
||||||
|
}
|
||||||
|
checkState(t, tb, false, false, tomb.ErrStillAlive)
|
||||||
|
}()
|
||||||
|
tb.Kill(tomb.ErrDying)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKillErrStillAlivePanic(t *testing.T) {
|
||||||
|
tb := &tomb.Tomb{}
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != "tomb: Kill with ErrStillAlive" {
|
||||||
|
t.Fatalf("Wrong panic on Kill(ErrStillAlive): %v", err)
|
||||||
|
}
|
||||||
|
checkState(t, tb, false, false, tomb.ErrStillAlive)
|
||||||
|
}()
|
||||||
|
tb.Kill(tomb.ErrStillAlive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkState(t *testing.T, tb *tomb.Tomb, wantDying, wantDead bool, wantErr error) {
|
||||||
|
select {
|
||||||
|
case <-tb.Dying():
|
||||||
|
if !wantDying {
|
||||||
|
t.Error("<-Dying: should block")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if wantDying {
|
||||||
|
t.Error("<-Dying: should not block")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seemsDead := false
|
||||||
|
select {
|
||||||
|
case <-tb.Dead():
|
||||||
|
if !wantDead {
|
||||||
|
t.Error("<-Dead: should block")
|
||||||
|
}
|
||||||
|
seemsDead = true
|
||||||
|
default:
|
||||||
|
if wantDead {
|
||||||
|
t.Error("<-Dead: should not block")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := tb.Err(); err != wantErr {
|
||||||
|
t.Errorf("Err: want %#v, got %#v", wantErr, err)
|
||||||
|
}
|
||||||
|
if wantDead && seemsDead {
|
||||||
|
waitErr := tb.Wait()
|
||||||
|
switch {
|
||||||
|
case waitErr == tomb.ErrStillAlive:
|
||||||
|
t.Errorf("Wait should not return ErrStillAlive")
|
||||||
|
case !reflect.DeepEqual(waitErr, wantErr):
|
||||||
|
t.Errorf("Wait: want %#v, got %#v", wantErr, waitErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue