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  }