Schedule tasks with TaskCreationOptions.HideScheduler #257
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
When Task.Factory.StartNew(...), Task.ContinueWith(...), etc. are used without specifying a TaskScheduler, TaskScheduler.Current is used. Since tests are being scheduled to a TaskScheduler that wraps the MaxConcurrencySyncContext, that means that if a test itself schedules another task using one of these methods without specifying a scheduler, that task will be scheduled back to the same MaxConcurrencySyncContext. In some cases that isn't problematic; however, if a synchronous test schedules such a task and then synchronously blocks waiting for such a task to complete, it's possible for the test to deadlock, e.g. if the concurrency level is 1 such that there's only one worker and that worker is blocked in the test waiting for the queued task to complete, but the queued task will never complete because it could only complete if the worker completed executing the blocked task so it could pick up the sub-task.
A solution is to specify the TaskCreationOptions.HideScheduler flag when xunit queues its RunTestCollectionAsync task. By adding this option, that task will be scheduled to the MaxConcurrencySyncContext scheduler, but inside of that task, TaskScheduler.Current will return TaskScheduler.Default rather than the custom scheduler, such that any tasks user code creates in the test won't be forced back to xunit's scheduler.