github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/device/pools.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package device
     7  
     8  import (
     9  	"sync"
    10  	"sync/atomic"
    11  )
    12  
    13  type WaitPool struct {
    14  	pool  sync.Pool
    15  	cond  sync.Cond
    16  	lock  sync.Mutex
    17  	count uint32
    18  	max   uint32
    19  }
    20  
    21  func NewWaitPool(max uint32, new func() interface{}) *WaitPool {
    22  	p := &WaitPool{pool: sync.Pool{New: new}, max: max}
    23  	p.cond = sync.Cond{L: &p.lock}
    24  	return p
    25  }
    26  
    27  func (p *WaitPool) Get() interface{} {
    28  	if p.max != 0 {
    29  		p.lock.Lock()
    30  		for atomic.LoadUint32(&p.count) >= p.max {
    31  			p.cond.Wait()
    32  		}
    33  		atomic.AddUint32(&p.count, 1)
    34  		p.lock.Unlock()
    35  	}
    36  	return p.pool.Get()
    37  }
    38  
    39  func (p *WaitPool) Put(x interface{}) {
    40  	p.pool.Put(x)
    41  	if p.max == 0 {
    42  		return
    43  	}
    44  	atomic.AddUint32(&p.count, ^uint32(0))
    45  	p.cond.Signal()
    46  }
    47  
    48  func (device *Device) PopulatePools() {
    49  	device.pool.messageBuffers = NewWaitPool(PreallocatedBuffersPerPool, func() interface{} {
    50  		return new([MaxMessageSize]byte)
    51  	})
    52  	device.pool.inboundElements = NewWaitPool(PreallocatedBuffersPerPool, func() interface{} {
    53  		return new(QueueInboundElement)
    54  	})
    55  	device.pool.outboundElements = NewWaitPool(PreallocatedBuffersPerPool, func() interface{} {
    56  		return new(QueueOutboundElement)
    57  	})
    58  }
    59  
    60  func (device *Device) GetMessageBuffer() *[MaxMessageSize]byte {
    61  	return device.pool.messageBuffers.Get().(*[MaxMessageSize]byte)
    62  }
    63  
    64  func (device *Device) PutMessageBuffer(msg *[MaxMessageSize]byte) {
    65  	device.pool.messageBuffers.Put(msg)
    66  }
    67  
    68  func (device *Device) GetInboundElement() *QueueInboundElement {
    69  	return device.pool.inboundElements.Get().(*QueueInboundElement)
    70  }
    71  
    72  func (device *Device) PutInboundElement(elem *QueueInboundElement) {
    73  	elem.clearPointers()
    74  	device.pool.inboundElements.Put(elem)
    75  }
    76  
    77  func (device *Device) GetOutboundElement() *QueueOutboundElement {
    78  	return device.pool.outboundElements.Get().(*QueueOutboundElement)
    79  }
    80  
    81  func (device *Device) PutOutboundElement(elem *QueueOutboundElement) {
    82  	elem.clearPointers()
    83  	device.pool.outboundElements.Put(elem)
    84  }