1
0
Fork 0
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:
MastahSenpai 2021-12-20 18:35:33 +07:00
commit 85e03649ba
Signed by untrusted user who does not match committer: Xeffy
GPG key ID: E41C08AD390E7C49
11 changed files with 793 additions and 0 deletions

7
README.md Normal file
View file

@ -0,0 +1,7 @@
# gouring
Low-lavel io uring library
```
go get github.com/ii64/gouring
```

198
const_value.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}