Skip to content

Conversation

@oldnewthing
Copy link
Member

The big deal here is that we fix co_await apartment_context so that it consumes no stack[1] if you are already in the destination context. This is a big win for loops that do apartment switching.

To do this, impl::resume_apartment now returns true if it wants the caller to resume the coroutine synchronously, rather than doing it directly. If the caller is await_suspend, then it can propagate that result to the coroutine infrastructure and avoid stack build-up.

Fixed a lifetime issue in apartment_awaiter, which copied the context too soon. It needs to copy it in the await_suspend, because the coroutine is to resume synchronously in the new apartment, which under the old code would destruct the context while await_suspend was still using it. This shifts a refcount update from one place to another, so no net change.

We no longer need to extend the lifetime of the IAsyncAction now that we detect and defer synchronous resumption. This deletes a refcount update.

[1] Older builds of MSVC have code generation issues for bool await_suspend, so we deftly avoid them here, in the same way we avoided them for co_await IAsyncAction. (Though the existing code in many awaiters such as final_suspend_awaiter still use bool await_suspend, so maybe it's okay to assume MSVC 16.11 or later?)

The big deal here is that we fix `co_await apartment_context`
so that it consumes no stack[1] if you are already in the destination
context. This is a big win for loops that do apartment switching.

To do this, `impl::resume_apartment` now returns `true` if
it wants the caller to resume the coroutine synchronously, rather
than doing it directly. If the caller is `await_suspend`, then it
can propagate that result to the coroutine infrastructure and
avoid stack build-up.

Fixed a lifetime issue in `apartment_awaiter`, which copied
the context too soon. It needs to copy it in the `await_suspend`,
because the coroutine is to resume synchronously in the new
apartment, which under the old code would destruct the context
while `await_suspend` was still using it. This shifts a refcount
update from one place to another, so no net change.

We no longer need to extend the lifetime of the `IAsyncAction`
now that we detect and defer synchronous resumption. This deletes
a refcount update.

[1] Older builds of MSVC have code generation issues for
`bool await_suspend`, so we deftly avoid them here, in the same
way we avoided them for `co_await IAsyncAction`. (Though the existing
code in many awaiters such as `final_suspend_awaiter` still use
`bool await_suspend`, so maybe we'll just hope everybody migrates
to MSVC 16.11 or later?)
@sylveon
Copy link
Contributor

sylveon commented Feb 8, 2023

I thought I heard somewhere that apartment_context wasn't recommended anymore and people should prefer a CoreDispatcher or DispatcherQueue. Is this correct?

Copy link
Collaborator

@kennykerr kennykerr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I had some concerns about stack unwinding but I think that's only a concern with dispatchers.

@kennykerr
Copy link
Collaborator

I thought I heard somewhere that apartment_context wasn't recommended anymore and people should prefer a CoreDispatcher or DispatcherQueue. Is this correct?

This is just a low-level COM-specific awaiter suitable for switching apartments. A given app model or API may require a specific dispatcher but apartment_context is still handy for more generalized implementations and avoids getting tied to any specific dispatcher.

@kennykerr
Copy link
Collaborator

so maybe it's okay to assume MSVC 16.11 or later

It's certainly time to start ditching some of the older workarounds.

@kennykerr kennykerr merged commit 4363e5c into microsoft:master Feb 8, 2023
@oldnewthing oldnewthing deleted the stack-reduction branch February 8, 2023 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants