namespace XFESystem.Kernel;
/// <summary>
/// Bounds adapter discovery with the monotonic clock, independently of the PIT
/// and its software timer registry. The caller supplies the already-running
/// LAPIC interrupt wait; neither delegate may block indefinitely.
/// </summary>
internal static class NativeNetworkBootWait
{
internal const int TimeoutSeconds = 5;
internal static bool WaitUntilReady(Func<bool> pollReady, Func<long> monotonicTimestamp,
long timestampFrequency, Action waitOneInterrupt)
{
ArgumentNullException.ThrowIfNull(pollReady);
ArgumentNullException.ThrowIfNull(monotonicTimestamp);
ArgumentNullException.ThrowIfNull(waitOneInterrupt);
// Keep the budget below half the counter range. This permits an
// unsigned elapsed subtraction across signed Stopwatch wrap without
// overflowing an absolute deadline or accepting a backwards clock.
if (timestampFrequency <= 0 || timestampFrequency > long.MaxValue / TimeoutSeconds)
throw new ArgumentOutOfRangeException(nameof(timestampFrequency));
ulong budget = (ulong)timestampFrequency * TimeoutSeconds;
long started = monotonicTimestamp();
while (true)
{
if (Elapsed(monotonicTimestamp(), started) >= budget) return false;
bool ready = pollReady();
// Count time spent polling as part of the same total budget. A
// readiness result obtained at or after the deadline is too late.
if (Elapsed(monotonicTimestamp(), started) >= budget) return false;
if (ready) return true;
waitOneInterrupt();
}
}
private static ulong Elapsed(long current, long started) => unchecked((ulong)(current - started));
}
namespace XFESystem.Kernel;
/// <summary>
/// Bounds adapter discovery with the monotonic clock, independently of the PIT
/// and its software timer registry. The caller supplies the already-running
/// LAPIC interrupt wait; neither delegate may block indefinitely.
/// </summary>
internal static class NativeNetworkBootWait
{
internal const int TimeoutSeconds = 5;
internal static bool WaitUntilReady(Func<bool> pollReady, Func<long> monotonicTimestamp,
long timestampFrequency, Action waitOneInterrupt)
{
ArgumentNullException.ThrowIfNull(pollReady);
ArgumentNullException.ThrowIfNull(monotonicTimestamp);
ArgumentNullException.ThrowIfNull(waitOneInterrupt);
// Keep the budget below half the counter range. This permits an
// unsigned elapsed subtraction across signed Stopwatch wrap without
// overflowing an absolute deadline or accepting a backwards clock.
if (timestampFrequency <= 0 || timestampFrequency > long.MaxValue / TimeoutSeconds)
throw new ArgumentOutOfRangeException(nameof(timestampFrequency));
ulong budget = (ulong)timestampFrequency * TimeoutSeconds;
long started = monotonicTimestamp();
while (true)
{
if (Elapsed(monotonicTimestamp(), started) >= budget) return false;
bool ready = pollReady();
// Count time spent polling as part of the same total budget. A
// readiness result obtained at or after the deadline is too late.
if (Elapsed(monotonicTimestamp(), started) >= budget) return false;
if (ready) return true;
waitOneInterrupt();
}
}
private static ulong Elapsed(long current, long started) => unchecked((ulong)(current - started));
}