github.com/noisysockets/netstack@v0.6.0/pkg/tcpip/link/qdisc/fifo/packet_buffer_circular_list.go (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package fifo
    15  
    16  import "github.com/noisysockets/netstack/pkg/tcpip/stack"
    17  
    18  // packetBufferCircularList is a slice-backed circular list. All operations are
    19  // O(1) unless otherwise noted. It only allocates once, during the call to
    20  // init().
    21  //
    22  // Users should call init() before using packetBufferCircularList.
    23  //
    24  // +stateify savable
    25  type packetBufferCircularList struct {
    26  	pbs  []*stack.PacketBuffer
    27  	head int
    28  	size int
    29  }
    30  
    31  // init initializes the list with the given size.
    32  func (pl *packetBufferCircularList) init(size int) {
    33  	pl.pbs = make([]*stack.PacketBuffer, size)
    34  }
    35  
    36  // length returns the number of elements in the list.
    37  //
    38  //go:nosplit
    39  func (pl *packetBufferCircularList) length() int {
    40  	return pl.size
    41  }
    42  
    43  // hasSpace returns whether there is space left in the list.
    44  //
    45  //go:nosplit
    46  func (pl *packetBufferCircularList) hasSpace() bool {
    47  	return pl.size < len(pl.pbs)
    48  }
    49  
    50  // isEmpty returns whether the list is empty.
    51  //
    52  //go:nosplit
    53  func (pl *packetBufferCircularList) isEmpty() bool {
    54  	return pl.size == 0
    55  }
    56  
    57  // pushBack inserts the PacketBuffer at the end of the list.
    58  //
    59  // Users must check beforehand that there is space via a call to hasSpace().
    60  // Failing to do so may clobber existing entries.
    61  //
    62  //go:nosplit
    63  func (pl *packetBufferCircularList) pushBack(pb *stack.PacketBuffer) {
    64  	next := (pl.head + pl.size) % len(pl.pbs)
    65  	pl.pbs[next] = pb
    66  	pl.size++
    67  }
    68  
    69  // removeFront returns the first element of the list or nil.
    70  //
    71  //go:nosplit
    72  func (pl *packetBufferCircularList) removeFront() *stack.PacketBuffer {
    73  	if pl.isEmpty() {
    74  		return nil
    75  	}
    76  	ret := pl.pbs[pl.head]
    77  	pl.pbs[pl.head] = nil
    78  	pl.head = (pl.head + 1) % len(pl.pbs)
    79  	pl.size--
    80  	return ret
    81  }
    82  
    83  // decRef decreases the reference count on each stack.PacketBuffer stored in
    84  // the list.
    85  //
    86  // NOTE: runs in O(n) time.
    87  //
    88  //go:nosplit
    89  func (pl *packetBufferCircularList) decRef() {
    90  	for i := 0; i < pl.size; i++ {
    91  		pl.pbs[(pl.head+i)%len(pl.pbs)].DecRef()
    92  	}
    93  }