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 }