/* This is an example that uses io_uring with attach mode. It demonstrates the what happens if some thread submits to the original ring and then spins, while a second thread waits on the attached ring. This deadlocks because even if rings are attached, they don't share a completion queue. Therefore all completion queues must be polled for progress to be made. It uses liburing for simplicity. */ #include #include #include #include #include #include #include #include volatile bool done = false; void * submitter(void * arg) { struct io_uring * ring = (struct io_uring *)arg; const char * path = __FILE__; int fd = open(path, 0, O_RDONLY); if( fd < 0) { fprintf(stderr, "Can't open file: (%d) %s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } printf("Opened file: %d\n", fd); char buffer[1024]; struct io_uring_sqe * sqe = io_uring_get_sqe(ring); io_uring_prep_read(sqe, fd, buffer, 1024, 0); io_uring_submit(ring); printf("Submitted read\n"); printf("Spinning\n"); while(!__atomic_load_n(&done, __ATOMIC_SEQ_CST)); return NULL; } void * poller(void * arg) { struct io_uring * ring = (struct io_uring *)arg; struct io_uring_cqe *cqe; printf("Waiting for results\n"); int ret = io_uring_wait_cqe(ring, &cqe); if( ret < 0) { fprintf(stderr, "ioring wait failed: (%d) %s\n", -ret, strerror(-ret)); exit(EXIT_FAILURE); } io_uring_cqe_seen(ring, cqe); printf("Got result\n"); __atomic_store_n(&done, true, __ATOMIC_SEQ_CST); return NULL; } int main() { struct io_uring base_ring; io_uring_queue_init(8, &base_ring, 0); printf("Created first ring: %d\n", base_ring.ring_fd); struct io_uring attached_ring; struct io_uring_params par; memset(&par, '\0', sizeof(struct io_uring_params)); par.flags |= IORING_SETUP_ATTACH_WQ; par.wq_fd = base_ring.ring_fd; io_uring_queue_init_params(8, &attached_ring, &par); printf("Attached second ring: %d\n", attached_ring.ring_fd); printf("Forking\n"); pthread_t s, p; int ret = pthread_create(&s, NULL, submitter, &base_ring); if( ret < 0) { fprintf(stderr, "pthread create 1 error: (%d) %s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } ret = pthread_create(&p, NULL, poller, &attached_ring); if( ret < 0) { fprintf(stderr, "pthread create 2 error: (%d) %s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } ret = pthread_join(p, NULL); if( ret < 0) { fprintf(stderr, "pthread join 2 error: (%d) %s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } ret = pthread_join(s, NULL); if( ret < 0) { fprintf(stderr, "pthread join 1 error: (%d) %s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } }