use polling instead of syscall

This commit is contained in:
Josh Bleecher Snyder 2021-06-02 13:32:19 -07:00
parent 56ba714e10
commit a03ee93e21
2 changed files with 25 additions and 8 deletions

View File

@ -18,6 +18,19 @@ typedef struct io_uring go_uring;
typedef struct msghdr go_msghdr;
typedef struct iovec go_iovec;
typedef struct sockaddr_in go_sockaddr_in;
typedef struct io_uring_params go_io_uring_params;
static int initialize(struct io_uring *ring, int fd) {
struct io_uring_params params;
memset(&params, 0, sizeof(params));
params.flags |= IORING_SETUP_SQPOLL;
params.sq_thread_idle = 1000; // 1s
io_uring_queue_init_params(16, ring, &params); // 16: size of ring
int ret;
ret = io_uring_register_files(ring, &fd, 1);
// TODO: Do we need to unregister files on close, or is Closing the uring enough?
return ret;
}
// Wait for a completion to be available, fetch the data
static uint64_t receive_into(struct io_uring *ring) {
@ -62,7 +75,7 @@ static uint16_t port(struct sockaddr_in *sa) {
// submit a recvmsg request via liburing
// TODO: What recvfrom support arrives, maybe use that instead?
static int submit_recvmsg_request(int sock, struct io_uring *ring, struct msghdr *mhdr, struct iovec *iov, struct sockaddr_in *sender, char *buf, int buflen, size_t idx) {
static int submit_recvmsg_request(struct io_uring *ring, struct msghdr *mhdr, struct iovec *iov, struct sockaddr_in *sender, char *buf, int buflen, size_t idx) {
iov->iov_base = buf;
iov->iov_len = buflen;
@ -73,7 +86,8 @@ static int submit_recvmsg_request(int sock, struct io_uring *ring, struct msghdr
mhdr->msg_namelen = sizeof(struct sockaddr_in);
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
io_uring_prep_recvmsg(sqe, sock, mhdr, 0);
io_uring_prep_recvmsg(sqe, 0, mhdr, 0); // use the 0th file in the list of registered fds
io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
io_uring_sqe_set_data(sqe, (void *)(idx));
io_uring_submit(ring);

View File

@ -56,13 +56,16 @@ func NewUDPConn(conn *net.UDPConn) (*UDPConn, error) {
}
r := new(C.go_uring)
const queue_depth = 16 // TODO: What value to use here?
C.io_uring_queue_init(queue_depth, r, 0)
fd := C.int(file.Fd())
ret := C.initialize(r, fd)
if ret < 0 {
return nil, fmt.Errorf("uring initialization failed: %d", ret)
}
u := &UDPConn{
ptr: r,
conn: conn,
file: file,
fd: C.int(file.Fd()),
fd: fd,
local: conn.LocalAddr(),
}
for i := range u.reqs {
@ -84,7 +87,7 @@ type req struct {
func (u *UDPConn) submitRequest(idx int) error {
r := &u.reqs[idx]
// TODO: make a C struct instead of a Go struct, and pass that in, to simplify call sites.
errno := C.submit_recvmsg_request(u.fd, u.ptr, &r.mhdr, &r.iov, &r.sa, (*C.char)(unsafe.Pointer(&r.buf[0])), C.int(len(r.buf)), C.size_t(idx))
errno := C.submit_recvmsg_request(u.ptr, &r.mhdr, &r.iov, &r.sa, (*C.char)(unsafe.Pointer(&r.buf[0])), C.int(len(r.buf)), C.size_t(idx))
if errno < 0 {
return fmt.Errorf("uring.submitRequest failed: %v", errno) // TODO: Improve
}
@ -96,8 +99,8 @@ func (u *UDPConn) ReadFromNetaddr(buf []byte) (int, netaddr.IPPort, error) {
return 0, netaddr.IPPort{}, errors.New("invalid uring.UDPConn")
}
nidx := C.receive_into(u.ptr)
if int64(nidx) == -1 {
return 0, netaddr.IPPort{}, errors.New("something wrong")
if int64(nidx) < 0 {
return 0, netaddr.IPPort{}, fmt.Errorf("something wrong, errno %v", int64(nidx))
}
idx := uint32(nidx)
n := uint32(nidx >> 32)