Skip to content

Scheduler-driven async cleanup for cancellation and frame exit #103

Description

@kammce

Problem

C++ has no async destructors. Async cleanup needs an active driver to resume
suspended work, and destruction can happen with no driver in reach — the two
are structurally incompatible. Not a missing language feature: Rust's
nightly AsyncDrop hits the same wall, scoped to async fn and falling back
to a detached task everywhere else.

New Policy

Async cleanup is explicit. Any object needing async cleanup will provide a shutdown() coroutine API. Libraries
implement it as a coroutine, and it's the method name the framework's
concepts (has_shutdown) looks for. Async cleanup is always a coroutine, driven by
whatever already drives the context, never a destructor.

  • Voluntary exit and involuntary cancellation are both solvable this way since destruction happens normally as apart of the normal resume() call.
  • The case of ~context() will need to cancel without cleanup rather than blocking the thread to cleanly cancel the operations.

Sub-issues

  • Rename context::cancel()cancel_without_cleanup()
  • Add is_cleanup bool field to promise_base
  • context::async_cancel(): coroutine, walks the continuation chain bottom-up,
    resumes/skips cleanup coroutines, cancels each real frame in turn,
    repeats until the top-level future is cancelled. Resolves the
    blocked_by::sync deadlock (driven by resume(), not a spin loop).
  • Cleanup-hook slot on promise_base, checked by async_cancel's walk
    and by final_awaiter — one mechanism for cancellation and normal
    exit.
  • Frame-free ordering fix: a spliced cleanup coroutine must run before
    the original frame's stack memory is reclaimed (allocator is strict
    LIFO).
  • async_cleanup<T>: no-op destructor, real destruction deferred to
    shutdown() via the final-awaiter drain.
  • async_cleanup<void>: same as above without a wrapped object. Holds a
    callback coroutine factory, invoked at final suspend time.
  • has_shutdown concept + shutdown_all fold pattern, for frames
    holding more than one cleanup object.
  • Docs: the three cases (voluntary / involuntary-but-scheduled /
    no-scheduler) and the policy for each.
  • Tests: cancellation cascade with cleanup hooks firing bottom-up;
    multi-resource cleanup ordering; LIFO frame-free regression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions