/* This is a file reading example that users io_uring in non-blocking mode. It demonstrates the bare minimum needed to use io_uring. It also optionally pre-registers the file descriptors (and a pipe, just to show it works). It uses liburing for simplicity. */ #include #include #include #include #include #include #include #include int main(int argc, char * argv[]) { if(argc != 3 && argc != 4) { printf("usage: %s FILE TIMES [fixed] - read FILE from disk TIMES times\n", argv[0]); return EXIT_FAILURE; } bool fixed = false; if(argc == 4) { fixed = 0 == strcmp(argv[3], "fixed"); } int times = atoi( argv[2] ); if(times <= 0) { printf("Invalid number of times %d (from %s).\n", times, argv[2]); return EXIT_FAILURE; } int fd = open(argv[1], 0); if(fd < 0) { printf("Could not open file %s.\n", argv[1]); return EXIT_FAILURE; } int rfd = fd; /* prep the array */ char data[100]; struct iovec iov = { data, 100 }; /* init liburing */ struct io_uring ring; io_uring_queue_init(256, &ring, 0); int pipefds[2]; if(fixed) { int ret = pipe(pipefds); if( ret < 0 ) { printf("Pipe Error : %s\n", strerror( errno )); return EXIT_FAILURE; } rfd = 0; int fds[] = { fd, pipefds[0], pipefds[1] }; int cnt = sizeof(fds) / sizeof(fds[0]); printf("Registering %d files as fixed\n", cnt); ret = io_uring_register_files(&ring, fds, cnt); if( ret < 0 ) { printf("Register Error : %s\n", strerror( -ret )); return EXIT_FAILURE; } } /* declare required structs */ printf("Reading %s(%d) %d times\n", argv[1], fd, times); size_t counter = 0; for(int i = 0; i < times; i++) { /* get an sqe and fill in a READV operation */ struct io_uring_sqe * sqe = io_uring_get_sqe(&ring); io_uring_prep_readv(sqe, rfd, &iov, 1, 0); if(fixed) { sqe->flags = IOSQE_FIXED_FILE; } /* tell the kernel we have an sqe ready for consumption */ io_uring_submit(&ring); /* poll the cq and count how much polling we did */ while(true) { struct io_uring_cqe * cqe = NULL; /* wait for the sqe to complete */ int ret = io_uring_wait_cqe_nr(&ring, &cqe, 0); /* read and process cqe event */ switch(ret) { case 0: if( cqe->res < 0 ) { printf("Completion Error : %s\n", strerror( -cqe->res )); return EXIT_FAILURE; } io_uring_cqe_seen(&ring, cqe); goto LOOP; case -EAGAIN: counter++; break; default: printf("Wait Error : %s\n", strerror( -ret )); return EXIT_FAILURE; } } LOOP:; } printf("%zu\n", counter); io_uring_queue_exit(&ring); close(fd); if(fixed) { close(pipefds[0]); close(pipefds[1]); } }