84 lines
2.4 KiB
Go
84 lines
2.4 KiB
Go
// Copyright 2020 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package buffer
|
|
|
|
const (
|
|
// embeddedCount is the number of buffer structures embedded in the pool. It
|
|
// is also the number for overflow allocations.
|
|
embeddedCount = 8
|
|
|
|
// defaultBufferSize is the default size for each underlying storage buffer.
|
|
//
|
|
// It is slightly less than two pages. This is done intentionally to ensure
|
|
// that the buffer object aligns with runtime internals. This two page size
|
|
// will effectively minimize internal fragmentation, but still have a large
|
|
// enough chunk to limit excessive segmentation.
|
|
defaultBufferSize = 8144
|
|
)
|
|
|
|
// pool allocates buffer.
|
|
//
|
|
// It contains an embedded buffer storage for fast path when the number of
|
|
// buffers needed is small.
|
|
//
|
|
// +stateify savable
|
|
type pool struct {
|
|
bufferSize int
|
|
avail []buffer `state:"nosave"`
|
|
embeddedStorage [embeddedCount]buffer `state:"wait"`
|
|
}
|
|
|
|
// get gets a new buffer from p.
|
|
func (p *pool) get() *buffer {
|
|
if p.avail == nil {
|
|
p.avail = p.embeddedStorage[:]
|
|
}
|
|
if len(p.avail) == 0 {
|
|
p.avail = make([]buffer, embeddedCount)
|
|
}
|
|
if p.bufferSize <= 0 {
|
|
p.bufferSize = defaultBufferSize
|
|
}
|
|
buf := &p.avail[0]
|
|
buf.init(p.bufferSize)
|
|
p.avail = p.avail[1:]
|
|
return buf
|
|
}
|
|
|
|
// put releases buf.
|
|
func (p *pool) put(buf *buffer) {
|
|
// Remove reference to the underlying storage, allowing it to be garbage
|
|
// collected.
|
|
buf.data = nil
|
|
}
|
|
|
|
// setBufferSize sets the size of underlying storage buffer for future
|
|
// allocations. It can be called at any time.
|
|
func (p *pool) setBufferSize(size int) {
|
|
p.bufferSize = size
|
|
}
|
|
|
|
// afterLoad is invoked by stateify.
|
|
func (p *pool) afterLoad() {
|
|
// S/R does not save subslice into embeddedStorage correctly. Restore
|
|
// available portion of embeddedStorage manually. Restore as nil if none used.
|
|
for i := len(p.embeddedStorage); i > 0; i-- {
|
|
if p.embeddedStorage[i-1].data != nil {
|
|
p.avail = p.embeddedStorage[i:]
|
|
break
|
|
}
|
|
}
|
|
}
|