Skip to content

Commit

Permalink
Merge pull request #482 from timcassell/fix-promisenew-racecond
Browse files Browse the repository at this point in the history
Fix race condition with `Promise.New`
  • Loading branch information
timcassell authored Oct 27, 2024
2 parents 177ddfd + 4f20dba commit b7e0d78
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 2 deletions.
12 changes: 10 additions & 2 deletions Package/Core/Promises/Internal/DeferredInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,14 @@ private DeferredNewPromise() { }

internal override void MaybeDispose()
{
Dispose();
ObjectPool.MaybeRepool(this);
// It is theoretically possible for this to be completed from the callback, and then the callback throws,
// causing this to attempt to complete again. The thread could be starved while another thread
// re-uses this object from the pool. This interlocked operation protects against that.
if (InterlockedAddWithUnsignedOverflowCheck(ref _disposeCounter, -1) == 0)
{
Dispose();
ObjectPool.MaybeRepool(this);
}
}

[MethodImpl(InlineOption)]
Expand All @@ -166,6 +172,7 @@ internal static DeferredNewPromise<TResult, TDelegate> GetOrCreate(TDelegate run
{
var promise = GetOrCreate();
promise.Reset();
promise._disposeCounter = 2;
promise._runner = runner;
return promise;
}
Expand Down Expand Up @@ -253,6 +260,7 @@ private void Run()
}
}
ClearCurrentInvoker();
MaybeDispose();
}
}
} // class PromiseRef
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 @@ -174,6 +174,7 @@ partial class DeferredPromise<TResult> : DeferredPromiseBase<TResult>
partial class DeferredNewPromise<TResult, TDelegate> : DeferredPromise<TResult>
where TDelegate : IDelegateNew<TResult>
{
private int _disposeCounter;
private TDelegate _runner;
}

Expand Down

0 comments on commit b7e0d78

Please sign in to comment.