Actually I'd love to be wrong about this, but I've not found a way to easily retrofit io_uring into programs/libraries that are already using either synchronous operations or poll(2).
Note that many applications don't use event loop frameworks. For simple applications they can be overkill. Even for more complex applications, it may be cleaner to use restartable semantics (i.e. same semantics as read--just call me again), especially for libraries or components that want to be event loop agnostic.
I'm sorry but that statement is incorrect. The same functionality is accomplished by either io_uring or epoll.
> every line in an application that calls read/recv needs to be refactored
If the GP finds it easy to refactor from poll to epoll they will find it no different to refactor from poll to io_uring; the only caveat being they won't exceed epoll's performance with the io_uring until the standalone syscalls are further refactored. They don't need to be. The statement is incorrect.
How easy/feasible this is depends on the language.
In C++, Rust, Zig, Java (Loom fibers), and Kotlin I know for a fact it's doable
Other languages I'm not sure what the experience is like
It seems to me to see any substantial benefit, you'd have to propagate async throughout your codebase, which would require rewriting your existing code to use some async primitive. I guess something like Java Loom does help you mask this, however.