Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task calls SynchronizationContext.Post on cancelling #12421

Closed
AndreyFromGomel opened this issue Jan 14, 2019 · 7 comments

Comments

@AndreyFromGomel
Copy link

@AndreyFromGomel AndreyFromGomel commented Jan 14, 2019

After updating Visual Studio from version 15.7 to 15.9 we noticed regression of our Android application. Investigation showed that for mono 5.10.1 and 5.14.0 following code works different:

        private async void StartButton_OnClicked(object sender, EventArgs e)
        {
            _tcs = new TaskCompletionSource<bool>();
            _cts = new CancellationTokenSource();
            Label.Text = "Started";

            _cts.Token.Register(() => _tcs.TrySetCanceled());
            try
            {
                await _tcs.Task;
            }
            catch (OperationCanceledException)
            {
                Label.Text += " -> OCE ";
                Console.WriteLine("Catching OperationCanceledException");
            }
        }

        private void StopButton_OnClicked(object sender, EventArgs e)
        {
            _cts.Cancel();
            Label.Text += " -> SBC ";
            Console.WriteLine("Stop button clicked");
        }

Further investigation revealed that mono 5.14.0 calls SynchronizationContext.Post method while 5.10.1 does not.
I created repository with POC: https://github.com/AndreyFromGomel/TestSyncContext

  1. Launch
  2. Click Start
  3. Click Stop

Output for mono 5.14.0:

Stop button clicked
Catching OperationCanceledException

Output for mono 5.10.1:

Catching OperationCanceledException
Stop button clicked

The same behavior for Xamarin.iOS (12.2), Xamarin.Android (9.1) and Xamarin.Mac (5.2) with mono 5.14.0.
My question: is this expected behavior or this is issue and will be fixed in further mono releases?

@EgorBo

This comment has been minimized.

Copy link
Member

@EgorBo EgorBo commented Jan 25, 2019

@AndreyFromGomel "SBC -> OCE" (mono 5.14) behavior looks more reasonable, doesn't it? (WPF+net45 behavior).
I am not sure what was the reason of this change

Further investigation revealed that mono 5.14.0 calls SynchronizationContext.Post method while 5.10.1 does not.

How did you log that event, did you override SynchronizationContext.SetSynchronizationContext? I don't see any redundant Post after I click "Start" button.

@AndreyFromGomel

This comment has been minimized.

Copy link
Author

@AndreyFromGomel AndreyFromGomel commented Jan 28, 2019

@EgorBo First of all thank you for your reply.

"SBC -> OCE" (mono 5.14) behavior looks more reasonable, doesn't it? (WPF+net45 behavior).

I'm agree with you that it is more reasonable, but if we check this behavior on Windows Forms (.NET 4.6.1) we get "OCE -> SBC" (like mono 5.10.1).

How did you log that event, did you override SynchronizationContext.SetSynchronizationContext?

Yes, I set my SynchronizationContext implementation via SynchronizationContext.SetSynchronizationContext.

I don't see any redundant Post after I click "Start" button.

Post call is not redundant in current implementation, but previously Task cancellation didn't call it. Is there any chance that current behavior (mono 5.14) will be rolled back to how it worked before (mono 5.10.1)?

@EgorBo

This comment has been minimized.

Copy link
Member

@EgorBo EgorBo commented Jan 28, 2019

@AndreyFromGomel I'll take a look, I am not sure the problem in Mono though. I tried to reproduce this case in a console app with hand-made sync context but couldn't reproduce any difference between mono-5.10 and mono-5.14. A while ago we replaced a lot of related stuff with .NET Core sources but as far as I remember it happened before mono-5.10 but I'll check.

@EgorBo

This comment has been minimized.

Copy link
Member

@EgorBo EgorBo commented Jan 29, 2019

Alright, so the behavior has changed exactly once we switched to the CoreRT-based impl of Task-related stuff. For some reason TrySetCancel indeed triggers SyncContext.Post, I suspect it's CoreRT-specific issue, can't reproduce it on .NET Core.

@EgorBo

This comment has been minimized.

Copy link
Member

@EgorBo EgorBo commented Feb 4, 2019

@AndreyFromGomel as a temp workaround you may try to override CreateCopy() in your custom sync context.

marek-safar added a commit that referenced this issue Feb 5, 2019
…ntext.Capture (#12780)

Fixes #12421
When we switched to CoreFX/CoreRT sources (mostly CoreRT) for System.Threading we had to keep old reference-source based `ExecutionContext`, `CancellationToken` and `CancellationTokenSource`.  In the bug above the redundant `SynchronizationContext.Post` was triggered here:
https://github.com/mono/corert/blob/1b7d4a1e4bd79305905338827cc41eb8303364f0/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs#L404

it was expected to be "myCustomSyncContext == myCustomSyncContext" but instead it was "myCustomSyncContext == empty SynchronizationContext instance".
That empty instance was allocated in `CreateCopy` which I am trying to delete in this PR.
That `.CreateCopy()` always creates `SynchronizationContext` instance (see [here](https://github.com/mono/mono/blob/master/mcs/class/referencesource/mscorlib/system/threading/synchronizationcontext.cs#L363-L368), but it's expected) so `==` is `false` in our case => it goes to the "Post" path instead of "Execute synchronously". 
PS: .NET Core sources do not call `CreateCopy anywhere.

Backport of #12774.

/cc @marek-safar @EgorBo
marek-safar added a commit that referenced this issue Feb 5, 2019
…ntext.Capture (#12779)

Fixes #12421
When we switched to CoreFX/CoreRT sources (mostly CoreRT) for System.Threading we had to keep old reference-source based `ExecutionContext`, `CancellationToken` and `CancellationTokenSource`.  In the bug above the redundant `SynchronizationContext.Post` was triggered here:
https://github.com/mono/corert/blob/1b7d4a1e4bd79305905338827cc41eb8303364f0/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs#L404

it was expected to be "myCustomSyncContext == myCustomSyncContext" but instead it was "myCustomSyncContext == empty SynchronizationContext instance".
That empty instance was allocated in `CreateCopy` which I am trying to delete in this PR.
That `.CreateCopy()` always creates `SynchronizationContext` instance (see [here](https://github.com/mono/mono/blob/master/mcs/class/referencesource/mscorlib/system/threading/synchronizationcontext.cs#L363-L368), but it's expected) so `==` is `false` in our case => it goes to the "Post" path instead of "Execute synchronously". 
PS: .NET Core sources do not call `CreateCopy anywhere.

Backport of #12774.

/cc @marek-safar @EgorBo
@AndreyFromGomel

This comment has been minimized.

Copy link
Author

@AndreyFromGomel AndreyFromGomel commented Feb 5, 2019

@EgorBo Thank you for your effort to fix this issue (and workaround). Do you know any plans when version with fix will be released?

@marek-safar

This comment has been minimized.

Copy link
Member

@marek-safar marek-safar commented Feb 6, 2019

@AndreyFromGomel the fix didn't make it to the next release and will be included in the version after that

jonpryor added a commit to xamarin/xamarin-android that referenced this issue Apr 24, 2019
Bumps to mono/api-snapshot@ae01378
Bumps to mono/reference-assemblies@e5173a5
Bumps to mono/bockbuild@d30329d
Bumps to mono/boringssl@3d87996
Bumps to mono/corefx@72f7d76
Bumps to mono/corert@1b7d4a1
Bumps to mono/helix-binaries@7e893ea
Bumps to mono/illinker-test-assets@f21ff68
Bumps to mono/linker@13d864e
Bumps to mono/llvm@1aaaaa5 [mono]
Bumps to mono/llvm@2c2cffe [xamarin-android]
Bumps to mono/NUnitLite@0029561
Bumps to mono/roslyn-binaries@0bbc9b4
Bumps to mono/xunit-binaries@8f6e62e

	$ git diff --shortstat 886c4901..e66c7667      # mono
        3597 files changed, 350850 insertions(+), 91128 deletions(-)
	$ git diff --shortstat 349752c464c5fc93b32e7d45825f2890c85c8b7d..2c2cffedf01e0fe266b9aaad2c2563e05b750ff4
	 240 files changed, 18562 insertions(+), 6581 deletions(-)

Context: dotnet/coreclr#22046

Fixes: CVE 2018-8292 on macOS
Fixes: http://work.devdiv.io/737323
Fixes: dotnet/corefx#33965
Fixes: dotnet/standard#642
Fixes: mono/mono#6997
Fixes: mono/mono#7326
Fixes: mono/mono#7517
Fixes: mono/mono#7750
Fixes: mono/mono#7859
Fixes: mono/mono#8360
Fixes: mono/mono#8460
Fixes: mono/mono#8766
Fixes: mono/mono#8922
Fixes: mono/mono#9418
Fixes: mono/mono#9507
Fixes: mono/mono#9951
Fixes: mono/mono#10024
Fixes: mono/mono#10030
Fixes: mono/mono#10038
Fixes: mono/mono#10448
Fixes: mono/mono#10735
Fixes: mono/mono#10735
Fixes: mono/mono#10737
Fixes: mono/mono#10743
Fixes: mono/mono#10834
Fixes: mono/mono#10837
Fixes: mono/mono#10838
Fixes: mono/mono#10863
Fixes: mono/mono#10945
Fixes: mono/mono#11020
Fixes: mono/mono#11021
Fixes: mono/mono#11021
Fixes: mono/mono#11049
Fixes: mono/mono#11091
Fixes: mono/mono#11095
Fixes: mono/mono#11123
Fixes: mono/mono#11138
Fixes: mono/mono#11146
Fixes: mono/mono#11202
Fixes: mono/mono#11214
Fixes: mono/mono#11317
Fixes: mono/mono#11326
Fixes: mono/mono#11378
Fixes: mono/mono#11385
Fixes: mono/mono#11478
Fixes: mono/mono#11479
Fixes: mono/mono#11488
Fixes: mono/mono#11489
Fixes: mono/mono#11527
Fixes: mono/mono#11529
Fixes: mono/mono#11596
Fixes: mono/mono#11603
Fixes: mono/mono#11613
Fixes: mono/mono#11623
Fixes: mono/mono#11663
Fixes: mono/mono#11681
Fixes: mono/mono#11684
Fixes: mono/mono#11693
Fixes: mono/mono#11697
Fixes: mono/mono#11779
Fixes: mono/mono#11809
Fixes: mono/mono#11858
Fixes: mono/mono#11895
Fixes: mono/mono#11898
Fixes: mono/mono#11898
Fixes: mono/mono#11965
Fixes: mono/mono#12182
Fixes: mono/mono#12193
Fixes: mono/mono#12218
Fixes: mono/mono#12235
Fixes: mono/mono#12263
Fixes: mono/mono#12307
Fixes: mono/mono#12331
Fixes: mono/mono#12362
Fixes: mono/mono#12374
Fixes: mono/mono#12402
Fixes: mono/mono#12421
Fixes: mono/mono#12461
Fixes: mono/mono#12479
Fixes: mono/mono#12479
Fixes: mono/mono#12552
Fixes: mono/mono#12603
Fixes: mono/mono#12747
Fixes: mono/mono#12831
Fixes: mono/mono#12843
Fixes: mono/mono#12881
Fixes: mono/mono#13030
Fixes: mono/mono#13284
Fixes: mono/mono#13297
Fixes: mono/mono#13455
Fixes: mono/mono#13460
Fixes: mono/mono#13478
Fixes: mono/mono#13479
Fixes: mono/mono#13522
Fixes: mono/mono#13607
Fixes: mono/mono#13610
Fixes: mono/mono#13610
Fixes: mono/mono#13639
Fixes: mono/mono#13672
Fixes: mono/mono#13834
Fixes: mono/mono#13878
Fixes: mono/mono#6352
Fixes: mono/monodevelop#6898
Fixes: xamarin/maccore#1069
Fixes: xamarin/maccore#1407
Fixes: xamarin/maccore#604
Fixes: xamarin/xamarin-macios#4984
Fixes: xamarin/xamarin-macios#5289
Fixes: xamarin/xamarin-macios#5363
Fixes: xamarin/xamarin-macios#5381
Fixes: https://issuetracker.unity3d.com/issues/editor-crashes-with-g-logv-when-entering-play-mode-with-active-flowcanvas-script
steveisok added a commit that referenced this issue Sep 23, 2019
Restores previous ExecutionContext Capture behavior where we were copying a new SynchronizationContext as opposed to a reference to the existing one.

The old behavior caused SynchronizationContextAwaitTaskContinuations to not post to a SynchronizationContext.

Fixes #16759

Reverts a fix for #12421
steveisok added a commit that referenced this issue Sep 23, 2019
Restores previous ExecutionContext Capture behavior where we were copying a new SynchronizationContext as opposed to a reference to the existing one.

The old behavior caused SynchronizationContextAwaitTaskContinuations to not post to a SynchronizationContext.

Fixes #16759

Reverts a fix for #12421

Backport of #16945
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.