From 7a306118f50ff3316ede85fa61ea8e9ba97a52ee Mon Sep 17 00:00:00 2001 From: neuecc Date: Tue, 19 May 2020 01:19:46 +0900 Subject: [PATCH] AsyncTrigger returns MoveNext -> false when destroyed --- .../Plugins/UniTask/Runtime/TriggerEvent.cs | 102 ++++++++++++++---- .../Runtime/Triggers/AsyncTriggerBase.cs | 36 ++++--- .../Runtime/UniTaskCompletionSource.cs | 8 -- 3 files changed, 104 insertions(+), 42 deletions(-) diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/TriggerEvent.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/TriggerEvent.cs index 65ec084..1e95590 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/TriggerEvent.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/TriggerEvent.cs @@ -4,26 +4,25 @@ using System.Threading; namespace Cysharp.Threading.Tasks { - public interface ITriggerEvent + public interface ITriggerHandler { - void SetResult(T value); - void SetCanceled(CancellationToken cancellationToken); - void Add(IResolveCancelPromise handler); - void Remove(IResolveCancelPromise handler); + void OnNext(T value); + void OnCanceled(CancellationToken cancellationToken); + void OnCompleted(); } // be careful to use, itself is struct. - public struct TriggerEvent : ITriggerEvent + public struct TriggerEvent { // optimize: many cases, handler is single. - IResolveCancelPromise singleHandler; + ITriggerHandler singleHandler; - IResolveCancelPromise[] handlers; + ITriggerHandler[] handlers; - // when running(in TrySetResult), does not add immediately. + // when running(in TrySetResult), does not add immediately(trampoline). bool isRunning; - IResolveCancelPromise waitHandler; - MinimumQueue> waitQueue; + ITriggerHandler waitHandler; + MinimumQueue> waitQueue; public void SetResult(T value) { @@ -33,7 +32,7 @@ namespace Cysharp.Threading.Tasks { try { - singleHandler.TrySetResult(value); + singleHandler.OnNext(value); } catch (Exception ex) { @@ -53,7 +52,7 @@ namespace Cysharp.Threading.Tasks { try { - handlers[i].TrySetResult(value); + handlers[i].OnNext(value); } catch (Exception ex) { @@ -94,7 +93,7 @@ namespace Cysharp.Threading.Tasks { try { - ((ICancelPromise)singleHandler).TrySetCanceled(cancellationToken); + (singleHandler).OnCanceled(cancellationToken); } catch (Exception ex) { @@ -114,7 +113,7 @@ namespace Cysharp.Threading.Tasks { try { - ((ICancelPromise)handlers[i]).TrySetCanceled(cancellationToken); + (handlers[i]).OnCanceled(cancellationToken); } catch (Exception ex) { @@ -147,7 +146,68 @@ namespace Cysharp.Threading.Tasks } } - public void Add(IResolveCancelPromise handler) + public void SetCompleted() + { + isRunning = true; + + if (singleHandler != null) + { + try + { + (singleHandler).OnCompleted(); + } + catch (Exception ex) + { +#if UNITY_2018_3_OR_NEWER + UnityEngine.Debug.LogException(ex); +#else + Console.WriteLine(ex); +#endif + } + } + + if (handlers != null) + { + for (int i = 0; i < handlers.Length; i++) + { + if (handlers[i] != null) + { + try + { + (handlers[i]).OnCompleted(); + } + catch (Exception ex) + { +#if UNITY_2018_3_OR_NEWER + UnityEngine.Debug.LogException(ex); +#else + Console.WriteLine(ex); +#endif + handlers[i] = null; + } + } + } + } + + isRunning = false; + + if (waitHandler != null) + { + var h = waitHandler; + waitHandler = null; + Add(h); + } + + if (waitQueue != null) + { + while (waitQueue.Count != 0) + { + Add(waitQueue.Dequeue()); + } + } + } + + public void Add(ITriggerHandler handler) { if (isRunning) { @@ -159,7 +219,7 @@ namespace Cysharp.Threading.Tasks if (waitQueue == null) { - waitQueue = new MinimumQueue>(4); + waitQueue = new MinimumQueue>(4); } waitQueue.Enqueue(handler); return; @@ -173,7 +233,7 @@ namespace Cysharp.Threading.Tasks { if (handlers == null) { - handlers = new IResolveCancelPromise[4]; + handlers = new ITriggerHandler[4]; } // check empty @@ -195,15 +255,15 @@ namespace Cysharp.Threading.Tasks } } - static void EnsureCapacity(ref IResolveCancelPromise[] array) + static void EnsureCapacity(ref ITriggerHandler[] array) { var newSize = array.Length * 2; - var newArray = new IResolveCancelPromise[newSize]; + var newArray = new ITriggerHandler[newSize]; Array.Copy(array, 0, newArray, 0, array.Length); array = newArray; } - public void Remove(IResolveCancelPromise handler) + public void Remove(ITriggerHandler handler) { if (singleHandler == handler) { diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/Triggers/AsyncTriggerBase.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/Triggers/AsyncTriggerBase.cs index 1fa1a42..f75fac8 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/Triggers/AsyncTriggerBase.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/Triggers/AsyncTriggerBase.cs @@ -24,10 +24,10 @@ namespace Cysharp.Threading.Tasks.Triggers if (calledDestroy) return; calledDestroy = true; - triggerEvent.SetCanceled(CancellationToken.None); + triggerEvent.SetCompleted(); } - internal void AddHandler(IResolveCancelPromise handler) + internal void AddHandler(ITriggerHandler handler) { if (!calledAwake) { @@ -37,7 +37,7 @@ namespace Cysharp.Threading.Tasks.Triggers triggerEvent.Add(handler); } - internal void RemoveHandler(IResolveCancelPromise handler) + internal void RemoveHandler(ITriggerHandler handler) { if (!calledAwake) { @@ -57,7 +57,7 @@ namespace Cysharp.Threading.Tasks.Triggers return new AsyncTriggerEnumerator(this, cancellationToken); } - sealed class AsyncTriggerEnumerator : MoveNextSource, IUniTaskAsyncEnumerator, IResolveCancelPromise + sealed class AsyncTriggerEnumerator : MoveNextSource, IUniTaskAsyncEnumerator, ITriggerHandler { static Action cancellationCallback = CancellationCallback; @@ -73,15 +73,20 @@ namespace Cysharp.Threading.Tasks.Triggers this.cancellationToken = cancellationToken; } - public bool TrySetCanceled(CancellationToken cancellationToken = default) + public void OnCanceled(CancellationToken cancellationToken = default) { - return completionSource.TrySetCanceled(cancellationToken); + completionSource.TrySetCanceled(cancellationToken); } - public bool TrySetResult(T value) + public void OnNext(T value) { Current = value; - return completionSource.TrySetResult(true); + completionSource.TrySetResult(true); + } + + public void OnCompleted() + { + completionSource.TrySetResult(false); } static void CancellationCallback(object state) @@ -164,7 +169,7 @@ namespace Cysharp.Threading.Tasks.Triggers } } - public sealed partial class AsyncTriggerHandler : IUniTaskSource, IResolveCancelPromise, IDisposable + public sealed partial class AsyncTriggerHandler : IUniTaskSource, ITriggerHandler, IDisposable { static Action cancellationCallback = CancellationCallback; @@ -253,14 +258,19 @@ namespace Cysharp.Threading.Tasks.Triggers } } - bool IResolvePromise.TrySetResult(T result) + void ITriggerHandler.OnNext(T value) { - return core.TrySetResult(result); + core.TrySetResult(value); } - bool ICancelPromise.TrySetCanceled(CancellationToken cancellationToken) + void ITriggerHandler.OnCanceled(CancellationToken cancellationToken) { - return core.TrySetCanceled(cancellationToken); + core.TrySetCanceled(cancellationToken); + } + + void ITriggerHandler.OnCompleted() + { + core.TrySetCanceled(CancellationToken.None); } void IUniTaskSource.GetResult(short token) diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs index 19b811c..e4d550d 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs @@ -38,14 +38,6 @@ namespace Cysharp.Threading.Tasks { } - public interface IResolveCancelPromise : IResolvePromise, ICancelPromise - { - } - - public interface IResolveCancelPromise : IResolvePromise, ICancelPromise - { - } - [StructLayout(LayoutKind.Auto)] public struct UniTaskCompletionSourceCore {