// Auto-generated by alef — DO NOT EDIT
#nullable enable
namespace {{ namespace }} {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
/// <summary>
/// Service wrapper for {{ service_name }}.
/// </summary>
internal sealed class {{ class_name }}SafeHandle : SafeHandle {
private ulong _nativeHandle;
internal {{ class_name }}SafeHandle(ulong handle) : base(IntPtr.Zero, true) {
_nativeHandle = handle;
SetHandle(handle == 0 ? IntPtr.Zero : new IntPtr(1));
}
public override bool IsInvalid => _nativeHandle == 0;
internal ulong AlefHandle => _nativeHandle;
protected override bool ReleaseHandle() {
NativeMethods.{{ native_free }}(_nativeHandle);
_nativeHandle = 0;
SetHandle(IntPtr.Zero);
return true;
}
}
public class {{ class_name }} : IDisposable {
private {{ class_name }}SafeHandle _safeHandle;
private readonly object _ownerLock = new();
private int _activeOwnerBorrows;
private bool _ownerUnavailable;
private bool _ownerTransferPending;
private readonly Dictionary<IntPtr, GCHandle> _registeredCallbacks = new();
// A single static delegate instance bridges the native callback. Held in a static field so the
// marshalled function pointer outlives every registration (a transient delegate would be collected).
private static readonly NativeMethods.HandlerCallback _handlerCallback = HandlerTrampoline;
private static readonly NativeMethods.HandlerResponseFree _handlerResponseFree = FreeHandlerResponse;
{% if needs_error_resolver %} private static Exception ResolveLastError() {
var code = NativeMethods.LastErrorCode();
var context = NativeMethods.LastErrorContext();
var message = Marshal.PtrToStringUTF8(context) ?? "Unknown native error";
return new {{ exception_name }}(code, message);
}
{% endif %}
private sealed class OwnerHandleLease : IDisposable {
private {{ class_name }}? _owner;
internal OwnerHandleLease({{ class_name }} owner) {
_owner = owner;
Handle = owner._safeHandle.AlefHandle;
}
internal ulong Handle { get; }
public void Dispose() {
var owner = global::System.Threading.Interlocked.Exchange(ref _owner, null);
owner?.ReleaseOwnerBorrow();
}
}
private sealed class OwnerHandleTransfer : IDisposable {
private {{ class_name }}? _owner;
private {{ class_name }}SafeHandle? _transferredHandle;
internal OwnerHandleTransfer({{ class_name }} owner, ulong handle) {
_owner = owner;
_transferredHandle = new {{ class_name }}SafeHandle(handle);
}
internal ulong Handle => _transferredHandle?.AlefHandle
?? throw new InvalidOperationException("Service owner transfer is no longer active");
internal void Commit() {
var transferred = _transferredHandle
?? throw new InvalidOperationException("Service owner transfer is no longer active");
transferred.SetHandleAsInvalid();
_transferredHandle = null;
var owner = _owner;
_owner = null;
owner?.CommitOwnerTransfer();
}
public void Dispose() {
var transferred = global::System.Threading.Interlocked.Exchange(ref _transferredHandle, null);
var owner = global::System.Threading.Interlocked.Exchange(ref _owner, null);
if (transferred is null) return;
if (owner is null) {
transferred.Dispose();
return;
}
var handle = transferred.AlefHandle;
transferred.SetHandleAsInvalid();
owner.RollbackOwnerTransfer(handle);
}
}
private OwnerHandleLease BorrowOwnerHandle() {
lock (_ownerLock) {
ThrowIfOwnerUnavailable();
var lease = new OwnerHandleLease(this);
var added = false;
_safeHandle.DangerousAddRef(ref added);
if (!added) throw new ObjectDisposedException(nameof({{ class_name }}));
_activeOwnerBorrows++;
return lease;
}
}
private void ReleaseOwnerBorrow() {
lock (_ownerLock) {
_safeHandle.DangerousRelease();
_activeOwnerBorrows--;
if (_activeOwnerBorrows == 0) global::System.Threading.Monitor.PulseAll(_ownerLock);
}
}
private OwnerHandleTransfer TakeOwnerHandle() {
lock (_ownerLock) {
ThrowIfOwnerUnavailable();
WaitForOwnerBorrows();
var transfer = new OwnerHandleTransfer(this, _safeHandle.AlefHandle);
_ownerUnavailable = true;
_safeHandle.SetHandleAsInvalid();
_ownerTransferPending = true;
return transfer;
}
}
private void RollbackOwnerTransfer(ulong handle) {
lock (_ownerLock) {
_safeHandle = new {{ class_name }}SafeHandle(handle);
_ownerTransferPending = false;
_ownerUnavailable = false;
global::System.Threading.Monitor.PulseAll(_ownerLock);
}
}
private void CommitOwnerTransfer() {
lock (_ownerLock) {
_ownerTransferPending = false;
global::System.Threading.Monitor.PulseAll(_ownerLock);
}
}
private void WaitForOwnerBorrows() {
var interrupted = false;
while (_activeOwnerBorrows != 0) {
try { global::System.Threading.Monitor.Wait(_ownerLock); }
catch (global::System.Threading.ThreadInterruptedException) { interrupted = true; }
}
if (interrupted) global::System.Threading.Thread.CurrentThread.Interrupt();
}
private void WaitForOwnerTransfer() {
var interrupted = false;
while (_ownerTransferPending) {
try { global::System.Threading.Monitor.Wait(_ownerLock); }
catch (global::System.Threading.ThreadInterruptedException) { interrupted = true; }
}
if (interrupted) global::System.Threading.Thread.CurrentThread.Interrupt();
}
private void ThrowIfOwnerUnavailable() {
if (_ownerUnavailable || _safeHandle.IsClosed || _safeHandle.IsInvalid) {
throw new ObjectDisposedException(nameof({{ class_name }}));
}
}