mirror of https://github.com/ceph/go-ceph
cutil: add Iovec type wrapping C struct iovec arrays
This type is useful for passing disparate buffers to be read or written in a single call. Functions using this type exist in cephfs and rbd. Currently this is needed for cephfs calls. Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
parent
4706453428
commit
ebea82dda5
|
@ -0,0 +1,78 @@
|
||||||
|
package cutil
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var iovecSize uintptr
|
||||||
|
|
||||||
|
// StructIovecPtr is an unsafe pointer wrapping C's `*struct iovec`.
|
||||||
|
type StructIovecPtr unsafe.Pointer
|
||||||
|
|
||||||
|
// Iovec helps manage struct iovec arrays needed by some C functions.
|
||||||
|
type Iovec struct {
|
||||||
|
// cvec represents an array of struct iovec C memory
|
||||||
|
cvec unsafe.Pointer
|
||||||
|
// length of the array (in elements)
|
||||||
|
length int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIovec creates an Iovec, and underlying C memory, of the specified size.
|
||||||
|
func NewIovec(l int) *Iovec {
|
||||||
|
r := &Iovec{
|
||||||
|
cvec: C.malloc(C.size_t(l) * C.size_t(iovecSize)),
|
||||||
|
length: l,
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByteSlicesToIovec takes a slice of byte slices and returns a new iovec that
|
||||||
|
// maps the slice data to struct iovec entries.
|
||||||
|
func ByteSlicesToIovec(data [][]byte) *Iovec {
|
||||||
|
iov := NewIovec(len(data))
|
||||||
|
for i := range data {
|
||||||
|
iov.Set(i, data[i])
|
||||||
|
}
|
||||||
|
return iov
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer returns a StructIovecPtr that represents the C memory of the
|
||||||
|
// underlying array.
|
||||||
|
func (v *Iovec) Pointer() StructIovecPtr {
|
||||||
|
return StructIovecPtr(unsafe.Pointer(v.cvec))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of entries in the Iovec.
|
||||||
|
func (v *Iovec) Len() int {
|
||||||
|
return v.length
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the C memory in the Iovec.
|
||||||
|
func (v *Iovec) Free() {
|
||||||
|
if v.cvec != nil {
|
||||||
|
C.free(v.cvec)
|
||||||
|
v.cvec = nil
|
||||||
|
v.length = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set will map the memory of the given byte slice to the iovec at the
|
||||||
|
// specified position.
|
||||||
|
func (v *Iovec) Set(i int, buf []byte) {
|
||||||
|
offset := uintptr(i) * iovecSize
|
||||||
|
iov := (*C.struct_iovec)(unsafe.Pointer(
|
||||||
|
uintptr(unsafe.Pointer(v.cvec)) + offset))
|
||||||
|
iov.iov_base = unsafe.Pointer(&buf[0])
|
||||||
|
iov.iov_len = C.size_t(len(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var iovec C.struct_iovec
|
||||||
|
iovecSize = unsafe.Sizeof(iovec)
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package cutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIovec(t *testing.T) {
|
||||||
|
t.Run("newAndFree", func(t *testing.T) {
|
||||||
|
iov := NewIovec(3)
|
||||||
|
iov.Free()
|
||||||
|
})
|
||||||
|
t.Run("setBufs", func(t *testing.T) {
|
||||||
|
b1 := []byte("foo")
|
||||||
|
b2 := []byte("barbar")
|
||||||
|
b3 := []byte("bazbazbaz")
|
||||||
|
iov := NewIovec(3)
|
||||||
|
iov.Set(0, b1)
|
||||||
|
iov.Set(1, b2)
|
||||||
|
iov.Set(2, b3)
|
||||||
|
iov.Free()
|
||||||
|
// free also unsets internal values
|
||||||
|
assert.Equal(t, unsafe.Pointer(nil), iov.cvec)
|
||||||
|
assert.Equal(t, 0, iov.length)
|
||||||
|
})
|
||||||
|
t.Run("testGetters", func(t *testing.T) {
|
||||||
|
b1 := []byte("foo")
|
||||||
|
b2 := []byte("barbar")
|
||||||
|
b3 := []byte("bazbazbaz")
|
||||||
|
b4 := []byte("zonk")
|
||||||
|
iov := NewIovec(4)
|
||||||
|
defer iov.Free()
|
||||||
|
iov.Set(0, b1)
|
||||||
|
iov.Set(1, b2)
|
||||||
|
iov.Set(2, b3)
|
||||||
|
iov.Set(3, b4)
|
||||||
|
|
||||||
|
assert.NotNil(t, iov.Pointer())
|
||||||
|
assert.Equal(t, 4, iov.Len())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestByteSlicesToIovec(t *testing.T) {
|
||||||
|
d := [][]byte{
|
||||||
|
[]byte("ramekin"),
|
||||||
|
[]byte("shuffleboard"),
|
||||||
|
[]byte("tranche"),
|
||||||
|
[]byte("phycobilisomes"),
|
||||||
|
}
|
||||||
|
iov := ByteSlicesToIovec(d)
|
||||||
|
defer iov.Free()
|
||||||
|
|
||||||
|
assert.NotNil(t, iov.Pointer())
|
||||||
|
assert.Equal(t, 4, iov.Len())
|
||||||
|
}
|
Loading…
Reference in New Issue