libunifex icon indicating copy to clipboard operation
libunifex copied to clipboard

Question about any_sender_of usage

Open Garcia6l20 opened this issue 3 years ago • 6 comments

First of all, libunifex is amazing ! Thanks for your great work.

I'm trying to implement networking stuff using libunifex, all the basic things are ok (send, recv, connect, accept, ...), but, I'm running into troubles when I try to implement ssl socket.

In this context I need to bind either a send_sender or a recv_sender to a any_sender_of<size_t> (for the handshake procedure).

I minimized the area of the problem I'm encountering into your io_uring_test.cpp, in the main function I added:

auto read_or_write = [&](bool read = true) -> any_sender_of<> {
  if (read) {
    return read_file(scheduler, "test.txt");
  } else {
    return write_new_file(scheduler, "test.txt");
  }
};

sync_wait(read_or_write());

Then I have the following error using clang-11:

In file included from <...>/libunifex/examples/linux/io_uring_test.cpp:24:
<...>/libunifex/include/unifex/let.hpp:76:5: error: no matching function for call to object of type 'const struct _set_error_fn'
    unifex::set_error(std::move(op_.receiver_), (Error &&) error);

see: example branch.

I am missing something ? Is this actually the purpose of an any_sender_of<...> ? Is the error handling part is just missing from any_sender_of<...> ?

Thanks !

Garcia6l20 avatar Mar 26 '21 07:03 Garcia6l20

The problem is that the io_uring_context can propagate errors of two types: std::exception_ptr and std::error_code. any_sender_of<> is only able to handle std::exception_ptr. There currently isn't a generalization of any_sender_of<> than can handle more than std::exception_ptr.

A good solution, and something we should probably have anyway, is a variant sender. Since it knows a priori what types it may contain, it doesn't have to guess what the error type is.

A stop-gap would be to change any_sender_of to handle error types other than std::exception_ptr by passing them to std::make_exception_ptr. That's not a super-awesome solution, though.

ericniebler avatar Mar 31 '21 01:03 ericniebler

Thanks for the reply !

I quick-fixed io_uring_ring context usability with coroutines and any_sender_of<> with those 2 commits:

  • https://github.com/Garcia6l20/libunifex/commit/f87af151bbb8b520eea9e1a4abacf1da0135c7fe
  • https://github.com/Garcia6l20/libunifex/commit/8b6abf69d09c0453f5842128a1d234fe19db197f

Are you interested for those changes, or are you planning to address them in another way ? (ie.: variant_sender)

Garcia6l20 avatar Apr 02 '21 15:04 Garcia6l20

Not those changes exactly, since that would lead to unnecessary code bloat for the vast majority of senders, which don't send std::error_code through the error channel. The io_uring_context is maintained by @lewissbaker. I wonder how he thinks we should deal with this.

ericniebler avatar Apr 02 '21 15:04 ericniebler

So, the simple path would be to make io_uring_context send std::system_error (wrapped into std::exception_ptr) rather than std::error_code. Isn't it ?

Garcia6l20 avatar Apr 02 '21 16:04 Garcia6l20

That would be one simple fix. Another is to put that logic into the type erased receiver itself so that any errors that are not already exception_ptrs get wrapped.

ericniebler avatar Apr 02 '21 22:04 ericniebler

Yes, I think this could be part of the type-erasing wrapper, but that would forward the non-exception_ptr error into another customisation point, like get_exception_ptr(err), that allowed you to customise how std::error_code was converted to an exception_ptr. i.e. so that it could be wrapped in a std::system_error instead.

For now, it could be hard-coded as logic in the type-erasing wrappers. e.g. the receiver it passes down could have two overloads of set_error(). One taking exception_ptr and the other taking an error_code that forwards on to set_error(*this, std::make_exception_ptr(std::system_error(ec)))

Longer term, it probably makes sense to allow the any_sender_of type to be parameterisable with both a list of set_value overloads and a list of set_error overloads that it expects/supports, rather than have them hard-coded to exception_ptr or some other error-types.

lewissbaker avatar Apr 02 '21 23:04 lewissbaker