github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/internal/buffer/out_message.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 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 import ( 18 "fmt" 19 "log" 20 "reflect" 21 "unsafe" 22 23 "github.com/scaleoutsean/fusego/internal/fusekernel" 24 ) 25 26 // OutMessageHeaderSize is the size of the leading header in every 27 // properly-constructed OutMessage. Reset brings the message back to this size. 28 const OutMessageHeaderSize = int(unsafe.Sizeof(fusekernel.OutHeader{})) 29 30 // OutMessage provides a mechanism for constructing a single contiguous fuse 31 // message from multiple segments, where the first segment is always a 32 // fusekernel.OutHeader message. 33 // 34 // Must be initialized with Reset. 35 type OutMessage struct { 36 // The offset into payload to which we're currently writing. 37 payloadOffset int 38 39 header fusekernel.OutHeader 40 payload [MaxReadSize]byte 41 } 42 43 // Make sure that the header and payload are contiguous. 44 func init() { 45 a := unsafe.Offsetof(OutMessage{}.header) + uintptr(OutMessageHeaderSize) 46 b := unsafe.Offsetof(OutMessage{}.payload) 47 48 if a != b { 49 log.Panicf( 50 "header ends at offset %d, but payload starts at offset %d", 51 a, b) 52 } 53 } 54 55 // Reset resets m so that it's ready to be used again. Afterward, the contents 56 // are solely a zeroed fusekernel.OutHeader struct. 57 func (m *OutMessage) Reset() { 58 // Ideally we'd like to write: 59 // 60 // m.payloadOffset = 0 61 // m.header = fusekernel.OutHeader{} 62 // 63 // But Go 1.8 beta 2 generates bad code for this 64 // (https://golang.org/issue/18370). Encourage it to generate the same code 65 // as Go 1.7.4 did. 66 if unsafe.Offsetof(m.payload) != 24 { 67 panic("unexpected OutMessage layout") 68 } 69 70 a := (*[3]uint64)(unsafe.Pointer(m)) 71 a[0] = 0 72 a[1] = 0 73 a[2] = 0 74 } 75 76 // OutHeader returns a pointer to the header at the start of the message. 77 func (m *OutMessage) OutHeader() *fusekernel.OutHeader { 78 return &m.header 79 } 80 81 // Grow grows m's buffer by the given number of bytes, returning a pointer to 82 // the start of the new segment, which is guaranteed to be zeroed. If there is 83 // insufficient space, it returns nil. 84 func (m *OutMessage) Grow(n int) unsafe.Pointer { 85 p := m.GrowNoZero(n) 86 if p != nil { 87 jacobsa_fuse_memclr(p, uintptr(n)) 88 } 89 90 return p 91 } 92 93 // GrowNoZero is equivalent to Grow, except the new segment is not zeroed. Use 94 // with caution! 95 func (m *OutMessage) GrowNoZero(n int) unsafe.Pointer { 96 // Will we overflow the buffer? 97 o := m.payloadOffset 98 if len(m.payload)-o < n { 99 return nil 100 } 101 102 p := unsafe.Pointer(uintptr(unsafe.Pointer(&m.payload)) + uintptr(o)) 103 m.payloadOffset = o + n 104 105 return p 106 } 107 108 // ShrinkTo shrinks m to the given size. It panics if the size is greater than 109 // Len() or less than OutMessageHeaderSize. 110 func (m *OutMessage) ShrinkTo(n int) { 111 if n < OutMessageHeaderSize || n > m.Len() { 112 panic(fmt.Sprintf( 113 "ShrinkTo(%d) out of range (current Len: %d)", 114 n, 115 m.Len())) 116 } 117 118 m.payloadOffset = n - OutMessageHeaderSize 119 } 120 121 // Append is equivalent to growing by len(src), then copying src over the new 122 // segment. Int panics if there is not enough room available. 123 func (m *OutMessage) Append(src []byte) { 124 p := m.GrowNoZero(len(src)) 125 if p == nil { 126 panic(fmt.Sprintf("Can't grow %d bytes", len(src))) 127 } 128 129 sh := (*reflect.SliceHeader)(unsafe.Pointer(&src)) 130 jacobsa_fuse_memmove(p, unsafe.Pointer(sh.Data), uintptr(sh.Len)) 131 132 return 133 } 134 135 // AppendString is like Append, but accepts string input. 136 func (m *OutMessage) AppendString(src string) { 137 p := m.GrowNoZero(len(src)) 138 if p == nil { 139 panic(fmt.Sprintf("Can't grow %d bytes", len(src))) 140 } 141 142 sh := (*reflect.StringHeader)(unsafe.Pointer(&src)) 143 jacobsa_fuse_memmove(p, unsafe.Pointer(sh.Data), uintptr(sh.Len)) 144 145 return 146 } 147 148 // Len returns the current size of the message, including the leading header. 149 func (m *OutMessage) Len() int { 150 return OutMessageHeaderSize + m.payloadOffset 151 } 152 153 // Bytes returns a reference to the current contents of the buffer, including 154 // the leading header. 155 func (m *OutMessage) Bytes() []byte { 156 l := m.Len() 157 sh := reflect.SliceHeader{ 158 Data: uintptr(unsafe.Pointer(&m.header)), 159 Len: l, 160 Cap: l, 161 } 162 163 return *(*[]byte)(unsafe.Pointer(&sh)) 164 }