1 // Copyright 2024 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 package http2 5 6 import "context" 7 8 // An gate is a monitor (mutex + condition variable) with one bit of state. 9 // 10 // The condition may be either set or unset. 11 // Lock operations may be unconditional, or wait for the condition to be set. 12 // Unlock operations record the new state of the condition. 13 type gate struct { 14 // When unlocked, exactly one of set or unset contains a value. 15 // When locked, neither chan contains a value. 16 set chan struct{} 17 unset chan struct{} 18 } 19 20 // newGate returns a new, unlocked gate with the condition unset. 21 func newGate() gate { 22 g := newLockedGate() 23 g.unlock(false) 24 return g 25 } 26 27 // newLocked gate returns a new, locked gate. 28 func newLockedGate() gate { 29 return gate{ 30 set: make(chan struct{}, 1), 31 unset: make(chan struct{}, 1), 32 } 33 } 34 35 // lock acquires the gate unconditionally. 36 // It reports whether the condition is set. 37 func (g *gate) lock() (set bool) { 38 select { 39 case <-g.set: 40 return true 41 case <-g.unset: 42 return false 43 } 44 } 45 46 // waitAndLock waits until the condition is set before acquiring the gate. 47 // If the context expires, waitAndLock returns an error and does not acquire the gate. 48 func (g *gate) waitAndLock(ctx context.Context) error { 49 select { 50 case <-g.set: 51 return nil 52 default: 53 } 54 select { 55 case <-g.set: 56 return nil 57 case <-ctx.Done(): 58 return ctx.Err() 59 } 60 } 61 62 // lockIfSet acquires the gate if and only if the condition is set. 63 func (g *gate) lockIfSet() (acquired bool) { 64 select { 65 case <-g.set: 66 return true 67 default: 68 return false 69 } 70 } 71 72 // unlock sets the condition and releases the gate. 73 func (g *gate) unlock(set bool) { 74 if set { 75 g.set <- struct{}{} 76 } else { 77 g.unset <- struct{}{} 78 } 79 } 80 81 // unlock sets the condition to the result of f and releases the gate. 82 // Useful in defers. 83 func (g *gate) unlockFunc(f func() bool) { 84 g.unlock(f()) 85 } 86