examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

io_uring.cpp (2463B)


      1 #include <liburing.h>
      2 #include <iostream>
      3 #include <coroutine>
      4 #include <span>
      5 
      6 struct awaitable;
      7 
      8 struct uring
      9 {
     10 	uring(unsigned entries, unsigned flags) 
     11 	{
     12 		if (io_uring_queue_init(entries, &ring, flags))
     13 			throw std::system_error(errno, std::system_category());
     14 	}
     15 
     16 	~uring(void)
     17 	{
     18 		io_uring_queue_exit(&ring);
     19 	}
     20 
     21 	uring(const uring&) = delete;
     22 	uring& operator =(const uring&) = delete;
     23 
     24 	io_uring_sqe* get_sqe(void)
     25 	{
     26 		return io_uring_get_sqe(&ring);
     27 	}
     28 
     29 	int submit(void)
     30 	{
     31 		return io_uring_submit(&ring);
     32 	}
     33 
     34 	bool process_completion(void);
     35 	awaitable read(int, std::span<char>, unsigned);
     36 	awaitable write(int, std::span<char const>, unsigned);
     37 	unsigned n = 0;
     38 private:
     39 	io_uring ring;
     40 };
     41 
     42 struct task
     43 {
     44 	struct promise_type
     45 	{
     46 		int res;
     47 
     48 		void get_return_object(void) const noexcept
     49 		{}
     50 		auto initial_suspend(void) const noexcept
     51 		{
     52 			return std::suspend_never{};
     53 		}
     54 		auto final_suspend(void) const noexcept
     55 		{
     56 			return std::suspend_always{};
     57 		}
     58 		void unhandled_exception(void) const noexcept
     59 		{
     60 			std::terminate();
     61 		}
     62 		void return_void(void) const noexcept
     63 		{}
     64 	};
     65 };
     66 
     67 struct awaitable
     68 {
     69 	uring& u;
     70 	io_uring_sqe& sqe;
     71 	task::promise_type* p;
     72 
     73 	bool await_ready(void) const noexcept
     74 	{
     75 		return false;
     76 	}
     77 	void await_suspend(std::coroutine_handle<task::promise_type> h)
     78 	{
     79 		p = &h.promise();
     80 		io_uring_sqe_set_data(&sqe, h.address());
     81 		u.submit();
     82 		u.n++;
     83 	}
     84 	int await_resume()
     85 	{
     86 		return p->res;
     87 	}
     88 };
     89 
     90 bool uring::process_completion(void)
     91 {
     92 	if (!n)
     93 		return false;
     94 	--n;
     95 
     96 	io_uring_cqe* cqe;
     97 	if (io_uring_wait_cqe(&ring, &cqe))
     98 		throw std::system_error(errno, std::system_category());
     99 
    100 	auto addr = io_uring_cqe_get_data(cqe);
    101 	auto h = std::coroutine_handle<task::promise_type>::from_address(addr);
    102 	h.promise().res = cqe->res;
    103 	h.resume();
    104 
    105 	return true;
    106 }
    107 
    108 awaitable uring::read(int fd, std::span<char> buf, unsigned flags)
    109 {
    110 	auto sqe = get_sqe();
    111 	io_uring_prep_read(sqe, fd, buf.data(), buf.size(), flags);
    112 	return {*this, *sqe, {}};
    113 }
    114 awaitable uring::write(int fd, std::span<char const> buf, unsigned flags)
    115 {
    116 	auto sqe = get_sqe();
    117 	io_uring_prep_write(sqe, fd, buf.data(), buf.size(), flags);
    118 	return {*this, *sqe, {}};
    119 }
    120 
    121 task read_routine(uring& u)
    122 {
    123 	char b[128];
    124 	std::span<char> buf(b);
    125 	int n = co_await u.read(0, buf, 0);
    126 	if (n > 0)
    127 		co_await u.write(1, {b, (std::size_t)n}, 0);
    128 	co_return;
    129 }
    130 
    131 int main()
    132 {
    133 	uring r(128, 0);
    134 
    135 	read_routine(r);
    136 
    137 	while (r.process_completion())
    138 	{}
    139 
    140 	return 0;
    141 }