github.com/anacrolix/torrent@v1.61.0/internal/alloclim/l.go (about) 1 package alloclim 2 3 import "sync" 4 5 // Manages reservations sharing a common allocation limit. 6 type Limiter struct { 7 // Maximum outstanding allocation space. 8 Max int64 9 initOnce sync.Once 10 mu sync.Mutex 11 // Current unallocated space. 12 value int64 13 // Reservations waiting to in the order they arrived. 14 waiting []*Reservation 15 } 16 17 func (me *Limiter) initValue() { 18 me.value = me.Max 19 } 20 21 func (me *Limiter) init() { 22 me.initOnce.Do(func() { 23 me.initValue() 24 }) 25 } 26 27 func (me *Limiter) Reserve(n int64) *Reservation { 28 r := &Reservation{ 29 l: me, 30 n: n, 31 } 32 me.init() 33 me.mu.Lock() 34 if n <= me.value { 35 me.value -= n 36 r.granted.Set() 37 } else { 38 me.waiting = append(me.waiting, r) 39 } 40 me.mu.Unlock() 41 return r 42 } 43 44 func (me *Limiter) doWakesLocked() { 45 for { 46 if len(me.waiting) == 0 { 47 break 48 } 49 r := me.waiting[0] 50 switch { 51 case r.cancelled.IsSet(): 52 case r.n <= me.value: 53 if r.wake() { 54 me.value -= r.n 55 } 56 default: 57 return 58 } 59 me.waiting = me.waiting[1:] 60 } 61 } 62 63 func (me *Limiter) doWakes() { 64 me.mu.Lock() 65 me.doWakesLocked() 66 me.mu.Unlock() 67 } 68 69 func (me *Limiter) addValue(n int64) { 70 me.mu.Lock() 71 me.value += n 72 me.doWakesLocked() 73 me.mu.Unlock() 74 } 75 76 func (me *Limiter) Value() int64 { 77 me.mu.Lock() 78 defer me.mu.Unlock() 79 return me.value 80 }