blob: f901a4299bd4bcb71b3aef7b5d19305f4e8a3350 [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package task
import "time"
// Baton implements a task interlock.
// A baton must be owned by exactly 1 task at any given time, so a release blocks until a corresponding acquire occurs.
// You can pass a value through the baton from the release to the acquire.
type Baton chan interface{}
// NewBaton returns a new Baton, with the expectation that the calling goroutine owns the baton.
func NewBaton() Baton { return make(Baton) }
// Acquire is a request to pick up the baton, it will block until another goroutine releases it.
// It returns the value passed to the release that triggers it.
func (b Baton) Acquire() interface{} {
return <-b
}
// TryAcquire is a request to pick up the baton, it will block until another goroutine releases it or timeout passes.
// It will return the released value and true if the baton was successfully acquired.
func (b Baton) TryAcquire(timeout time.Duration) (interface{}, bool) {
select {
case value := <-b:
return value, true
case <-time.Tick(timeout):
return nil, false
}
}
// Release is a request to relinquish the baton, it will block until another goroutine acquires it.
// The supplied value is returned from the Acquire this release triggers.
func (b Baton) Release(value interface{}) {
b <- value
}
// TryRelease is a request to relinquish the baton, it will block until another goroutine acquires it or timeout passes.
// It will return true if the baton was successfully released.
func (b Baton) TryRelease(value interface{}, timeout time.Duration) bool {
select {
case b <- value:
return true
case <-time.Tick(timeout):
return false
}
}
// Yield is helper that does Release followed by an Acquire.
// It waits for another goroutine to acquire the baton, and then waits for the baton to be released back to this goroutine.
func (b Baton) Yield(value interface{}) interface{} {
b.Release(value)
return b.Acquire()
}
// Relay is a helper that does an Acquire followed by a Release with the value that came from the Acquire.
// This waits for the baton to be available, and then immediately passes back, used as a signalling gate.
func (b Baton) Relay() {
value := b.Acquire()
b.Release(value)
}