summaryrefslogtreecommitdiff
path: root/vendor/gopkg.in/tomb.v1/tomb.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/tomb.v1/tomb.go')
-rw-r--r--vendor/gopkg.in/tomb.v1/tomb.go176
1 files changed, 176 insertions, 0 deletions
diff --git a/vendor/gopkg.in/tomb.v1/tomb.go b/vendor/gopkg.in/tomb.v1/tomb.go
new file mode 100644
index 000000000..9aec56d82
--- /dev/null
+++ b/vendor/gopkg.in/tomb.v1/tomb.go
@@ -0,0 +1,176 @@
+// 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 offers a conventional API for clean goroutine termination.
+//
+// A Tomb tracks the lifecycle of a goroutine as alive, dying or dead,
+// and the reason for its death.
+//
+// The zero value of a Tomb assumes that a goroutine is about to be
+// created or already alive. Once Kill or Killf is called with an
+// argument that informs the reason for death, the goroutine is in
+// a dying state and is expected to terminate soon. Right before the
+// goroutine function or method returns, Done must be called to inform
+// that the goroutine is indeed dead and about to stop running.
+//
+// A Tomb exposes Dying and Dead channels. These channels are closed
+// when the Tomb state changes in the respective way. They enable
+// explicit blocking until the state changes, and also to selectively
+// unblock select statements accordingly.
+//
+// When the tomb state changes to dying and there's still logic going
+// on within the goroutine, nested functions and methods may choose to
+// return ErrDying as their error value, as this error won't alter the
+// tomb state if provided to the Kill method. This is a convenient way to
+// follow standard Go practices in the context of a dying tomb.
+//
+// For background and a detailed example, see the following blog post:
+//
+// http://blog.labix.org/2011/10/09/death-of-goroutines-under-control
+//
+// For a more complex code snippet demonstrating the use of multiple
+// goroutines with a single Tomb, see:
+//
+// http://play.golang.org/p/Xh7qWsDPZP
+//
+package tomb
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+)
+
+// A Tomb tracks the lifecycle of a goroutine as alive, dying or dead,
+// and the reason for its death.
+//
+// See the package documentation for details.
+type Tomb struct {
+ m sync.Mutex
+ dying chan struct{}
+ dead chan struct{}
+ reason error
+}
+
+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 t.Done has been called.
+func (t *Tomb) Dead() <-chan struct{} {
+ t.init()
+ return t.dead
+}
+
+// Dying returns the channel that can be used to wait
+// until t.Kill or t.Done has been called.
+func (t *Tomb) Dying() <-chan struct{} {
+ t.init()
+ return t.dying
+}
+
+// Wait blocks until the goroutine is in a dead state and returns the
+// reason for its death.
+func (t *Tomb) Wait() error {
+ t.init()
+ <-t.dead
+ t.m.Lock()
+ reason := t.reason
+ t.m.Unlock()
+ return reason
+}
+
+// Done flags the goroutine as dead, and should be called a single time
+// right before the goroutine function or method returns.
+// If the goroutine was not already in a dying state before Done is
+// called, it will be flagged as dying and dead at once with no
+// error.
+func (t *Tomb) Done() {
+ t.Kill(nil)
+ close(t.dead)
+}
+
+// Kill flags the goroutine as dying for the given reason.
+// Kill may be called multiple times, but only the first
+// non-nil error is recorded as the reason for termination.
+//
+// If reason is ErrDying, the previous reason isn't replaced
+// even if it is 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()
+ if reason == ErrDying {
+ if t.reason == ErrStillAlive {
+ panic("tomb: Kill with ErrDying while still alive")
+ }
+ return
+ }
+ if t.reason == nil || t.reason == ErrStillAlive {
+ t.reason = reason
+ }
+ // If the receive on t.dying succeeds, then
+ // it can only be because we have already closed it.
+ // If it blocks, then we know that it needs to be closed.
+ select {
+ case <-t.dying:
+ default:
+ close(t.dying)
+ }
+}
+
+// Killf works like Kill, but builds the reason providing the received
+// arguments 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 reason for the goroutine death provided via Kill
+// or Killf, or ErrStillAlive when the goroutine is still alive.
+func (t *Tomb) Err() (reason error) {
+ t.init()
+ t.m.Lock()
+ reason = t.reason
+ t.m.Unlock()
+ return
+}