rclone/vendor/storj.io/drpc/drpcsignal/signal.go
2020-05-12 15:56:50 +00:00

76 lines
1.7 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package drpcsignal
import (
"sync"
"sync/atomic"
)
// Signal contains an error value that can be set one and exports
// a number of ways to inspect it.
type Signal struct {
set uint32
on sync.Once
mu sync.Mutex
sig chan struct{}
err error
}
func (s *Signal) init() { s.sig = make(chan struct{}) }
// Signal returns a channel that will be closed when the signal is set.
func (s *Signal) Signal() chan struct{} {
s.on.Do(s.init)
return s.sig
}
// Set stores the error in the signal. It only keeps track of the first
// error set, and returns true if it was the first error set.
func (s *Signal) Set(err error) (ok bool) {
if atomic.LoadUint32(&s.set) != 0 {
return false
}
return s.setSlow(err)
}
// setSlow is the slow path for Set, so that the fast path is inlined into
// callers.
func (s *Signal) setSlow(err error) (ok bool) {
s.mu.Lock()
if s.set == 0 {
s.err = err
atomic.StoreUint32(&s.set, 1)
s.on.Do(s.init)
close(s.sig)
ok = true
}
s.mu.Unlock()
return ok
}
// Get returns the error set with the signal and a boolean indicating if
// the result is valid.
func (s *Signal) Get() (error, bool) { //nolint
if atomic.LoadUint32(&s.set) != 0 {
return s.err, true
}
return nil, false
}
// IsSet returns true if the Signal is set.
func (s *Signal) IsSet() bool {
return atomic.LoadUint32(&s.set) != 0
}
// Err returns the error stored in the signal. Since one can store a nil error
// care must be taken. A non-nil error returned from this method means that
// the Signal has been set, but the inverse is not true.
func (s *Signal) Err() error {
if atomic.LoadUint32(&s.set) != 0 {
return s.err
}
return nil
}