inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/buffer/pool.go (about) 1 // Copyright 2020 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 buffer 16 17 const ( 18 // embeddedCount is the number of buffer structures embedded in the pool. It 19 // is also the number for overflow allocations. 20 embeddedCount = 8 21 22 // defaultBufferSize is the default size for each underlying storage buffer. 23 // 24 // It is slightly less than two pages. This is done intentionally to ensure 25 // that the buffer object aligns with runtime internals. This two page size 26 // will effectively minimize internal fragmentation, but still have a large 27 // enough chunk to limit excessive segmentation. 28 defaultBufferSize = 8144 29 ) 30 31 // pool allocates buffer. 32 // 33 // It contains an embedded buffer storage for fast path when the number of 34 // buffers needed is small. 35 // 36 // +stateify savable 37 type pool struct { 38 bufferSize int 39 avail []buffer `state:"nosave"` 40 embeddedStorage [embeddedCount]buffer `state:"wait"` 41 } 42 43 // get gets a new buffer from p. 44 func (p *pool) get() *buffer { 45 buf := p.getNoInit() 46 buf.init(p.bufferSize) 47 return buf 48 } 49 50 // get gets a new buffer from p without initializing it. 51 func (p *pool) getNoInit() *buffer { 52 if p.avail == nil { 53 p.avail = p.embeddedStorage[:] 54 } 55 if len(p.avail) == 0 { 56 p.avail = make([]buffer, embeddedCount) 57 } 58 if p.bufferSize <= 0 { 59 p.bufferSize = defaultBufferSize 60 } 61 buf := &p.avail[0] 62 p.avail = p.avail[1:] 63 return buf 64 } 65 66 // put releases buf. 67 func (p *pool) put(buf *buffer) { 68 // Remove reference to the underlying storage, allowing it to be garbage 69 // collected. 70 buf.data = nil 71 buf.Reset() 72 } 73 74 // setBufferSize sets the size of underlying storage buffer for future 75 // allocations. It can be called at any time. 76 func (p *pool) setBufferSize(size int) { 77 p.bufferSize = size 78 } 79 80 // afterLoad is invoked by stateify. 81 func (p *pool) afterLoad() { 82 // S/R does not save subslice into embeddedStorage correctly. Restore 83 // available portion of embeddedStorage manually. Restore as nil if none used. 84 for i := len(p.embeddedStorage); i > 0; i-- { 85 if p.embeddedStorage[i-1].data != nil { 86 p.avail = p.embeddedStorage[i:] 87 break 88 } 89 } 90 }