Example #1
0
def test_socket_timeout():
    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # socket
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
    server.bind(('0.0.0.0', 0))  # random port
    server.listen(32)

    # prepare
    fd = server.fileno()
    addr, addrlen = liburing.sockaddr()
    try:
        # initialization
        assert liburing.io_uring_queue_init(32, ring, 0) == 0

        # accept
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_accept(sqe, fd, addr, addrlen, 0)
        sqe.flags |= liburing.IOSQE_IO_LINK
        sqe.user_data = 1

        sqe = liburing.io_uring_get_sqe(ring)
        ts = liburing.timespec(0, 41666)  # 1000000//24 nanosecond
        liburing.io_uring_prep_link_timeout(sqe, ts, 0)
        sqe.user_data = 2

        assert liburing.io_uring_submit(ring) == 2

        while True:
            try:
                assert liburing.io_uring_peek_cqe(ring, cqes) == 0
            except BlockingIOError:
                pass  # waiting for events, do something else here.
            else:
                cqe = cqes[0]
                if cqe.user_data == 1:
                    # OSError: [Errno 125] Operation canceled
                    assert cqe.res == -125
                    liburing.io_uring_cqe_seen(ring, cqe)
                    continue
                else:
                    # Timeout value confirm
                    assert cqe.user_data == 2

                    # `OSError: [Errno 62] Timer expired` or
                    # `BlockingIOError: [Errno 114] Operation already in progress`
                    assert cqe.res in (-62, -114)
                    liburing.io_uring_cqe_seen(ring, cqe)
                    break

    finally:
        server.close()
        liburing.io_uring_queue_exit(ring)
Example #2
0
def onwait_flag(path):

    fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_NONBLOCK, 0o660)

    one = bytearray(6)
    two = bytearray(5)
    vec = liburing.iovec(one, two)

    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # print()

    try:
        # WRITE
        # -----
        os.write(fd, b'hello world')
        os.fsync(fd)

        assert liburing.io_uring_queue_init(2, ring, 0) == 0

        # READ
        # ----
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_readv(sqe, fd, vec, len(vec), 0, os.RWF_NOWAIT)
        sqe.user_data = 1

        assert liburing.io_uring_submit(ring) == 1

        while True:
            try:
                liburing.io_uring_peek_cqe(ring, cqes)
            except BlockingIOError:
                pass  # print('test_rwf_nowait_flag BlockingIOError', flush=True)
            else:
                cqe = cqes[0]
                liburing.trap_error(cqe.res)
                assert cqe.res == 6 + 5
                assert cqe.user_data == 1
                assert one == b'hello '
                assert two == b'world'
                liburing.io_uring_cqe_seen(ring, cqe)
                break
    finally:
        liburing.io_uring_queue_exit(ring)
        os.close(fd)
        os.unlink(path)
Example #3
0
def submit_wait_result(ring, cqes, no=1):
    io_uring_submit(ring)
    if no == 1:
        io_uring_wait_cqe(ring, cqes)
        cqe = cqes[0]
        result = cqe.res
        io_uring_cqe_seen(ring, cqe)
        return trap_error(result)  # type: int
    else:  # multiple
        r = []
        for i in range(no, 0, -1):
            io_uring_wait_cqes(ring, cqes, i)
            cqe = cqes[0]
            r.append(cqe.res)
            io_uring_cqe_seen(ring, cqe)

        # check for errors and raise if any
        for i in r:
            trap_error(i)
        return r  # type: list[int]
Example #4
0
def onwait_flag_empty_file(path, flag):

    fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_NONBLOCK, 0o660)
    read = bytearray(5)
    vec = liburing.iovec(read)

    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    try:
        assert liburing.io_uring_queue_init(2, ring, 0) == 0

        # READ empty file
        # ---------------
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_readv(sqe, fd, vec, len(vec), 0, flag)
        sqe.user_data = 1

        assert liburing.io_uring_submit(ring) == 1

        while True:
            try:
                liburing.io_uring_peek_cqe(ring, cqes)
            except BlockingIOError:
                pass  # print('test_rwf_nowait_flag BlockingIOError', flush=True)
            else:
                cqe = cqes[0]
                # empty file with `RWF_NOWAIT` flag will return `-EAGAIN` rather then `0`
                if flag & os.RWF_NOWAIT:
                    assert cqe.res == -errno.EAGAIN
                else:
                    assert cqe.res == 0
                liburing.io_uring_cqe_seen(ring, cqe)
                break
    finally:
        liburing.io_uring_queue_exit(ring)
        os.close(fd)
        os.unlink(path)
Example #5
0
def test_event(tmpdir):
    fd = os.open(os.path.join(tmpdir, 'event.txt'), os.O_RDWR | os.O_CREAT,
                 0o660)
    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # prepare for writing.
    data = bytearray(b'hello world')
    vecs = liburing.iovec(data)

    try:
        # initialization
        assert liburing.io_uring_queue_init(32, ring, 0) == 0

        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_writev(sqe, fd, vecs, len(vecs), 0)
        assert liburing.io_uring_submit(ring) == 1

        while True:
            try:
                liburing.io_uring_peek_cqe(ring, cqes)
            except BlockingIOError:
                pass  # waiting for events, do something else here.
            else:
                cqe = cqes[0]
                assert cqe.res == 11
                liburing.io_uring_cqe_seen(ring, cqe)
                break

        # confirm
        content = os.read(fd, 100)
        assert content == data
        assert len(content) == vecs[0].iov_len
    finally:
        os.close(fd)
        liburing.io_uring_queue_exit(ring)
Example #6
0
    def eventfd_callback(self):
        libc.eventfd_read(self.event_fd, os.O_NONBLOCK | os.O_CLOEXEC)
        while True:
            try:
                liburing.io_uring_peek_cqe(self.ring, self.cqes)
            except BlockingIOError:
                break
            cqe = self.cqes[0]
            result = liburing.trap_error(cqe.res)
            request_type, future, *args = self.store[cqe.user_data]

            if request_type is RequestType.OPEN:
                future.set_result(result)
            elif request_type is RequestType.CLOSE:
                future.set_result(None)
            elif request_type is RequestType.READ:
                future.set_result(args[0])
            elif request_type is RequestType.WRITE:
                future.set_result(None)
            else:
                raise RuntimeError

            del self.store[cqe.user_data]
            liburing.io_uring_cqe_seen(self.ring, cqe)
Example #7
0
def test_files_write_read(tmpdir):
    fd = os.open(os.path.join(tmpdir, '1.txt'), os.O_RDWR | os.O_CREAT, 0o660)
    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # prepare for writing two separate writes and reads.
    one = bytearray(b'hello')
    two = bytearray(b'world')
    vec_one = liburing.iovec(one)
    vec_two = liburing.iovec(two)

    try:
        # initialization
        assert liburing.io_uring_queue_init(2, ring, 0) == 0

        # write "hello"
        sqe = liburing.io_uring_get_sqe(ring)  # get sqe (submission queue entry) to fill
        liburing.io_uring_prep_write(sqe, fd, vec_one[0].iov_base, vec_one[0].iov_len, 0)
        sqe.user_data = 1

        # write "world"
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_writev(sqe, fd, vec_two, len(vec_two), 5)
        sqe.user_data = 2

        # submit both writes
        assert liburing.io_uring_submit(ring) == 2

        # wait for ``2`` entry to complete using single syscall
        assert liburing.io_uring_wait_cqes(ring, cqes, 2) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 1
        liburing.io_uring_cqe_seen(ring, cqe)

        # re-uses the same resources from above?!
        assert liburing.io_uring_wait_cqes(ring, cqes, 1) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 2
        liburing.io_uring_cqe_seen(ring, cqe)

        # Using same ``vec*`` swap so read can be confirmed.

        # read "world"
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_readv(sqe, fd, vec_one, len(vec_one), 5)
        sqe.user_data = 3

        assert liburing.io_uring_submit(ring) == 1
        assert liburing.io_uring_wait_cqe(ring, cqes) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 3
        liburing.io_uring_cq_advance(ring, 1)

        # read "hello"
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_read(sqe, fd, vec_two[0].iov_base, vec_two[0].iov_len, 0)
        sqe.user_data = 4

        assert liburing.io_uring_submit(ring) == 1
        assert liburing.io_uring_wait_cqe(ring, cqes) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 4
        liburing.io_uring_cq_advance(ring, 1)

        # use same as write buffer to read but switch values so the change is detected
        assert one == b'world'
        assert two == b'hello'
    finally:
        os.close(fd)
        liburing.io_uring_queue_exit(ring)