Skip to content

Commit

Permalink
Added and fixed AllSettled tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
timcassell committed Sep 10, 2023
1 parent e0e579b commit 3be71a8
Show file tree
Hide file tree
Showing 4 changed files with 1,337 additions and 17 deletions.
4 changes: 2 additions & 2 deletions Package/Core/Promises/Internal/MergeInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ internal static MergePromise<TResult> GetOrCreateMergePromise<TResult>(
return MergePromiseT<TResult>.GetOrCreate(promisePassThroughs, value, pendingAwaits, completedProgress, depth, getResultFunc);
}

internal sealed class MergeSettledPromise<TResult> : MergePromise<TResult>
internal sealed partial class MergeSettledPromise<TResult> : MergePromise<TResult>
{
private static GetResultContainerDelegate<TResult> s_getResult;

Expand Down Expand Up @@ -300,7 +300,7 @@ internal override sealed void Handle(PromiseRefBase handler, object rejectContai
handler.MaybeDispose();
if (RemoveWaiterAndGetIsComplete())
{
ReleaseAndHandleNext(rejectContainer, state);
ReleaseAndHandleNext(null, Promise.State.Resolved);
return;
}
MaybeDispose();
Expand Down
55 changes: 40 additions & 15 deletions Package/Core/Promises/Internal/Progress/ProgressMergeInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,57 @@ void IMultiHandleablePromise.ReturnPassthroughs(ValueLinkedStack<PromisePassThro

partial class MergePromise<TResult>
{
internal sealed override PromiseRefBase AddProgressWaiter(short promiseId, out HandleablePromiseBase previousWaiter, ref ProgressHookupValues progressHookupValues)
protected void SetProgressValuesAndGetPrevious(ref ProgressHookupValues progressHookupValues, bool reportUnresolved)
{
ThrowIfInPool(this);
// Retain this until we've hooked up progress to the passthroughs. This is necessary because we take the passthroughs, then put back the ones that are unable to be hooked up.
InterlockedAddWithUnsignedOverflowCheck(ref _retainCounter, 1);
progressHookupValues.RegisterHandler(this);
ProgressMerger.MaybeHookup(this, _completeProgress, _passThroughs.TakeAndClear(), ref progressHookupValues, reportUnresolved);
}

internal override PromiseRefBase AddProgressWaiter(short promiseId, out HandleablePromiseBase previousWaiter, ref ProgressHookupValues progressHookupValues)
{
var promiseSingleAwait = AddWaiterImpl(promiseId, progressHookupValues.ProgressListener, out previousWaiter);
if (previousWaiter == PendingAwaitSentinel.s_instance)
{
SetProgressValuesAndGetPrevious(ref progressHookupValues);
SetProgressValuesAndGetPrevious(ref progressHookupValues, false);
}
return promiseSingleAwait;
}

new private void SetProgressValuesAndGetPrevious(ref ProgressHookupValues progressHookupValues)
internal override bool TryHookupProgressListenerAndGetPrevious(ref ProgressHookupValues progressHookupValues)
{
ThrowIfInPool(this);
// Retain this until we've hooked up progress to the passthroughs. This is necessary because we take the passthroughs, then put back the ones that are unable to be hooked up.
InterlockedAddWithUnsignedOverflowCheck(ref _retainCounter, 1);
progressHookupValues.RegisterHandler(this);
ProgressMerger.MaybeHookup(this, _completeProgress, _passThroughs.TakeAndClear(), ref progressHookupValues);
if (CompareExchangeWaiter(progressHookupValues.ProgressListener, progressHookupValues._expectedWaiter) != progressHookupValues._expectedWaiter)
{
progressHookupValues._previous = null;
return false;
}
SetProgressValuesAndGetPrevious(ref progressHookupValues, false);
return true;
}
}

partial class MergeSettledPromise<TResult>
{
internal override PromiseRefBase AddProgressWaiter(short promiseId, out HandleablePromiseBase previousWaiter, ref ProgressHookupValues progressHookupValues)
{
var promiseSingleAwait = AddWaiterImpl(promiseId, progressHookupValues.ProgressListener, out previousWaiter);
if (previousWaiter == PendingAwaitSentinel.s_instance)
{
SetProgressValuesAndGetPrevious(ref progressHookupValues, true);
}
return promiseSingleAwait;
}

internal override sealed bool TryHookupProgressListenerAndGetPrevious(ref ProgressHookupValues progressHookupValues)
internal override bool TryHookupProgressListenerAndGetPrevious(ref ProgressHookupValues progressHookupValues)
{
if (CompareExchangeWaiter(progressHookupValues.ProgressListener, progressHookupValues._expectedWaiter) != progressHookupValues._expectedWaiter)
{
progressHookupValues._previous = null;
return false;
}
SetProgressValuesAndGetPrevious(ref progressHookupValues);
SetProgressValuesAndGetPrevious(ref progressHookupValues, true);
return true;
}
}
Expand Down Expand Up @@ -115,14 +139,15 @@ private static ProgressMerger GetOrCreate()
: obj.UnsafeAs<ProgressMerger>();
}

private static ProgressMerger GetOrCreate(PromiseRefBase targetMergePromise, ulong completedProgress, ulong expectedProgress, ValueLinkedStack<PromisePassThrough> passThroughs)
private static ProgressMerger GetOrCreate(PromiseRefBase targetMergePromise, ulong completedProgress, ulong expectedProgress, ValueLinkedStack<PromisePassThrough> passThroughs, bool reportUnresolved)
{
var merger = GetOrCreate();
merger._next = null;
merger._targetMergePromise = targetMergePromise;
merger._passThroughs = passThroughs;
merger._currentProgress = completedProgress;
merger._divisorReciprocal = 1d / expectedProgress;
merger._reportUnresolved = reportUnresolved;
#if PROMISE_DEBUG || PROTO_PROMISE_DEVELOPER_MODE
merger._disposed = false;
#endif
Expand All @@ -138,7 +163,7 @@ private void Dispose()
ObjectPool.MaybeRepool(this);
}

internal static void MaybeHookup(PromiseRefBase targetMergePromise, ulong completedProgress, ValueLinkedStack<PromisePassThrough> passThroughs, ref ProgressHookupValues progressHookupValues)
internal static void MaybeHookup(PromiseRefBase targetMergePromise, ulong completedProgress, ValueLinkedStack<PromisePassThrough> passThroughs, ref ProgressHookupValues progressHookupValues, bool reportUnresolved)
{
progressHookupValues._previous = null;
ushort depth = targetMergePromise.Depth;
Expand All @@ -155,7 +180,7 @@ internal static void MaybeHookup(PromiseRefBase targetMergePromise, ulong comple
{
expectedProgress += pt.Depth + 1u;
}
var merger = GetOrCreate(targetMergePromise, completedProgress, expectedProgress, passThroughs);
var merger = GetOrCreate(targetMergePromise, completedProgress, expectedProgress, passThroughs, reportUnresolved);
progressHookupValues._currentProgress = completedProgress * merger._divisorReciprocal;

progressHookupValues.AddPassthrough(merger);
Expand Down Expand Up @@ -236,10 +261,10 @@ internal void Handle(float oldProgress, float maxProgress, PromiseRefBase handle
var progressReportValues = new ProgressReportValues(null, this, lockedObject, maxProgress);
UpdateProgress(oldProgress, ref progressReportValues);

// We only report the progress if the handler was not the last completed, and the state is resolved.
// We only report the progress if the handler was not the last completed, and the state is resolved (or the merge type is All/MergeSettled).
// We check the more common case first.
bool isComplete = InterlockedAddWithUnsignedOverflowCheck(ref _retainCounter, -1) == 0;
if (!isComplete & state == Promise.State.Resolved)
if (!isComplete & (_reportUnresolved | state == Promise.State.Resolved))
{
progressReportValues.ReportProgressToAllListeners();
}
Expand Down
1 change: 1 addition & 0 deletions Package/Core/Promises/Internal/PromiseFieldsInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ partial class ProgressMerger : ProgressPassThrough
private double _currentProgress;
private double _divisorReciprocal; // 1 / expectedProgress since multiplying is faster than dividing.
volatile private int _retainCounter;
private bool _reportUnresolved;
// The passthroughs are only stored during the hookup.
private ValueLinkedStack<PromisePassThrough> _passThroughs;
#if PROMISE_DEBUG || PROTO_PROMISE_DEVELOPER_MODE
Expand Down
Loading

0 comments on commit 3be71a8

Please sign in to comment.