Skip to content

Commit

Permalink
Merge pull request #807 from microsoft/dev/lifengl/preventMainThreadQ…
Browse files Browse the repository at this point in the history
…ueueTwice

Prevent going through UI thread pending queue twice
  • Loading branch information
lifengl committed Mar 18, 2021
2 parents a0a24d0 + 47f5b2a commit f116ea0
Showing 1 changed file with 34 additions and 56 deletions.
90 changes: 34 additions & 56 deletions src/Microsoft.VisualStudio.Threading/ReentrantSemaphore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,10 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
// Use ConfiguredAwaitRunInline() as ConfigureAwait(true) will
// deadlock due to not being inside a JTF.RunAsync().
Task<AsyncSemaphore.Releaser>? releaserTask = this.semaphore.EnterAsync(cancellationToken);

// Yield to prevent running on the stack that released the semaphore.
mustYield = !releaserTask.IsCompleted;

releaser = await releaserTask.ConfigureAwaitRunInline();
}
else
Expand All @@ -425,17 +428,11 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
if (resumeOnMainThread)
{
// Return to the main thread if we started there.
await joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: mustYield, cancellationToken);
}
else
{
await TaskScheduler.Default;
}

if (mustYield)
{
// Yield to prevent running on the stack that released the semaphore.
await Task.Yield();
await TaskScheduler.Default.SwitchTo(alwaysYield: mustYield);
}
}

Expand Down Expand Up @@ -506,7 +503,10 @@ public override async Task ExecuteAsync(Func<Task> operation, CancellationToken
// Use ConfiguredAwaitRunInline() as ConfigureAwait(true) will
// deadlock due to not being inside a JTF.RunAsync().
Task<AsyncSemaphore.Releaser>? releaserTask = this.semaphore.EnterAsync(cancellationToken);

// Yield to prevent running on the stack that released the semaphore.
mustYield = !releaserTask.IsCompleted;

releaser = await releaserTask.ConfigureAwaitRunInline();
}
else
Expand All @@ -524,17 +524,11 @@ await this.ExecuteCoreAsync(async delegate
if (resumeOnMainThread)
{
// Return to the main thread if we started there.
await joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: mustYield, cancellationToken);
}
else
{
await TaskScheduler.Default;
}

if (mustYield)
{
// Yield to prevent running on the stack that released the semaphore.
await Task.Yield();
await TaskScheduler.Default.SwitchTo(alwaysYield: mustYield);
}
}

Expand Down Expand Up @@ -585,6 +579,8 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
// Use ConfiguredAwaitRunInline() as ConfigureAwait(true) will
// deadlock due to not being inside a JTF.RunAsync().
Task<AsyncSemaphore.Releaser>? releaserTask = this.semaphore.EnterAsync(cancellationToken);

// Yield to prevent running on the stack that released the semaphore.
mustYield = !releaserTask.IsCompleted;
releaser = await releaserTask.ConfigureAwaitRunInline();
}
Expand All @@ -603,17 +599,11 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
if (resumeOnMainThread)
{
// Return to the main thread if we started there.
await joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: mustYield, cancellationToken);
}
else
{
await TaskScheduler.Default;
}

if (mustYield)
{
// Yield to prevent running on the stack that released the semaphore.
await Task.Yield();
await TaskScheduler.Default.SwitchTo(alwaysYield: mustYield);
}
}

Expand Down Expand Up @@ -711,7 +701,10 @@ public override async Task ExecuteAsync(Func<Task> operation, CancellationToken
// Use ConfiguredAwaitRunInline() as ConfigureAwait(true) will
// deadlock due to not being inside a JTF.RunAsync().
Task<AsyncSemaphore.Releaser>? releaserTask = this.semaphore.EnterAsync(cancellationToken);

// Yield to prevent running on the stack that released the semaphore.
mustYield = !releaserTask.IsCompleted;

releaser = await releaserTask.ConfigureAwaitRunInline();
}
else
Expand All @@ -736,17 +729,11 @@ await this.ExecuteCoreAsync(async delegate
if (resumeOnMainThread)
{
// Return to the main thread if we started there.
await joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: mustYield, cancellationToken);
}
else
{
await TaskScheduler.Default;
}

if (mustYield)
{
// Yield to prevent running on the stack that released the semaphore.
await Task.Yield();
await TaskScheduler.Default.SwitchTo(alwaysYield: mustYield);
}
}

Expand Down Expand Up @@ -827,7 +814,10 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
// Use ConfiguredAwaitRunInline() as ConfigureAwait(true) will
// deadlock due to not being inside a JTF.RunAsync().
Task<AsyncSemaphore.Releaser>? releaserTask = this.semaphore.EnterAsync(cancellationToken);

// Yield to prevent running on the stack that released the semaphore.
mustYield = !releaserTask.IsCompleted;

releaser = await releaserTask.ConfigureAwaitRunInline();
}
else
Expand All @@ -852,17 +842,11 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
if (resumeOnMainThread)
{
// Return to the main thread if we started there.
await joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: mustYield, cancellationToken);
}
else
{
await TaskScheduler.Default;
}

if (mustYield)
{
// Yield to prevent running on the stack that released the semaphore.
await Task.Yield();
await TaskScheduler.Default.SwitchTo(alwaysYield: mustYield);
}
}

Expand Down Expand Up @@ -976,7 +960,10 @@ public override async Task ExecuteAsync(Func<Task> operation, CancellationToken
// Use ConfiguredAwaitRunInline() as ConfigureAwait(true) will
// deadlock due to not being inside a JTF.RunAsync().
Task<AsyncSemaphore.Releaser>? releaserTask = this.semaphore.EnterAsync(cancellationToken);

// Yield to prevent running on the stack that released the semaphore.
mustYield = !releaserTask.IsCompleted;

releaser = await releaserTask.ConfigureAwaitRunInline();
}
else
Expand All @@ -1000,17 +987,11 @@ await this.ExecuteCoreAsync(async delegate
if (resumeOnMainThread)
{
// Return to the main thread if we started there.
await joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: mustYield, cancellationToken);
}
else
{
await TaskScheduler.Default;
}

if (mustYield)
{
// Yield to prevent running on the stack that released the semaphore.
await Task.Yield();
await TaskScheduler.Default.SwitchTo(alwaysYield: mustYield);
}
}

Expand Down Expand Up @@ -1072,7 +1053,10 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
// Use ConfiguredAwaitRunInline() as ConfigureAwait(true) will
// deadlock due to not being inside a JTF.RunAsync().
Task<AsyncSemaphore.Releaser>? releaserTask = this.semaphore.EnterAsync(cancellationToken);

// Yield to prevent running on the stack that released the semaphore.
mustYield = !releaserTask.IsCompleted;

releaser = await releaserTask.ConfigureAwaitRunInline();
}
else
Expand All @@ -1096,17 +1080,11 @@ public override async ValueTask<T> ExecuteAsync<T>(Func<ValueTask<T>> operation,
if (resumeOnMainThread)
{
// Return to the main thread if we started there.
await joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: mustYield, cancellationToken);
}
else
{
await TaskScheduler.Default;
}

if (mustYield)
{
// Yield to prevent running on the stack that released the semaphore.
await Task.Yield();
await TaskScheduler.Default.SwitchTo(alwaysYield: mustYield);
}
}

Expand Down

0 comments on commit f116ea0

Please sign in to comment.