NVIDIA/stdexec

Coroutines and any_sender

Closed this issue · 0 comments

Issue

I would like to use any_sender with coroutines via let_value.

any_sender concat(any_sender&& a, auto&& coroutine)
{
    return stdexec::let_value(std::move(a), std::move(coroutine));
}

An error occurs during connect, because the connect function can't be called.

My investigation result

The chain looks something like:

  • Error occurs when the any_sender is constructed and the vtable is built up
  • It tries to make the connect call
  • It goes to the set_value tag invoke
  • It ends up in the let_value. Here the sender is a task and the receiver is any_rec_ref

Here the connect can't be called due to the environment.
Actually the problem that the task is not awaitable with the context (environment) of the any_rec_ref.
the task is awaitable only if it is an indirect_scheduler_provider.
Here the promise is the connec_t promise which forwards the receiver environment which ends up at any_rec_ref.

So the environment of the any_rec_ref is

  • not a scheduler provider (its query is not forwarded)
  • and the task has the default_task_context which has a scheduler.

It makes the concept not fulfilled and causing that task is not awaitable with any_rec_ref

My two attempt to solve the issue:

With raw sender

I thought I can try to eliminate the issue with making the task to not have a scheduler. Actually it works but this type is 'private' and also feel a bit hacky solution. exec::basic_task<T, exec::__task::__raw_task_context<T>>;

Making the scheduler queriable in any_rec_ref

I thought using the ReceiversQuery template arguments of any_rec will solve the issue. But it failed with compile error. Looking around in the code it looks like never used and also stop_token is not provided via __query_vfun. The basic error that __query_vfun expects a signature and it receives a Tag. And for this the operator is not implemented.

Summary

I think the ideal solution would be to make the any_rec_ref be able to forward queries. (I'm also opened to create the PR but need some help to see how should the current __query_vfun work. I felt trying to modify it might break other - currently working - functionalities)

Test Code

https://godbolt.org/z/rjW3vWojW

Here there are 3 macros to control the scenarios:

  • USE_RAW_TASK: When true raw task type is used and it compiles
  • USE_TYPE_ERASE: When it is true it uses any_sender. When it is false it uses the sexpr and all works (like a sanity check)
  • USE_QUERIES: Try to use the receiver queries with get_scheduler