/
GeekNerd
/
ServerModelingProject
Обзор
Документация
Войти
/
GeekNerd
/
ServerModelingProject
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Assets/Plugins/UniTask/Runtime/TimeoutController.cs
129 строк
5 KB
Gorney-Alex
Init
30 май 2026, 19:05
30 май 2026, 19:05
3cdcc49
Код
Авторство
О чём код?
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System; using System.Threading; namespace Cysharp.Threading.Tasks { // CancellationTokenSource itself can not reuse but CancelAfter(Timeout.InfiniteTimeSpan) allows reuse if did not reach timeout. // Similar discussion: // https://github.com/dotnet/runtime/issues/4694 // https://github.com/dotnet/runtime/issues/48492 // This TimeoutController emulate similar implementation, using CancelAfterSlim; to achieve zero allocation timeout. public sealed class TimeoutController : IDisposable { readonly static Action<object> CancelCancellationTokenSourceStateDelegate = new Action<object>(CancelCancellationTokenSourceState); static void CancelCancellationTokenSourceState(object state) { var cts = (CancellationTokenSource)state; cts.Cancel(); } CancellationTokenSource timeoutSource; CancellationTokenSource linkedSource; PlayerLoopTimer timer; bool isDisposed; readonly DelayType delayType; readonly PlayerLoopTiming delayTiming; readonly CancellationTokenSource originalLinkCancellationTokenSource; public TimeoutController(DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) { this.timeoutSource = new CancellationTokenSource(); this.originalLinkCancellationTokenSource = null; this.linkedSource = null; this.delayType = delayType; this.delayTiming = delayTiming; } public TimeoutController(CancellationTokenSource linkCancellationTokenSource, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) { this.timeoutSource = new CancellationTokenSource(); this.originalLinkCancellationTokenSource = linkCancellationTokenSource; this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, linkCancellationTokenSource.Token); this.delayType = delayType; this.delayTiming = delayTiming; } public CancellationToken Timeout(int millisecondsTimeout) { return Timeout(TimeSpan.FromMilliseconds(millisecondsTimeout)); } public CancellationToken Timeout(TimeSpan timeout) { if (originalLinkCancellationTokenSource != null && originalLinkCancellationTokenSource.IsCancellationRequested) { return originalLinkCancellationTokenSource.Token; } // Timeouted, create new source and timer. if (timeoutSource.IsCancellationRequested) { timeoutSource.Dispose(); timeoutSource = new CancellationTokenSource(); if (linkedSource != null) { this.linkedSource.Cancel(); this.linkedSource.Dispose(); this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, originalLinkCancellationTokenSource.Token); } timer?.Dispose(); timer = null; } var useSource = (linkedSource != null) ? linkedSource : timeoutSource; var token = useSource.Token; if (timer == null) { // Timer complete => timeoutSource.Cancel() -> linkedSource will be canceled. // (linked)token is canceled => stop timer timer = PlayerLoopTimer.StartNew(timeout, false, delayType, delayTiming, token, CancelCancellationTokenSourceStateDelegate, timeoutSource); } else { timer.Restart(timeout); } return token; } public bool IsTimeout() { return timeoutSource.IsCancellationRequested; } public void Reset() { timer?.Stop(); } public void Dispose() { if (isDisposed) return; try { // stop timer. timer?.Dispose(); // cancel and dispose. timeoutSource.Cancel(); timeoutSource.Dispose(); if (linkedSource != null) { linkedSource.Cancel(); linkedSource.Dispose(); } } finally { isDisposed = true; } } } }