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

Add thread locking to the UWP gamepads dictionary #7655

Merged
merged 1 commit into from
Apr 26, 2022

Conversation

squarebananas
Copy link
Contributor

This pull request is to fix a potential thread issue that may occur when a gamepad is disconnected.

WGI.Gamepad.GamepadAdded and WGI.Gamepad.GamepadRemoved are adding and removing gamepads from a different thread to the game tick where PlatformGetState is likely to be called. If the timing was right a disconnected gamepad could be removed from the dictionary while also accessing it for GetState/GetCapabilities.

This can be prevented by adding a lock statement around each use of the gamepads dictionary.

Add thread locking around the gamepads dictionary
@nkast
Copy link
Contributor

nkast commented Feb 23, 2022

Locking is not necessary if you replace the dictionary and linq operations with an array.
Reading and writing ints to the array is an atomic operation.
My implementation is here.

Of course I don't object if the maintainers chose to merged your commit right way,
your solution is very straight forward.

@damian-666

This comment was marked as abuse.

@squarebananas
Copy link
Contributor Author

My implementation is here.

I gave that a try and it seems to work fine.

I was thinking the gamepad object shouldn't be used after being removed and your solution could rarely allow WGI.Gamepad.GetCurrentReading to be run after a gamepad has just been disconnected. However it turns out this works and just returns a default WGI.GamepadReading.

If someone lets me know which way to proceed I can amend the PR.

Also with that first call empty workaround I'm only getting an empty list when placing a breakpoint there but not when running normally. Not sure why that is.

@nkast
Copy link
Contributor

nkast commented Feb 25, 2022

Honesty, your PR is fine. There's no reason to postpone a merge.

About the workaround, I have no idea why it's behaving like that but I left it in just in case
it's a weird race thing that could happen every now and then.

About your other comment, I think you are saying that after reading the gamepad in this line
var gamepad = _gamepads[index];
we might receive a GamepadRemoved event for that gamepad.
I'd say that the gamepad had been physically detached before the event had reach our code anyway.
The end result is the same whether we catch the removed event first and return a default state
or call GetCurrentReading() on a removed gamepad.

@squarebananas
Copy link
Contributor Author

Thanks.

About your other comment, I think you are saying that after reading the gamepad in this line
var gamepad = _gamepads[index];
we might receive a GamepadRemoved event for that gamepad.

Yeah that's it. I was initially thinking that calling GetCurrentReading on a removed gamepad might work like calling Play on a used SoundEffectInstance which can't be reused. After testing this I found GetCurrentReading works even if the gamepad no longer exists in the static WGI.Gamepad.Gamepads list. So I was just confirming that your method works fine.

@mrhelmut mrhelmut merged commit 1f2905b into MonoGame:develop Apr 26, 2022
@mrhelmut
Copy link
Contributor

Fine by me! Thank you!

viniciusjarina pushed a commit to codefoco/MonoGame that referenced this pull request May 1, 2022
Add thread locking around the gamepads dictionary
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants