github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/tcpip/link/sharedmem/pipe/pipe.go (about) 1 // Copyright 2018 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package pipe implements a shared memory ring buffer on which a single reader 16 // and a single writer can operate (read/write) concurrently. The ring buffer 17 // allows for data of different sizes to be written, and preserves the boundary 18 // of the written data. 19 // 20 // Example usage is as follows: 21 // 22 // wb := t.Push(20) 23 // // Write data to wb. 24 // t.Flush() 25 // 26 // rb := r.Pull() 27 // // Do something with data in rb. 28 // t.Flush() 29 package pipe 30 31 import ( 32 "math" 33 ) 34 35 const ( 36 jump uint64 = math.MaxUint32 + 1 37 offsetMask uint64 = math.MaxUint32 38 revolutionMask uint64 = ^offsetMask 39 40 sizeOfSlotHeader = 8 // sizeof(uint64) 41 slotFree uint64 = 1 << 63 42 slotSizeMask uint64 = math.MaxUint32 43 ) 44 45 // payloadToSlotSize calculates the total size of a slot based on its payload 46 // size. The total size is the header size, plus the payload size, plus padding 47 // if necessary to make the total size a multiple of sizeOfSlotHeader. 48 func payloadToSlotSize(payloadSize uint64) uint64 { 49 s := sizeOfSlotHeader + payloadSize 50 return (s + sizeOfSlotHeader - 1) &^ (sizeOfSlotHeader - 1) 51 } 52 53 // slotToPayloadSize calculates the payload size of a slot based on the total 54 // size of the slot. This is only meant to be used when creating slots that 55 // don't carry information (e.g., free slots or wrap slots). 56 func slotToPayloadSize(offset uint64) uint64 { 57 return offset - sizeOfSlotHeader 58 } 59 60 // pipe is a basic data structure used by both (transmit & receive) ends of a 61 // pipe. Indices into this pipe are split into two fields: offset, which counts 62 // the number of bytes from the beginning of the buffer, and revolution, which 63 // counts the number of times the index has wrapped around. 64 type pipe struct { 65 buffer []byte 66 } 67 68 // init initializes the pipe buffer such that its size is a multiple of the size 69 // of the slot header. 70 func (p *pipe) init(b []byte) { 71 p.buffer = b[:len(b)&^(sizeOfSlotHeader-1)] 72 } 73 74 // data returns a section of the buffer starting at the given index (which may 75 // include revolution information) and with the given size. 76 func (p *pipe) data(idx uint64, size uint64) []byte { 77 return p.buffer[(idx&offsetMask)+sizeOfSlotHeader:][:size] 78 }