Skip to content

libcoring is a C++ network library in Proactor, and it is based on the new io_uring syscall of linux and coroutine in C++ 20. It's stop currently. We will try to bring sender-receiver model to it in the future.

License

Notifications You must be signed in to change notification settings

rzbdz/libcoring

Repository files navigation

What 's this:

libcoring is a C++ network library in Proactor pattern (@see: POSA2), and it is based on the new io_uring syscall of linux and coroutine in C++ 20. It's under development now, the progress could be viewed in Github project page.

There are some documents available:

  • For an overview of development document or to know how libcoring is arranged, please refer to design document file.
  • To build and run this library with demos, check getting start file. Installation and library import/link configuration isn't available yet for it's still developing.

Getting Start

Just take a look at the directory demo.

echo server:

// codes are trimmed, check the source `coring/demo/echo_server.cpp` for details
task<> echo_loop(tcp::connection conn){
  while(true){
    auto& selected = co_await buffer_pool.try_read_block(conn, GID, MAX_MESSAGE_LEN);
    selected_buffer_resource return_it_when_exit(selected);
    co_await socket_writer(conn, selected).write_all_to_file();
  }
}
task<> event_loop() {
  co_await buffer_pool.provide_group_contiguous(buf, MAX_MESSAGE_LEN, BUFFERS_COUNT, GID);
  while (true) {
    auto conn = co_await acceptor.accept();
    coro::spawn(echo_loop(conn));
  }
}
void run(){
  io_context context;
  context.schedule(event_loop());
  context.run();
}

timeout:

// codes are trimmed, check the source `coring/demo/connect_with_timeout.cpp` for details
task<> connect() {
  using namespace std::chrono_literals;
  auto endpoint = net::endpoint::from_resolve("www.google.com", 80);
  std::cout << endpoint.address_str() << std::endl;
  auto conn = co_await tcp::connect_to(endpoint, 3s); // timer in kernel, it would throw an exception if timeout
  // ... do sth with conn
  // ....................
  co_await timeout(20s); // timer in user space , see coring/test/io_context_test.cpp
                         // with coroutine, this is natual
  // ... do sth else
  // ....................
}

void run() {
  io_context context;
  context.schedule(connect(&context));
  context.run();
}

cancellation:

Notice: since IORING_ASYNC_CANCEL_ANY in io_uring will soon be released, the development on cancellation part of libcoring stalls now. The cancellation branch would be marked decrapted and be deleted soon. By the time the new kernel is available, the development would go on with another branch. Codes below may be not supported or supported in newer versions.

task<> connect(io_context *ioc) {
  using namespace std::chrono_literals;
  io_cancel_source src;
  auto ep = net::endpoint::from_resolve("www.google.com", 80);
  // non-blocking, fire-and-forget, async_task
  auto promise = tcp::connect_to(ep, src.get_token()); 
  // I can just do many other things here, say do some O(n^2) computing...
  // ......
  // use this for simplicity, user space timer is low cost-effective here...
  co_await ioc->timeout(3s);
  if (!promise.is_ready()) {
    auto res = co_await src.cancel_and_wait_for_result(*ioc);
    // res is 0 if successfully cancelled
  }
  [[maybe_unused]] auto c = co_await promise; 
  // here may throw if cancelled, I didn't decide if we should count ECLEAN as an exception
}

For more details, check getting start file.


Performance

Now the comparison is focus on the overhead of the utilities and coroutine abstraction in libcoring, when it comes to io_uring versus epoll/... is another topics. Currently, only httpd and echo-server is benched. Check benchmark page for details.

Without SQPoll, compared to raw C liburing interface (100%):

utility QPS Throughput
webbench (120 bytes) 102% 99%
apache bench (120 bytes) 101% 102%
rust-echo-bench (512 bytes) 96% N/A
rust-echo-bench (2018 bytes) 102% N/A

Focusing on now

  • [*now] Benchmarking for all module with alternatives designs.
  • Threading, no good threading model design now.
  • more simple buffer interface, and improve the performance on sth like insert_iterator with fmt.
  • [suspended] Cancellation for io_uring.

Notices and Concerns:

This project learn from following library or repositories:

This project learn and modified some codes from following library or repositories:

The type of coroutine task<> is lazy in libcoring, just like the awaitable<> in boost::asio, arguments on lazy task<> or non-lazy task<> both make sense, the difference is only in the initial_suspend function, I would try to find which is better design, maybe lazy task cooperate with executor would be enough:

The cancellation for io_uring and combined with stackless coroutine would be a little difficult to image. There are mature solution in C# await and async facilities, but IOCP differs to io_uring on both cancellation and multithreading restrictions. Although a simple cancellation token could be used for coroutine, but the supports for io_uring would be another subject. Another things is that the cancellation part in io_uring is still keep going, recently the CANCEL_ANY is patched, cancellation is now supporting cancel more than one request a time (use a fd). But it requires a further upgrade of latest kernel, I would try once it's available.


About

libcoring is a C++ network library in Proactor, and it is based on the new io_uring syscall of linux and coroutine in C++ 20. It's stop currently. We will try to bring sender-receiver model to it in the future.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published