@ -16,7 +16,6 @@ package buffer
import (
"fmt"
"log"
"reflect"
"unsafe"
@ -33,30 +32,15 @@ const OutMessageHeaderSize = int(unsafe.Sizeof(fusekernel.OutHeader{}))
//
// Must be initialized with Reset.
type OutMessage struct {
// The offset into payload to which we're currently writing.
payloadOffset int
header fusekernel . OutHeader
payload [ MaxReadSize ] byte
}
// Make sure that the header and payload are contiguous.
func init ( ) {
a := unsafe . Offsetof ( OutMessage { } . header ) + uintptr ( OutMessageHeaderSize )
b := unsafe . Offsetof ( OutMessage { } . payload )
if a != b {
log . Panicf (
"header ends at offset %d, but payload starts at offset %d" ,
a , b )
}
header fusekernel . OutHeader
Sglist [ ] [ ] byte
}
// Reset resets m so that it's ready to be used again. Afterward, the contents
// are solely a zeroed fusekernel.OutHeader struct.
func ( m * OutMessage ) Reset ( ) {
m . payloadOffset = 0
m . header = fusekernel . OutHeader { }
m . Sglist = nil
}
// OutHeader returns a pointer to the header at the start of the message.
@ -64,30 +48,12 @@ func (m *OutMessage) OutHeader() *fusekernel.OutHeader {
return & m . header
}
// Grow grows m's buffer by the given number of bytes, returning a pointer to
// the start of the new segment, which is guaranteed to be zeroed. If there is
// insufficient space, it returns nil.
// Grow adds a new buffer of <n> bytes to the message, returning a pointer to
// the start of the new segment, which is guaranteed to be zeroed.
func ( m * OutMessage ) Grow ( n int ) unsafe . Pointer {
p := m . GrowNoZero ( n )
if p != nil {
jacobsa_fuse_memclr ( p , uintptr ( n ) )
}
return p
}
// GrowNoZero is equivalent to Grow, except the new segment is not zeroed. Use
// with caution!
func ( m * OutMessage ) GrowNoZero ( n int ) unsafe . Pointer {
// Will we overflow the buffer?
o := m . payloadOffset
if len ( m . payload ) - o < n {
return nil
}
p := unsafe . Pointer ( uintptr ( unsafe . Pointer ( & m . payload ) ) + uintptr ( o ) )
m . payloadOffset = o + n
b := make ( [ ] byte , n )
m . Append ( b )
p := unsafe . Pointer ( & b [ 0 ] )
return p
}
@ -100,51 +66,62 @@ func (m *OutMessage) ShrinkTo(n int) {
n ,
m . Len ( ) ) )
}
m . payloadOffset = n - OutMessageHeaderSize
if n == OutMessageHeaderSize {
m . Sglist = nil
} else {
i := 1
n -= OutMessageHeaderSize
for len ( m . Sglist ) > i && n >= len ( m . Sglist [ i ] ) {
n -= len ( m . Sglist [ i ] )
i ++
}
if n > 0 {
m . Sglist [ i ] = m . Sglist [ i ] [ 0 : n ]
i ++
}
m . Sglist = m . Sglist [ 0 : i ]
}
}
// Append is equivalent to growing by len(src), then copying src over the new
// segment. Int panics if there is not enough room available.
func ( m * OutMessage ) Append ( src [ ] byte ) {
p := m . GrowNoZero ( len ( src ) )
if p == nil {
panic ( fmt . Sprintf ( "Can't grow %d bytes" , len ( src ) ) )
func ( m * OutMessage ) Append ( src ... [ ] byte ) {
if m . Sglist == nil {
// First element of Sglist is pre-filled with a pointer to the header
// to allow sending it with a single writev() call without copying the
// slice again
m . Sglist = append ( m . Sglist , m . OutHeaderBytes ( ) )
}
sh := ( * reflect . SliceHeader ) ( unsafe . Pointer ( & src ) )
jacobsa_fuse_memmove ( p , unsafe . Pointer ( sh . Data ) , uintptr ( sh . Len ) )
m . Sglist = append ( m . Sglist , src ... )
return
}
// AppendString is like Append, but accepts string input.
func ( m * OutMessage ) AppendString ( src string ) {
p := m . GrowNoZero ( len ( src ) )
if p == nil {
panic ( fmt . Sprintf ( "Can't grow %d bytes" , len ( src ) ) )
}
sh := ( * reflect . StringHeader ) ( unsafe . Pointer ( & src ) )
jacobsa_fuse_memmove ( p , unsafe . Pointer ( sh . Data ) , uintptr ( sh . Len ) )
m . Append ( [ ] byte ( src ) )
return
}
// Len returns the current size of the message, including the leading header.
func ( m * OutMessage ) Len ( ) int {
return OutMessageHeaderSize + m . payloadOffset
if m . Sglist == nil {
return OutMessageHeaderSize
}
// First element of Sglist is the header, so we don't need to count it here
r := 0
for _ , b := range m . Sglist {
r += len ( b )
}
return r
}
// Bytes returns a reference to the current contents of the buffer, including
// the leading header.
func ( m * OutMessage ) Bytes ( ) [ ] byte {
l := m . Len ( )
// OutHeaderBytes returns a byte slice containing the current header.
func ( m * OutMessage ) OutHeaderBytes ( ) [ ] byte {
l := OutMessageHeaderSize
sh := reflect . SliceHeader {
Data : uintptr ( unsafe . Pointer ( & m . header ) ) ,
Len : l ,
Cap : l ,
}
return * ( * [ ] byte ) ( unsafe . Pointer ( & sh ) )
}