| // Copyright 2024 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Package gate contains an alternative condition variable. | |
| package gate | |
| import "context" | |
| // A Gate is a monitor (mutex + condition variable) with one bit of state. | |
| // | |
| // The condition may be either set or unset. | |
| // Lock operations may be unconditional, or wait for the condition to be set. | |
| // Unlock operations record the new state of the condition. | |
| type Gate struct { | |
| // When unlocked, exactly one of set or unset contains a value. | |
| // When locked, neither chan contains a value. | |
| set chan struct{} | |
| unset chan struct{} | |
| } | |
| // New returns a new, unlocked gate. | |
| func New(set bool) Gate { | |
| g := Gate{ | |
| set: make(chan struct{}, 1), | |
| unset: make(chan struct{}, 1), | |
| } | |
| g.Unlock(set) | |
| return g | |
| } | |
| // Lock acquires the gate unconditionally. | |
| // It reports whether the condition is set. | |
| func (g *Gate) Lock() (set bool) { | |
| select { | |
| case <-g.set: | |
| return true | |
| case <-g.unset: | |
| return false | |
| } | |
| } | |
| // WaitAndLock waits until the condition is set before acquiring the gate. | |
| // If the context expires, WaitAndLock returns an error and does not acquire the gate. | |
| func (g *Gate) WaitAndLock(ctx context.Context) error { | |
| select { | |
| case <-g.set: | |
| return nil | |
| default: | |
| } | |
| select { | |
| case <-g.set: | |
| return nil | |
| case <-ctx.Done(): | |
| return ctx.Err() | |
| } | |
| } | |
| // LockIfSet acquires the gate if and only if the condition is set. | |
| func (g *Gate) LockIfSet() (acquired bool) { | |
| select { | |
| case <-g.set: | |
| return true | |
| default: | |
| return false | |
| } | |
| } | |
| // Unlock sets the condition and releases the gate. | |
| func (g *Gate) Unlock(set bool) { | |
| if set { | |
| g.set <- struct{}{} | |
| } else { | |
| g.unset <- struct{}{} | |
| } | |
| } |