acdream/src/AcDream.App/Rendering/HostQuiescenceGate.cs
Erik 18d4b999de refactor(app): own native window callback lifetime
Publish the fixed Silk callback binding before acquisition, quiesce admitted callbacks before teardown, and retain failed physical detach ownership for retry. Preserve the frozen callback order while covering partial event accessors, concurrency, reentrancy, and shutdown completion.

Co-authored-by: Codex <codex@openai.com>
2026-07-22 09:59:10 +02:00

55 lines
1.4 KiB
C#

namespace AcDream.App.Rendering;
/// <summary>
/// Single logical admission gate for callbacks entering the application host.
/// Physical event removal remains important for ownership, but closing this
/// gate first makes a still-attached native callback inert while teardown
/// converges.
/// </summary>
internal sealed class HostQuiescenceGate
{
private readonly object _sync = new();
private bool _accepting = true;
public bool IsAccepting
{
get
{
lock (_sync)
return _accepting;
}
}
internal bool IsEnteredByCurrentThread => Monitor.IsEntered(_sync);
/// <summary>
/// Closes admission after any callback already executing on another
/// thread has returned. Monitor reentrancy lets the native Closing
/// callback close its own gate without waiting on itself.
/// </summary>
public void StopAccepting()
{
lock (_sync)
_accepting = false;
}
public void Invoke(Action callback)
{
ArgumentNullException.ThrowIfNull(callback);
lock (_sync)
{
if (_accepting)
callback();
}
}
public void Invoke<T>(Action<T> callback, T value)
{
ArgumentNullException.ThrowIfNull(callback);
lock (_sync)
{
if (_accepting)
callback(value);
}
}
}