-
Notifications
You must be signed in to change notification settings - Fork 142
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
Fix macOS Reset() causing crash on input thread when GCAdapter is unplugged #301
Conversation
* On macOS 11.0 I noticed that the libusb hotplug event was getting called on the read thread. This seemed to be different behavior than my windows platform where the hotplug event was happening on it's own thread * when a hotplug detach event happens the reset thread waits for the in and out threads to error out with "join" * however, on macOS 11.0 (when started with an adapter plugged in), the detach event would attempt to join itself causing a crash. * To get around this before trying to join threads reset will try to see if it is one of those threads and start a new reset thread if so. * If we wait attempt to join the reset thread from the caller they will both be trying to join each other which will also result in a crash
I've also tested this change against this branch - #257 And with this, mac supported adapter hot-swapping for unplug. The controller menu showed the polling rate go from a number to adapter not detected. It seems there are still issues with a new GCAdapter showing up but unplugging is half the battle! |
The adapter not showing up (a "new" one) is possibly due to IOKit/kext oddities. Big Sur can run the DriverKit variant instead, which would support dynamically loading/unloading (and thus re-blocking) Apple's handlers. |
This got me on the right track! It definitely is mac/obj-c oddities. it's again related to the weirdness of libusb though. Mac can temporarily transfer execution on a thread and that is how the hotplug works. This means in the scan thread here
Still trying to work out a clean solution in my head, if there should be a hotplug+reset thread or something like that. Maybe even don't use the wait condition on mac due to hotplug oddities. #ifdef the wait condition seems like the lowest impact, especially since it wasn't working anyway. any thoughts? |
You might want to take a gander at how mainline Dolphin does this. I'm not at my laptop but I recall it still uses |
Also probably worth noting that the |
* Pulled from Dolphin source. Their GCAdapter has greatly changed however I was able to pull out a small set of changes required to get hotwapping working. They did this by having an event thread that lives for the lifetime of the context. This thread polls for events and handles them there instead of handling them in place. Handling them in place on macOS causes macos to be stuck on a wait condtion
Looking at the mainline dolphin was the key.
Was what they did except much cleaner. They wrapped the libusb context in an object that spawns an event thread that lives for the lifetime of the context. This way as long as the context is around there is at least 1 dedicated thread willing to handle events others are waiting on. I was able to port over just the Wrapper they used and apply the minimal changes to Ishiiruka's GCAdapter like the mainline. This fixes the macOS crash and when run with #257 seemingly has full hot swap support, at least on macOS now I wasn't able to break it like I used to be able to. |
I'm thinking the linux support for #257 is probably a similar issue/same issue resolved by an event thread. I don't have an ubuntu box to test it on though |
I will be testing this PR on windows and Ubuntu just to be sure everything is working fine. Thanks for investigating and implementing a fix! |
Very happy to help, it's my first attempt at a public contribution and I felt like I could jump in with something I really use. It was really exciting my skill set lined up with something I felt was tackle-able relating to Slippi 😄 |
oooo hmmm looks like the new files aren't as easy to add to multiplatform stuff as a cmakelists, failing on linker stuff. I'll try to fix this soon |
On Windows, you'll need to add (I believe) a line to
Offhand not sure what the Ubuntu issue is, considering it's CMake like macOS and all. |
* When including libusb because of a non standard extension you have to let the solution know that you are expecting this * This was pulled from dolphin mainline that uses a newer version of libusb with more set_options and isn't needed for this version on windows
* On mainline dolphin LibusbUtils was built into core/core because some IOS files used it frequently. Slippi has none of these files so LibusbUtils was not used in core/core * gcc on linux has the default behavior of --as-needed. (Note: on macOS clang does not do this as default) * This meant core was stripping symbols from libusb before linking in with inputcommon. and missing symbols on linux * Moved libusbutils to InputCommon as they are only used there and not used in core/core, instead of turning off the default behavior of --as-needed, as that may have wider side effects. * If they are ever needed in core/core they can be moved back adn then the symbols won't be stripped since they will be used inside of that library
The windows issue was a vcxproj build and the ubuntu issue was aggressive symbol stripping since usbutils was being built into core/core but not used by core/core. We won't need them in core/core for what mainline dolphin used it for so I put them in inputcommon instead of changing linker options. I described it a bit more here 7ec1692 I expect it to build across the board now |
These changes + the PR 257 did add Linux adapter hot swapping. |
Steps to repro:
Expected: Slippi Dolphin remains open
Actual: Slippi Dolphin closes and MacOS reports Slippi Dolphin closed unexpectedly (crash)
Change notes + thoughts:
On macOS 11.0 I noticed that the libusb hotplug event was getting
called on the read thread. This seemed to be different behavior than
my windows platform where the hotplug event was happening on it's
own thread
when a hotplug detach event happens the reset thread waits for the
in and out threads to error out with "join"
however, on macOS 11.0 (when started with an adapter plugged in),
the detach event would attempt to join itself causing a crash.
To get around this before trying to join threads reset will try to
see if it is one of those threads and start a new reset thread if
so.
If we wait attempt to join the reset thread from the caller they
will both be trying to join each other which will also result in a crash