blob: 1173a60da91d5db52dfd5eaddcef57532dbf8621 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
// Copyright 2016 The Netstack Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package pipe implements a shared memory ring buffer on which a single reader
// and a single writer can operate (read/write) concurrently. The ring buffer
// allows for data of different sizes to be written, and preserves the boundary
// of the written data.
//
// Example usage is as follows:
//
// wb := t.Push(20)
// // Write data to wb.
// t.Flush()
//
// rb := r.Pull()
// // Do something with data in rb.
// t.Flush()
package pipe
import (
"math"
)
const (
jump uint64 = math.MaxUint32 + 1
offsetMask uint64 = math.MaxUint32
revolutionMask uint64 = ^offsetMask
sizeOfSlotHeader = 8 // sizeof(uint64)
slotFree uint64 = 1 << 63
slotSizeMask uint64 = math.MaxUint32
)
// payloadToSlotSize calculates the total size of a slot based on its payload
// size. The total size is the header size, plus the payload size, plus padding
// if necessary to make the total size a multiple of sizeOfSlotHeader.
func payloadToSlotSize(payloadSize uint64) uint64 {
s := sizeOfSlotHeader + payloadSize
return (s + sizeOfSlotHeader - 1) &^ (sizeOfSlotHeader - 1)
}
// slotToPayloadSize calculates the payload size of a slot based on the total
// size of the slot. This is only meant to be used when creating slots that
// don't carry information (e.g., free slots or wrap slots).
func slotToPayloadSize(offset uint64) uint64 {
return offset - sizeOfSlotHeader
}
// pipe is a basic data structure used by both (transmit & receive) ends of a
// pipe. Indices into this pipe are split into two fields: offset, which counts
// the number of bytes from the beginning of the buffer, and revolution, which
// counts the number of times the index has wrapped around.
type pipe struct {
buffer []byte
}
// init initializes the pipe buffer such that its size is a multiple of the size
// of the slot header.
func (p *pipe) init(b []byte) {
p.buffer = b[:len(b)&^(sizeOfSlotHeader-1)]
}
// data returns a section of the buffer starting at the given index (which may
// include revolution information) and with the given size.
func (p *pipe) data(idx uint64, size uint64) []byte {
return p.buffer[(idx&offsetMask)+sizeOfSlotHeader:][:size]
}
|