Skip to content

Lifetime management: Explicit peer-lifetime state + transition choke point - #11875

Open
Protik Biswas (protikbiswas100) wants to merge 3 commits into
mainfrom
user/protikbiswas/pillar-a-peer-lifetime
Open

Protik Biswas (protikbiswas100) wants to merge 3 commits into
mainfrom
user/protikbiswas/pillar-a-peer-lifetime

Conversation

@protikbiswas100

@protikbiswas100 Protik Biswas (protikbiswas100) commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

What

Adds an explicit peer-lifetime state machine to track the lifetime relationship between a native DependencyObject and its managed peer, so the transition between "connected" and "torn down" is observable at a single, well-defined point instead of being implicit.

Fixes

https://task.ms/64051050

Why

XAML objects exist as a native/managed pair whose lifetimes must stay in sync. Today the connect/disconnect and teardown transitions are scattered and implicit, which makes premature release and over-hold bugs hard to reason about. This change centralizes those transitions so peer lifetime can be tracked reliably.

Changes

  • Introduce an explicit peer-lifetime state and a single transition choke point that all state changes flow through.
  • Route tracker connect/disconnect and the implicit peg through that choke point.
  • Announce the Releasing / TornDown transitions at the peer teardown funnel.

Files touched

  • dxaml/xcp/dxaml/lifetime/inc/WeakReferenceSourceNoThreadId.h (+36)
  • dxaml/xcp/dxaml/lifetime/lib/WeakReferenceSourceNoThreadId.cpp (+190)
  • dxaml/xcp/dxaml/lib/DependencyObject.cpp (+18)

Net: 3 files changed, 244 insertions (additive only, no deletions).

…hoke point

Add PeerLifetimeState {Detached,Pegged,Tracked,Releasing,TornDown} and a single
TransitionPeerState choke point on the framework peer base
(ctl::WeakReferenceSourceNoThreadId), where the peg/tracker bookkeeping actually
lives.

This is the compat-shim phase of Pillar A: GetPeerLifetimeState() is *derived*
from the existing scattered fields (m_ulPegRefCount, m_bIsPeggedNoRef,
m_bReferenceTrackerPeg, bRefCountPeg, m_ulExpectedRefCount, disconnect flags) so
it can never drift from reality while the rest of the framework still mutates
those fields directly. TransitionPeerState is a non-fatal observability/assertion
gate wired into the real peg primitives (UpdatePeg/PegNoRef/UnpegNoRef) under DBG,
so retail is zero-cost and shipping builds cannot be destabilized.

No behavioral change. Establishes the dependency root for migrating the ~62
peg/unpeg call sites onto the transition API in subsequent changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1677a4a7-252f-4dae-82bb-c43c6e88340c
…gh the choke point

Extend the Pillar A observability from PR (1/N) to the remaining lifetime edges
that peg-counting alone doesn't cover:

  * ConnectFromTrackerSource / DisconnectFromTrackerSource -> the Tracked<->Detached
    edges as a reference-tracker source starts/stops rooting the peer.
  * SetRefCountPeg / ClearRefCountPeg -> the implicit GC-walk root applied/removed
    during a reference-tracker walk.

Each announces its transition through TransitionPeerState. Still DBG-only and
non-fatal (zero retail cost, no behavior change); builds directly on the derived
GetPeerLifetimeState() introduced in (1/N).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1677a4a7-252f-4dae-82bb-c43c6e88340c
Complete the peer-lifetime state machine's terminal lifecycle, which the
peg/tracker instrumentation in (1/N) and (2/N) does not cover:

  * DirectUI::DependencyObject::OnFinalRelease -> announce the peer entering
    final release (-> Releasing).
  * DirectUI::DependencyObject::DisconnectFrameworkPeerCore -> capture the state
    before teardown and announce the terminal transition once the disconnect
    flags are set (-> TornDown).

Both route through TransitionPeerState. DBG-only and non-fatal (zero retail cost,
no behavioral change); the release/disconnect paths themselves are untouched.

Together (1/N)+(2/N)+(3/N) give the state machine full observability across the
peg, tracker, and teardown edges, which the later native call-site migrations
will assert against.

Built: wrtdxamlfoundation.lib (Debug|x64) compiles clean with these changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1677a4a7-252f-4dae-82bb-c43c6e88340c
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@microsoft-github-policy-service microsoft-github-policy-service Bot added the needs-triage Issue needs to be triaged by the area owners label Sep 14, 2026
@protikbiswas100 Protik Biswas (protikbiswas100) changed the title Pillar A: explicit peer-lifetime state + transition choke point (1-3/N) Track native/managed peer lifetime via an explicit state + transition choke point Sep 14, 2026
@protikbiswas100 Protik Biswas (protikbiswas100) changed the title Track native/managed peer lifetime via an explicit state + transition choke point Lifetime management: Explicit peer-lifetime state + transition choke point Sep 14, 2026
@protikbiswas100

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
1 pipeline(s) were filtered out due to trigger conditions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-triage Issue needs to be triaged by the area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant