mirror of
https://github.com/ii64/gouring.git
synced 2025-04-01 03:41:44 +02:00
feat(): initail files
Signed-off-by: MastahSenpai <26342994+ii64@users.noreply.github.com>
This commit is contained in:
commit
85e03649ba
11 changed files with 793 additions and 0 deletions
7
README.md
Normal file
7
README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# gouring
|
||||
|
||||
Low-lavel io uring library
|
||||
|
||||
```
|
||||
go get github.com/ii64/gouring
|
||||
```
|
198
const_value.go
Normal file
198
const_value.go
Normal file
|
@ -0,0 +1,198 @@
|
|||
package gouring
|
||||
|
||||
type UringSQEFlag = uint8
|
||||
|
||||
const (
|
||||
IOSQE_FIXED_FILE_BIT UringSQEFlag = iota
|
||||
IOSQE_IO_DRAIN_BIT
|
||||
IOSQE_IO_LINK_BIT
|
||||
IOSQE_TO_HARDLINK_BIT
|
||||
IOSQE_ASYNC_BIT
|
||||
IOSQE_BUFFER_SELECT_BIT
|
||||
IOSQE_CQE_SKIP_BIT
|
||||
)
|
||||
|
||||
//
|
||||
|
||||
// io_uring_setup() flags
|
||||
type UringSetupFlag = uint32
|
||||
|
||||
const (
|
||||
IORING_SETUP_IOPOLL UringSetupFlag = 1 << iota
|
||||
IORING_SETUP_SQPOLL
|
||||
IORING_SETUP_SQ_AFF
|
||||
IORING_SETUP_SQSIZE
|
||||
IORING_SETUP_CLAMP
|
||||
IORING_SETUP_ATTACH_WQ
|
||||
IORING_SETUP_R_DISABLED
|
||||
)
|
||||
|
||||
//
|
||||
|
||||
// uring op code
|
||||
type UringOpcode = uint8
|
||||
|
||||
const (
|
||||
IORING_OP_NOP UringOpcode = iota
|
||||
IORING_OP_READV
|
||||
IORING_OP_WRITEV
|
||||
IORING_OP_FSYNC
|
||||
IORING_OP_READ_FIXED
|
||||
IORING_OP_WRITE_FIXED
|
||||
IORING_OP_POLL_ADD
|
||||
IORING_OP_POLL_REMOVE
|
||||
IORING_OP_SYNC_FILE_RANGE
|
||||
IORING_OP_SENDMSG
|
||||
IORING_OP_RECVMSG
|
||||
IORING_OP_TIMEOUT
|
||||
IORING_OP_TIMEOUT_REMOVE
|
||||
IORING_OP_ACCEPT
|
||||
IORING_OP_ASYNC_CANCEL
|
||||
IORING_OP_LINK_TIMEOUT
|
||||
IORING_OP_CONNECT
|
||||
IORING_OP_FALLOCATE
|
||||
IORING_OP_OPENAT
|
||||
IORING_OP_CLOSE
|
||||
IORING_OP_FILES_UPDATE
|
||||
IORING_OP_STATX
|
||||
IORING_OP_READ
|
||||
IORING_OP_WRITE
|
||||
IORING_OP_FADVISE
|
||||
IORING_OP_MADVISE
|
||||
IORING_OP_SEND
|
||||
IORING_OP_RECV
|
||||
IORING_OP_OPENAT2
|
||||
IORING_OP_EPOLL_CTL
|
||||
IORING_OP_SPLICE
|
||||
IORING_OP_PROVIDE_BUFFERS
|
||||
IORING_OP_REMOVE_BUFFERS
|
||||
IORING_OP_TEE
|
||||
IORING_OP_SHUTDOWN
|
||||
IORING_OP_RENAMEAT
|
||||
IORING_OP_UNLINKAT
|
||||
IORING_OP_MKDIRAT
|
||||
IORING_OP_SYMLINKAT
|
||||
IORING_OP_LINKAT
|
||||
|
||||
/* this goes last, obviously */
|
||||
IORING_OP_LAST
|
||||
)
|
||||
|
||||
// sqe->fsync_flags
|
||||
const IORING_FSYNC_DATASYNC uint32 = 1 << 0
|
||||
|
||||
// sqe->timeout_flags
|
||||
const IORING_TIMEOUT_ABS uint32 = 1 << 0
|
||||
|
||||
// sqe->splice_flags
|
||||
// extends splice(2) flags
|
||||
const SPLICE_F_FD_IN_FIXED uint32 = 1 << 31
|
||||
|
||||
//
|
||||
|
||||
// cqe->flags
|
||||
type UringCQEFlag = uint32
|
||||
|
||||
const IORING_CQE_F_BUFFER UringCQEFlag = 1 << 8
|
||||
const IORING_CQE_BUFFER_SHIFT UringCQEFlag = 16
|
||||
|
||||
//
|
||||
|
||||
// Magic offsets for the application to mmap the data it needs
|
||||
type UringOffset = int64
|
||||
|
||||
const (
|
||||
IORING_OFF_SQ_RING UringOffset = 0
|
||||
IORING_OFF_CQ_RING UringOffset = 0x8000000
|
||||
IORING_OFF_SQES UringOffset = 0x10000000
|
||||
)
|
||||
|
||||
//
|
||||
|
||||
// sq_ring->flags
|
||||
type UringSQ = uint32
|
||||
|
||||
const (
|
||||
IORING_SQ_NEED_WAKEUP UringSQ = 1 << iota // needs io_uring_enter wakeup
|
||||
IORING_SQ_CQ_OVERFLOW // CQ Ring is overflow
|
||||
)
|
||||
|
||||
//
|
||||
|
||||
// cq_ring->flags
|
||||
type UringCQ = uint32
|
||||
|
||||
const IORING_CQ_EVENTFD_DISABLED = 1 << 0
|
||||
|
||||
//
|
||||
|
||||
// io_uring_enter(2) flag
|
||||
type UringEnterFlag = uint
|
||||
|
||||
const (
|
||||
IORING_ENTER_GETEVENTS UringEnterFlag = 1 << iota
|
||||
IORING_ENTER_SQ_WAKEUP
|
||||
IORING_ENTER_SQ_WAIT
|
||||
)
|
||||
|
||||
//
|
||||
|
||||
// io_uring_params->features flags
|
||||
type UringParamFeatureFlag = uint32
|
||||
|
||||
const (
|
||||
IORING_FEAT_SINGLE_MMAP UringParamFeatureFlag = 1 << iota
|
||||
IORING_FEAT_NODROP
|
||||
IORING_FEAT_SUBMIT_STABLE
|
||||
IORING_FEAT_RW_CUR_POS
|
||||
IORING_FEAT_CUR_PERSONALITY
|
||||
IORING_FEAT_FAST_POLL
|
||||
IORING_FEAT_POLL_32BITS
|
||||
)
|
||||
|
||||
//
|
||||
|
||||
type UringRegisterOpcode = uint32
|
||||
|
||||
const (
|
||||
IORING_REGISTER_BUFFERS UringRegisterOpcode = iota
|
||||
IORING_UREGISTER_BUFFERS
|
||||
|
||||
IORING_REGISTER_FILES
|
||||
IORING_UNREGISTER_FILES
|
||||
|
||||
IORING_REGISTER_EVENTFD
|
||||
IORING_UNREGISTER_EVENTFD
|
||||
|
||||
IORING_REGISTER_FILES_UPDATE
|
||||
IORING_REGISTER_EVENTFD_ASYNC
|
||||
IORING_REGISTER_PROBE
|
||||
|
||||
IORING_REGISTER_PERSONALITY
|
||||
IORING_UNREGISTER_PERSONALITY
|
||||
|
||||
IORING_REGISTER_RESTRICTIONS
|
||||
IORING_REGISTER_ENABLE_RINGS
|
||||
|
||||
//
|
||||
/* this goes last */
|
||||
IORING_REGISTER_LAST
|
||||
)
|
||||
|
||||
//
|
||||
|
||||
const IO_URING_OP_SUPPORTED = 1 << 0
|
||||
|
||||
//
|
||||
|
||||
// io_uring_restriction->opcode values
|
||||
type UringRestrictionOpcode = uint32
|
||||
|
||||
const (
|
||||
IORING_RESTRICTION_REGISTER_OP UringRestrictionOpcode = iota
|
||||
IORING_RESTRICTION_SQE_OP
|
||||
IORING_RESTRICTION_SQE_FLAGS_ALLOWED
|
||||
IORINGN_RESTRICTION_SQE_FLAGS_REQUIRED
|
||||
|
||||
IORING_RESTRICTION_LAST
|
||||
)
|
54
core.go
Normal file
54
core.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package gouring
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func New(entries uint, params *IOUringParams) (*Ring, error) {
|
||||
r := &Ring{}
|
||||
if params != nil {
|
||||
r.params = *params
|
||||
}
|
||||
var err error
|
||||
if r.fd, err = setup(r, entries, &r.params); err != nil {
|
||||
err = errors.Wrap(err, "setup")
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *Ring) Close() (err error) {
|
||||
if err = unsetup(r); err != nil {
|
||||
err = errors.Wrap(err, "close")
|
||||
return
|
||||
}
|
||||
// tbd..
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Ring) Enter(toSubmit, minComplete uint, flags UringEnterFlag, sig *Sigset_t) (ret int, err error) {
|
||||
ret, err = enter(r, toSubmit, minComplete, flags, sig)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "enter")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func (r *Ring) Params() *IOUringParams {
|
||||
return &r.params
|
||||
}
|
||||
|
||||
func (r *Ring) Fd() int {
|
||||
return r.fd
|
||||
}
|
||||
|
||||
func (r *Ring) SQ() *SQRing {
|
||||
return &r.sq
|
||||
}
|
||||
|
||||
func (r *Ring) CQ() *CQRing {
|
||||
return &r.cq
|
||||
}
|
61
core_test.go
Normal file
61
core_test.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package gouring
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCore(t *testing.T) {
|
||||
ring, err := New(256, nil)
|
||||
assert.NoError(t, err, "create ring")
|
||||
defer func() {
|
||||
err := ring.Close()
|
||||
assert.NoError(t, err, "close ring")
|
||||
}()
|
||||
|
||||
mkdata := func(i int) []byte {
|
||||
return []byte("print me to stdout please" + strings.Repeat("!", i) + "\n")
|
||||
}
|
||||
|
||||
sq := ring.SQ()
|
||||
n := 5
|
||||
for i := 0; i < n; i++ {
|
||||
sqTail := *sq.Tail()
|
||||
sqIdx := sqTail & *sq.RingMask()
|
||||
|
||||
sqe := sq.Get(sqIdx)
|
||||
|
||||
m := mkdata(i)
|
||||
|
||||
sqe.Opcode = IORING_OP_WRITE
|
||||
sqe.Fd = int32(syscall.Stdout)
|
||||
sqe.UserData = uint64(i)
|
||||
*sqe.Addr() = (uint64)(uintptr(unsafe.Pointer(&m[0])))
|
||||
|
||||
*sq.Array().Get(sqIdx) = *sq.Head() & *sq.RingMask()
|
||||
*sq.Tail()++
|
||||
|
||||
t.Logf("Queued %d: %+#v", i, sqe)
|
||||
}
|
||||
|
||||
done, err := ring.Enter(uint(n), uint(n), IORING_ENTER_GETEVENTS, nil)
|
||||
assert.NoError(t, err, "ring enter")
|
||||
t.Logf("done %d", done)
|
||||
|
||||
// get cq
|
||||
cq := ring.CQ()
|
||||
for i := 0; i < int(*cq.Tail()); i++ {
|
||||
cqHead := *cq.Head()
|
||||
cqIdx := cqHead & *cq.RingMask()
|
||||
|
||||
cqe := cq.Get(cqIdx)
|
||||
|
||||
*cq.Head()++
|
||||
t.Logf("CQE %+#v", cqe)
|
||||
}
|
||||
|
||||
}
|
14
go.mod
Normal file
14
go.mod
Normal file
|
@ -0,0 +1,14 @@
|
|||
module github.com/ii64/gouring
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
)
|
13
go.sum
Normal file
13
go.sum
Normal file
|
@ -0,0 +1,13 @@
|
|||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
134
mem_util.go
Normal file
134
mem_util.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
package gouring
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
_uint32 uint32 = 0
|
||||
_sz_uint32 = unsafe.Sizeof(_uint32)
|
||||
)
|
||||
|
||||
//go:linkname mmap syscall.mmap
|
||||
func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
|
||||
|
||||
//go:linkname munmap syscall.munmap
|
||||
func munmap(addr uintptr, length uintptr) (err error)
|
||||
|
||||
func setup(r *Ring, entries uint, parmas *IOUringParams) (ringFd int, err error) {
|
||||
var sq = &r.sq
|
||||
var cq = &r.cq
|
||||
var p = &r.params
|
||||
|
||||
if ringFd, err = io_uring_setup(entries, p); err != nil {
|
||||
err = errors.Wrap(err, "io_uring_setup")
|
||||
return
|
||||
}
|
||||
if ringFd < 0 {
|
||||
err = syscall.EAGAIN
|
||||
return
|
||||
}
|
||||
|
||||
featSingleMap := p.Features&IORING_FEAT_SINGLE_MMAP > 0
|
||||
|
||||
r.sringSz = p.SQOff.Array + p.SQEntries*uint32(_sz_uint32)
|
||||
r.cringSz = p.CQOff.CQEs + p.CQEntries*uint32(_sz_cqe)
|
||||
if featSingleMap {
|
||||
if r.cringSz > r.sringSz {
|
||||
r.sringSz = r.cringSz
|
||||
}
|
||||
}
|
||||
|
||||
// allocate ring mem
|
||||
var sqRingPtr uintptr
|
||||
var cqRingPtr uintptr
|
||||
sqRingPtr, err = mmap(0, uintptr(r.sringSz),
|
||||
syscall.PROT_READ|syscall.PROT_WRITE,
|
||||
syscall.MAP_SHARED|syscall.MAP_POPULATE,
|
||||
ringFd, IORING_OFF_SQ_RING)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "mmap sqring")
|
||||
return
|
||||
}
|
||||
if featSingleMap {
|
||||
cqRingPtr = sqRingPtr
|
||||
} else {
|
||||
cqRingPtr, err = mmap(0, uintptr(r.cringSz),
|
||||
syscall.PROT_READ|syscall.PROT_WRITE,
|
||||
syscall.MAP_SHARED|syscall.MAP_POPULATE,
|
||||
ringFd, IORING_OFF_CQ_RING)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "mmap cqring")
|
||||
return
|
||||
}
|
||||
}
|
||||
r.sqRingPtr = sqRingPtr
|
||||
r.cqRingPtr = cqRingPtr
|
||||
|
||||
//
|
||||
|
||||
// address Go's ring with base+offset allocated
|
||||
sq.head = sqRingPtr + uintptr(p.SQOff.Head)
|
||||
sq.tail = sqRingPtr + uintptr(p.SQOff.Tail)
|
||||
sq.ringMask = sqRingPtr + uintptr(p.SQOff.RingMask)
|
||||
sq.ringEntries = sqRingPtr + uintptr(p.SQOff.RingEntries)
|
||||
sq.flags = sqRingPtr + uintptr(p.SQOff.Flags)
|
||||
sq.array = uint32Array(sqRingPtr + uintptr(p.SQOff.Array))
|
||||
r.sqesPtr, err = mmap(0, uintptr(p.SQEntries),
|
||||
syscall.PROT_READ|syscall.PROT_WRITE,
|
||||
syscall.MAP_SHARED|syscall.MAP_POPULATE,
|
||||
ringFd, IORING_OFF_SQES)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "mmap sqes")
|
||||
return
|
||||
}
|
||||
sq.sqes = sqeArray(r.sqesPtr)
|
||||
sq.sqesSz = uintptr(p.SQEntries) // cache
|
||||
|
||||
//
|
||||
|
||||
cq.head = cqRingPtr + uintptr(p.CQOff.Head)
|
||||
cq.tail = cqRingPtr + uintptr(p.CQOff.Tail)
|
||||
cq.ringMask = cqRingPtr + uintptr(p.CQOff.RingMask)
|
||||
cq.ringEntries = cqRingPtr + uintptr(p.CQOff.RingEntries)
|
||||
cq.cqes = cqeArray(cqRingPtr + uintptr(p.CQOff.CQEs))
|
||||
cq.cqesSz = uintptr(p.CQEntries) // cache
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func unsetup(r *Ring) (err error) {
|
||||
if r.sqesPtr != 0 {
|
||||
if err = munmap(r.sqesPtr, uintptr(r.params.SQEntries)); err != nil {
|
||||
err = errors.Wrap(err, "munmap sqes")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
featSingleMap := r.params.Features&IORING_FEAT_SINGLE_MMAP > 0
|
||||
if err = munmap(r.sqRingPtr, uintptr(r.sringSz)); err != nil {
|
||||
err = errors.Wrap(err, "munmap sq")
|
||||
}
|
||||
if !featSingleMap || r.sqRingPtr != r.cqRingPtr { // not a single map
|
||||
if err = munmap(r.cqRingPtr, uintptr(r.cringSz)); err != nil {
|
||||
err = errors.Wrap(err, "munmap cq")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func register(r *Ring) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func enter(r *Ring, toSubmit, minComplete uint, flags UringEnterFlag, sig *Sigset_t) (ret int, err error) {
|
||||
if ret, err = io_uring_enter(r.fd, toSubmit, minComplete, flags, sig); err != nil {
|
||||
err = errors.Wrap(err, "io_uring_enter")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
127
ring.go
Normal file
127
ring.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
package gouring
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type Ring struct {
|
||||
fd int
|
||||
params IOUringParams
|
||||
sq SQRing
|
||||
cq CQRing
|
||||
|
||||
// cached ringn value
|
||||
sqRingPtr, cqRingPtr, sqesPtr uintptr
|
||||
sringSz, cringSz uint32
|
||||
}
|
||||
|
||||
//
|
||||
//-- SQ
|
||||
|
||||
type SQRing struct {
|
||||
head uintptr
|
||||
tail uintptr
|
||||
ringMask uintptr
|
||||
ringEntries uintptr
|
||||
flags uintptr
|
||||
array uint32Array
|
||||
sqes sqeArray
|
||||
|
||||
// cache
|
||||
sqesSz uintptr
|
||||
}
|
||||
|
||||
func (sq SQRing) Get(idx uint32) *SQEvent {
|
||||
if uintptr(idx) >= sq.sqesSz {
|
||||
return nil
|
||||
}
|
||||
return sq.sqes.Get(uintptr(idx))
|
||||
}
|
||||
func (sq SQRing) Head() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(sq.head))
|
||||
}
|
||||
func (sq SQRing) Tail() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(sq.tail))
|
||||
}
|
||||
func (sq SQRing) RingMask() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(sq.ringMask))
|
||||
}
|
||||
func (sq SQRing) RingEntries() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(sq.ringEntries))
|
||||
}
|
||||
func (sq SQRing) Flags() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(sq.flags))
|
||||
}
|
||||
func (sq SQRing) Array() uint32Array {
|
||||
return sq.array
|
||||
}
|
||||
func (sq SQRing) Event() sqeArray {
|
||||
return sq.sqes
|
||||
}
|
||||
|
||||
//
|
||||
type uint32Array uintptr
|
||||
|
||||
func (a uint32Array) Get(idx uint32) *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(uintptr(a) + uintptr(idx)*_sz_uint32))
|
||||
}
|
||||
|
||||
func (a uint32Array) Set(idx uint32, v uint32) {
|
||||
*a.Get(idx) = v
|
||||
}
|
||||
|
||||
type sqeArray uintptr
|
||||
|
||||
func (sa sqeArray) Get(idx uintptr) *SQEvent {
|
||||
return (*SQEvent)(unsafe.Pointer(uintptr(sa) + idx*_sz_sqe))
|
||||
}
|
||||
|
||||
func (sa sqeArray) Set(idx uintptr, v SQEvent) {
|
||||
*sa.Get(idx) = v
|
||||
}
|
||||
|
||||
//
|
||||
//-- CQ
|
||||
|
||||
type CQRing struct {
|
||||
head uintptr
|
||||
tail uintptr
|
||||
ringMask uintptr
|
||||
ringEntries uintptr
|
||||
cqes cqeArray
|
||||
|
||||
// cache
|
||||
cqesSz uintptr
|
||||
}
|
||||
|
||||
func (cq CQRing) Get(idx uint32) *CQEvent {
|
||||
if uintptr(idx) >= cq.cqesSz { // avoid lookup overflow
|
||||
return nil
|
||||
}
|
||||
return cq.cqes.Get(uintptr(idx))
|
||||
}
|
||||
func (cq CQRing) Head() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(cq.head))
|
||||
}
|
||||
func (cq CQRing) Tail() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(cq.tail))
|
||||
}
|
||||
func (cq CQRing) RingMask() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(cq.ringMask))
|
||||
}
|
||||
func (cq CQRing) RingEntries() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(cq.ringEntries))
|
||||
}
|
||||
func (cq CQRing) Event() cqeArray {
|
||||
return cq.cqes
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
type cqeArray uintptr
|
||||
|
||||
func (ca cqeArray) Get(idx uintptr) *CQEvent {
|
||||
return (*CQEvent)(unsafe.Pointer(uintptr(ca) + idx*_sz_cqe))
|
||||
}
|
||||
|
||||
func (ca cqeArray) Set(idx uintptr, v CQEvent) {
|
||||
*ca.Get(idx) = v
|
||||
}
|
79
ring_event.go
Normal file
79
ring_event.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package gouring
|
||||
|
||||
import "unsafe"
|
||||
|
||||
var (
|
||||
_sqe = SQEvent{}
|
||||
_sqe_mm = make([]byte, _sz_sqe)
|
||||
_sz_sqe = unsafe.Sizeof(_sqe)
|
||||
_cqe = CQEvent{}
|
||||
_cqe_mm = make([]byte, _sz_cqe)
|
||||
_sz_cqe = unsafe.Sizeof(_cqe)
|
||||
)
|
||||
|
||||
type SQEvent struct {
|
||||
Opcode UringOpcode
|
||||
Flags UringSQEFlag
|
||||
Ioprio uint16
|
||||
Fd int32
|
||||
|
||||
off__addr2 uint64 // union { off, addr2 }
|
||||
addr__splice_off_in uint64 // union { addr, splice_off_in }
|
||||
|
||||
Len uint32
|
||||
|
||||
opcode__flags_events uint32 // union of events and flags for opcode
|
||||
|
||||
UserData uint64
|
||||
|
||||
buf__index_group uint16 // union {buf_index, buf_group}
|
||||
|
||||
Personality uint16
|
||||
|
||||
splice_fd_in__file_index int32 // union { __s32 splice_fd_in, __u32 file_index }
|
||||
|
||||
pad2 [2]uint64
|
||||
}
|
||||
|
||||
func (sqe *SQEvent) Offset() *uint64 {
|
||||
return &sqe.off__addr2
|
||||
}
|
||||
func (sqe *SQEvent) Addr2() *uint64 {
|
||||
return &sqe.off__addr2
|
||||
}
|
||||
|
||||
func (sqe *SQEvent) Addr() *uint64 {
|
||||
return &sqe.addr__splice_off_in
|
||||
}
|
||||
func (sqe *SQEvent) SpliceOffIn() *uint64 {
|
||||
return &sqe.addr__splice_off_in
|
||||
}
|
||||
|
||||
func (sqe *SQEvent) OpcodeFlags() *uint32 {
|
||||
return &sqe.opcode__flags_events
|
||||
}
|
||||
func (sqe *SQEvent) OpodeEvents() *uint32 {
|
||||
return &sqe.opcode__flags_events
|
||||
}
|
||||
|
||||
func (sqe *SQEvent) BufIndex() *uint16 {
|
||||
return &sqe.buf__index_group
|
||||
}
|
||||
func (sqe *SQEvent) BufGroup() *uint16 {
|
||||
return &sqe.buf__index_group
|
||||
}
|
||||
|
||||
func (sqe *SQEvent) SpliceFdIn() *int32 {
|
||||
return &sqe.splice_fd_in__file_index
|
||||
}
|
||||
func (sqe *SQEvent) FileIndex() *uint32 {
|
||||
return (*uint32)(unsafe.Pointer(&sqe.splice_fd_in__file_index))
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
type CQEvent struct {
|
||||
UserData uint64 /* sqe->data submission passed back */
|
||||
Res int32 /* result code for this event */
|
||||
Flags UringCQEFlag
|
||||
}
|
20
sigset.go
Normal file
20
sigset.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package gouring
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
_uint64 uint64 = 0
|
||||
_sz_uint64 = unsafe.Sizeof(_uint64)
|
||||
SIGSET_NWORDS = (1024 / (8 * _sz_uint64))
|
||||
SIGTMIN = 32
|
||||
SIGTMAX = SIGTMIN
|
||||
NSIG = (SIGTMAX + 1)
|
||||
)
|
||||
|
||||
type Sigset_t struct {
|
||||
Val [SIGSET_NWORDS]uint64
|
||||
}
|
||||
|
||||
// https://baike.baidu.com/item/sigset_t/4481187
|
86
sysnum.go
Normal file
86
sysnum.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package gouring
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SYS_IO_URING_SETUP = 425
|
||||
SYS_IO_URING_ENTER = 426
|
||||
SYS_IO_URING_REGISTER = 427
|
||||
)
|
||||
|
||||
//go:linkname errnoErr syscall.errnoErr
|
||||
func errnoErr(e syscall.Errno) error
|
||||
|
||||
type SQOffsets struct {
|
||||
Head uint32
|
||||
Tail uint32
|
||||
RingMask uint32
|
||||
RingEntries uint32
|
||||
Flags uint32
|
||||
Dropped uint32
|
||||
Array uint32
|
||||
Resv1 uint32
|
||||
Resv2 uint64
|
||||
}
|
||||
|
||||
type CQOffsets struct {
|
||||
Head uint32
|
||||
Tail uint32
|
||||
RingMask uint32
|
||||
RingEntries uint32
|
||||
Overflow uint32
|
||||
CQEs uint32
|
||||
Flags uint32
|
||||
Resv1 uint32
|
||||
Resv2 uint64
|
||||
}
|
||||
|
||||
type IOUringParams struct {
|
||||
SQEntries uint32 // sq_entries
|
||||
CQEntries uint32 // cq_entries
|
||||
Flags UringSetupFlag // flags
|
||||
SQThreadCPU uint32 // sq_thread_cpu
|
||||
SQThreadIdle uint32 // sq_threead_idle
|
||||
Features UringParamFeatureFlag // features
|
||||
WQFd uint32 // wq_fd
|
||||
|
||||
resv [3]uint32 // resv
|
||||
|
||||
SQOff SQOffsets // sq_off
|
||||
CQOff CQOffsets // cq_off
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func io_uring_setup(entries uint, params *IOUringParams) (fd int, err error) {
|
||||
r1, _, e1 := syscall.Syscall(SYS_IO_URING_SETUP, uintptr(entries), uintptr(unsafe.Pointer(params)), 0)
|
||||
fd = int(r1)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func io_uring_enter(ringFd int, toSubmit uint, minComplete uint, flags uint, sig *Sigset_t) (ret int, err error) {
|
||||
return io_uring_enter2(ringFd, toSubmit, minComplete, flags, sig, NSIG/8)
|
||||
}
|
||||
|
||||
func io_uring_enter2(ringFd int, toSubmit uint, minComplete uint, flags uint, sig *Sigset_t, sz int) (ret int, err error) {
|
||||
r1, _, e1 := syscall.Syscall6(SYS_IO_URING_ENTER, uintptr(ringFd), uintptr(toSubmit), uintptr(minComplete), uintptr(flags), uintptr(unsafe.Pointer(sig)), uintptr(sz))
|
||||
ret = int(r1)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func io_uring_register(ringFd int, opcode uint /*const*/, arg uintptr, nrArgs uint) (ret int, err error) {
|
||||
r1, _, e1 := syscall.Syscall6(SYS_IO_URING_REGISTER, uintptr(ringFd), uintptr(opcode), arg, uintptr(nrArgs), 0, 0)
|
||||
ret = int(r1)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Add table
Reference in a new issue