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)
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]
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)
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)
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)
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)
def _submit(self, request_type, sqe, *args): future = asyncio.Future() sqe.user_data = id(future) self.store[sqe.user_data] = request_type, future, *args liburing.io_uring_submit(self.ring) return future