AngleSharp by AngleSharp

<PackageReference Include="AngleSharp" Version="0.9.10" />

 TaskEventLoop

sealed class TaskEventLoop : IEventLoop
The default event loop.
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace AngleSharp { internal sealed class TaskEventLoop : IEventLoop { private sealed class TaskEventLoopEntry : ICancellable { private readonly CancellationTokenSource _cts; private readonly Action<CancellationToken> _action; private Task _task; public bool IsCompleted { get { if (_task != null) return _task.IsCompleted; return false; } } public bool IsRunning { get { if ((_task == null || _task.Status != TaskStatus.Running) && _task.Status != TaskStatus.WaitingForActivation && _task.Status != TaskStatus.WaitingToRun) return _task.Status == TaskStatus.WaitingForChildrenToComplete; return true; } } public TaskEventLoopEntry(Action<CancellationToken> action) { _cts = new CancellationTokenSource(); _action = action; } public void Run(Action callback) { if (_task == null) _task = TaskEx.Run(delegate { _action(_cts.Token); callback(); }, _cts.Token); } public void Cancel() { _cts.Cancel(); } } private readonly Dictionary<TaskPriority, Queue<TaskEventLoopEntry>> _queues; private TaskEventLoopEntry _current; public TaskEventLoop() { _queues = new Dictionary<TaskPriority, Queue<TaskEventLoopEntry>>(); _current = null; } public ICancellable Enqueue(Action<CancellationToken> task, TaskPriority priority) { TaskEventLoopEntry taskEventLoopEntry = new TaskEventLoopEntry(task); lock (this) { Queue<TaskEventLoopEntry> value = null; if (!_queues.TryGetValue(priority, out value)) { value = new Queue<TaskEventLoopEntry>(); _queues.Add(priority, value); } if (_current != null) { value.Enqueue(taskEventLoopEntry); return taskEventLoopEntry; } SetCurrent(taskEventLoopEntry); return taskEventLoopEntry; } } public void Spin() { lock (this) { TaskEventLoopEntry current = _current; if (current == null || !current.IsRunning) SetCurrent(Dequeue(TaskPriority.Critical) ?? Dequeue(TaskPriority.Microtask) ?? Dequeue(TaskPriority.Normal) ?? Dequeue(TaskPriority.None)); } } public void CancelAll() { lock (this) { foreach (KeyValuePair<TaskPriority, Queue<TaskEventLoopEntry>> queue in _queues) { Queue<TaskEventLoopEntry> value = queue.Value; while (value.Count > 0) { value.Dequeue().Cancel(); } } _queues.Clear(); _current?.Cancel(); } } private void SetCurrent(TaskEventLoopEntry entry) { _current = entry; entry?.Run(Continue); } private void Continue() { lock (this) { _current = null; } Spin(); } private TaskEventLoopEntry Dequeue(TaskPriority priority) { if (_queues.ContainsKey(priority) && _queues[priority].Count != 0) return _queues[priority].Dequeue(); return null; } } }