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

Remove workaround for ThreadPool not working #7080

Closed
migueldeicaza opened this issue Sep 23, 2019 · 11 comments · Fixed by #17082
Closed

Remove workaround for ThreadPool not working #7080

migueldeicaza opened this issue Sep 23, 2019 · 11 comments · Fixed by #17082
Labels
enhancement The issue or pull request is an enhancement iOS Issues affecting Xamarin.iOS
Milestone

Comments

@migueldeicaza
Copy link
Contributor

Xamarin on iOS currently has a workaround for the Mono Thread Pool not working:

#5463

That workaround is necessary because the Mono's ThreadPool stops working after the app is suspended for 10 seconds:

https://xamarin.github.io/bugzilla-archives/58/58633/bug.html#c7

The workaround effectively kills all background support from Xamarin.iOS.

There is a repro that shows this problem in action (but might require disabling the incorrect bandaid that was put in place):

#5333

@steveisok
Copy link
Contributor

steveisok commented Sep 24, 2019

I undid the band-aid and built against mono-2019-06, using the sample provided by #5333. After ~15-20 different tries, I couldn't reproduce the problem. Each time after 10+ seconds, the threadpool threads would kick back up and resume normal execution (Http requests too).

Has anyone else been able to reproduce? If so, what device(s), versions, etc?

@marek-safar
Copy link
Contributor

@steveisok did you put your app into background mode on the device?

The workaround effectively kills all background support from Xamarin.iOS.

@migueldeicaza could you be more specific on this^ ?

@steveisok
Copy link
Contributor

@marek-safar Yeah, I'd swipe up and wait at least 10 seconds (often longer). In addition, I opened other apps, did something, and then went back.

@migueldeicaza
Copy link
Contributor Author

Yes, this means that the NSUrlSession which is an API that can perform downloads in the background, even if the application is stopped does not work. So the hack cancels the downloads.

@steveisok perhaps the heuristics for the OS have changed, and the app is not backgrounded, might be worth checking.

@mandel-macaque can provide more details on the side effects.

@lambdageek
Copy link
Member

lambdageek commented Sep 24, 2019

There's a similar issue on Android on at least one device (after a while, a background service can't schedule new Tasks to run). I've been looking at this piece of code:
https://github.com/mono/mono/blob/d371432a1030db86d1ed6afb9bc174fb1587191f/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs#L649-L654
My theory is that when the app is in the background we have requests backing up somehow and we end up with insufficient number of calls to ThreadPool.RequestWorkerThread - that icall ends up here:
https://github.com/mono/mono/blob/da02f1330f1dd872f1e723a1f6e35997979df27c/mono/metadata/threadpool-worker-default.c#L340-L349
and the call to work_item_push is critical because that's the code that signals a worker to unpark and to try and process a job from its queue.
If we somehow end up with numOutstandingThreadRequests >= ThreadPoolGlobals.processorCount new jobs wouldn't run.

This EnsureThreadRequested/MarkThreadRequestSatisfied code is pretty critical - CoreCLR had to revert some changes (so they're back to matching referencesource) when they tried to optimize it: dotnet/coreclr@b8dda0c

The android device where I saw this has processorCount = 2. I'm trying to repro on desktop by hardcoding 2 for the count in a hacked up corlib.

@chamons chamons added iOS Issues affecting Xamarin.iOS enhancement The issue or pull request is an enhancement labels Sep 25, 2019
@chamons chamons added this to the Future milestone Sep 25, 2019
@lambdageek
Copy link
Member

To followup on my theory that ThreadPool.RequestWorkerThread isn't getting called enough.
I changed this loop to while (true) instead https://github.com/mono/mono/blob/b45d0a108474bafc56d853b74d89ac82800a38f8/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs#L648-L658

and also added some logging to note whether we ever call it when count >= ThreadPoolGlobals.processorCount and:

  1. before the app is backgrounded, count < ThreadPoolGlobals.processorCount
  2. after the app is backgrounded:
    a. I get my warning that count >= ThreadPoolGlobals.processorCount
    b. the task starts running.

So on the particular Android device that I'm watching, it certainly seems like we get into a situation where the native threadpool machinery was flooded with requests (count >= processorCount) but it s workers didn't unpark or start up to process them, and so numOutstandingThreadRequests never got decremented and as a result queueing new Tasks doesn't actually cause the threadpool to wake up and pick up work anymore.

I'm planning to look into a couple of things:

  1. What the heck is going in the unmanaged threadpool code
  2. What exactly is count < processorCount protecting against?
  3. Does CoreCLR do something different with ThreadPool.RequestWorkerThread? In Mono it seems pretty critical to call this periodically to nudge the unmanaged code to actually try to pick up work items. Maybe it doesn't do that in CoreCLR and the threadpool doesn't idle the same way. (Or maybe they just didn't consider the OS suspending the application since desktop OSes probably don't do that the same way).

But maybe we should check in something like:

#if MONO && MOBILE
    while (true) {
#else
   while (count < ThreadPoolGlobals.processorCount) {
#endif

And just see what happens?

@lambdageek
Copy link
Member

Just a brief update. My previous comment is not the direction we ended up taking for the possibly-related Android issue.

The fix we ultimately ended up going with is mono/mono#17927. Once backports of that PR are available for xamarin.ios, we could investigate removing the workaround in XI.

Although, given that we haven't been able to reproduce the issue recently, we will first need to identify a way to induce the bad threadpool behavior on an ios device.

@chamons
Copy link
Contributor

chamons commented Mar 27, 2020

@lambdageek - Git suggests that mono 2020-02 has this (via b6a351c3308). Could we look at removing the work around now?

@akoeplinger
Copy link
Member

@chamons the PR also landed in 2019-10 and 2019-12 so you should be able to already try it on your stable bits.

mandel-macaque added a commit to mandel-macaque/xamarin-macios that referenced this issue Apr 6, 2020
…andler for thethreadpool.

When an application was moved the the background, the thread pool from
mono would be left in an unknonw state, making applications to stale
(https://xamarin.github.io/bugzilla-archives/58/58633/bug.html#c7).

This work was added in xamarin#5463

We now set the default behaviour to skip the workaround to see if the
new provided mono works as expected. We do not fully remove the
workaround because we need some real world testing.

If the new ThreadPool from mono does not work as expected we do provide
a property to re-add the workaround. The BypassBackgroundSessionCheck
can be set to false to allow users get it back.

The following is an example usage of the API:

```csharp
// create your own handler instance rather than using the one provided
by default.
var handler = new NSUrlSessionHandler() {
  BypassBackgroundSessionCheck = false, // readd the hack
};
var httpClient = new HttpClient (handler); // use the handler with the hack
```

This is a partial fix for xamarin#7080
@chamons
Copy link
Contributor

chamons commented Apr 6, 2020

The Xamarin iOS and Mac team would like some customer testing with the this fix.

Here are the instructions:

  1. On latest stable (or preview) Xamarin.iOS / Mac modify your HttpClient creation to the following:
var handler = new NSUrlSessionHandler () { BypassBackgroundSessionCheck = true };
var client = new HttpClient (handler);
  1. Test your networking, in particular by back-grounding and for-grounding your application in various network conditions (wi-fi, cellular, etc).
  2. If you run into issues, change BypassBackgroundSessionCheck back to false (the default) and try to reproduce.
  3. Report any differences here in a comment. In theory, they should behave exactly the same now.

We'd like to change the default in future versions (#8296) and hearing from some customers would be very helpful.

mandel-macaque added a commit that referenced this issue Apr 6, 2020
…andler for thethreadpool. (#8296)

When an application was moved the the background, the thread pool from
mono would be left in an unknonw state, making applications to stale
(https://xamarin.github.io/bugzilla-archives/58/58633/bug.html#c7).

This work was added in #5463

We now set the default behaviour to skip the workaround to see if the
new provided mono works as expected. We do not fully remove the
workaround because we need some real world testing.

If the new ThreadPool from mono does not work as expected we do provide
a property to re-add the workaround. The BypassBackgroundSessionCheck
can be set to false to allow users get it back.

The following is an example usage of the API:

```csharp
// create your own handler instance rather than using the one provided
by default.
var handler = new NSUrlSessionHandler() {
  BypassBackgroundSessionCheck = false, // readd the hack
};
var httpClient = new HttpClient (handler); // use the handler with the hack
```

This is a partial fix for #7080
@rolfbjarne
Copy link
Member

Looks like we can remove the workaround, since we haven't gotten any feedback after turning it off by default.

Scheduling it for .NET 8.

@rolfbjarne rolfbjarne modified the milestones: Future, .NET 8 Sep 27, 2022
rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Dec 19, 2022
…amarin#7080.

Completely remove a workaround for an issue with the thread pool in Mono.
We've previously turned this workaround off by default, and we got no reports
of any problems.

Fixes xamarin#7080.
rolfbjarne added a commit that referenced this issue Dec 21, 2022
…7080. (#17082)

Completely remove a workaround for an issue with the thread pool in Mono.
We've previously turned this workaround off by default, and we got no reports
of any problems.

Fixes #7080.
@ghost ghost locked as resolved and limited conversation to collaborators Jan 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement The issue or pull request is an enhancement iOS Issues affecting Xamarin.iOS
Projects
None yet
7 participants