// 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{}{} } }