AngleSharp by AngleSharp

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

 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 : IEventLoopEntry { private readonly Task _task; private readonly CancellationTokenSource _cts; private bool _started; private DateTime _created; public bool IsRunning { get { if (_task.Status != TaskStatus.Running && _task.Status != TaskStatus.WaitingForActivation) return _task.Status == TaskStatus.WaitingToRun; return true; } } public DateTime? Started { get { if (!IsRunning) return null; return _created; } } public TaskEventLoopEntry(Action<CancellationToken> action) { _cts = new CancellationTokenSource(); _task = new Task(delegate { action(_cts.Token); }, _cts.Token); } public void Run(Action callback) { if (!_started) { _created = DateTime.Now; _task.Start(); _task.ContinueWith(delegate { callback(); }); _started = true; } } 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 IEventLoopEntry 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; } _current = taskEventLoopEntry; RunCurrent(); return taskEventLoopEntry; } } public void Spin() { lock (this) { if (_current != null && _current.IsRunning) return; _current = (Dequeue(TaskPriority.Critical) ?? Dequeue(TaskPriority.Microtask) ?? Dequeue(TaskPriority.Normal) ?? Dequeue(TaskPriority.None)); } RunCurrent(); } public void CancelAll() { lock (this) { foreach (KeyValuePair<TaskPriority, Queue<TaskEventLoopEntry>> queue in _queues) { Queue<TaskEventLoopEntry> value = queue.Value; foreach (TaskEventLoopEntry item in value) { item.Cancel(); } value.Clear(); } _queues.Clear(); if (_current != null) _current.Cancel(); } } private void RunCurrent() { _current?.Run(delegate { lock (this) { _current = null; } Spin(); }); } private TaskEventLoopEntry Dequeue(TaskPriority priority) { if (_queues.ContainsKey(priority) && _queues[priority].Count != 0) return _queues[priority].Dequeue(); return null; } } }