-
-
Notifications
You must be signed in to change notification settings - Fork 8.8k
frontend: Adjust application shutdown logic #12668
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
base: master
Are you sure you want to change the base?
Conversation
3a8a6a9 to
f97a730
Compare
frontend/OBSApp.cpp
Outdated
| connect(snInt, &QSocketNotifier::activated, this, &OBSApp::ProcessSigInt); | ||
| #else | ||
| connect(qApp, &QGuiApplication::commitDataRequest, this, &OBSApp::commitData); | ||
| connect(qApp, &QGuiApplication::commitDataRequest, this, &OBSApp::commitData, Qt::DirectConnection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also just catching WM_QUERYENDSESSION so it could be removed unless it does anything useful on other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't found out how Qt behaves on Linux, at least no Linux-specific platform plugin seems to call commitData or aboutToQuit as Windows or macOS do.
At least under xcb Qt uses its session manager.
On macOS commitData should occur in reaction to - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender, which serves the same purpose as the WM_QUERYENDSESSION signal (allowing apps to cancel the shutdown procedure, with the expectation that they also signal when they took care of stuff and are actually able to comply).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also just catching
WM_QUERYENDSESSIONso it could be removed unless it does anything useful on other platforms.
Qt's documentation suggests that we ourselves should not try to exit in response to commitDataRequest, it should only save data. The session manager may try to quit() the application later in the process, depending how things respond.
https://doc.qt.io/qt-6/qguiapplication.html#commitDataRequest
This PR also adjusted commitData() to only save data, I think at worst this is an extra safety.
frontend/OBSApp.cpp
Outdated
| connect(snInt, &QSocketNotifier::activated, this, &OBSApp::ProcessSigInt); | ||
| #else | ||
| connect(qApp, &QGuiApplication::commitDataRequest, this, &OBSApp::commitData); | ||
| connect(qApp, &QGuiApplication::commitDataRequest, this, &OBSApp::commitData, Qt::DirectConnection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't found out how Qt behaves on Linux, at least no Linux-specific platform plugin seems to call commitData or aboutToQuit as Windows or macOS do.
At least under xcb Qt uses its session manager.
On macOS commitData should occur in reaction to - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender, which serves the same purpose as the WM_QUERYENDSESSION signal (allowing apps to cancel the shutdown procedure, with the expectation that they also signal when they took care of stuff and are actually able to comply).
6d08792 to
617e7ea
Compare
|
Testing this on Gentoo Linux, it seems to be working fine, but I don't think I ever got to see the "unsafe shutdown detected" or so, even without it. I have a way to prod a segmentation fault even (I promies I'll eventually actually report that one), and OBS Studio still starts just fine. I haven't looked at the code, but I don't think it should be anything related to 'systemd' or something like that which I don't use, so it is a bit interesting to me. It might be interesting if people who /do/ get the pop-up/logs for un-clean shutdowns explain how exactly they do get them. In addition to the segfault, I've been sending OBS Studio the various signals ranging from 1 to 15, such as kill (9) and terminate (15) and nothing seems to prod up the message. On that note, I think most if not all desktop environments will/should send the term (15) signal to all applications when shutting down, though I saw some discussion of 'systemd' also sending 'kill' (9) immediately after, but they may have made that better some time ago (I have no systems using 'systemd' to test right now). In any case, thank you! |
|
There is a potential application hang when experimental captions are enabled and trying to stop it. Fix candidate in #12729 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least on macOS these changes seem to dangerously interfere with the orderly shutdown process of the app:
- When OBS is closed from the outside (by the OS), then
commitDatais calledsaveAllis calledcloseWindowis called viacloseEventsaveAllis called again`OBSBasic's destructor runs (triggered by aQEvent::DeferredDeleteevent)- The destructor crashes
- When OBS is closing itself, then
closeWindowis calledsaveAllis calledcommitDatais calledsaveAllis called again`closeWindowis called again (triggered byQApplication::aboutToQuit), but bails out earlyOBSBasic's destructor runs
Here's what STDERR gave me:
info: [OBSBasic] Destructor
libc++abi: terminating due to uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument
warning: QMetaObject::invokeMethod: No such method QObject::DoCefMessageLoop(int)
Confusingly enough the mutex in question is the log_mutex used by too_many_repeated_entries after the info message has been printed.
frontend/widgets/OBSBasic.cpp
Outdated
| applicationShutdown(); | ||
| deleteLater(); | ||
|
|
||
| App()->quit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This single line will make OBS crash on macOS if the application is closed by the OS either because of a shutdown/restart or the user quit the application using the dock icon.
On macOS, the external termination message is handled by the global application instance, which already calls QApplication::Quit as part of its platform plugin, which will send the close event to the main window all by itself.
Calling it again here leads to a nested call to Quit, which seems to have undefined side-effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This review thread is unresolved.
Sorry for pinging you twice. The other one got clogged by Joel's ego. My question was:
I want to try this pr but I feel like I'm missing something? I wasn't getting this dependency issue before. |
You can download artifacts compiled on CI of this PR: |
617e7ea to
6b2debe
Compare
e06d69a to
a0930bd
Compare
PatTheMav
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most recent pushed fixed the crash bug on macOS. Indeed QGuiApplicationPrivate::quit never seems to be executed at all (neither when terminated via macOS nor when quitting the app directly), probably the app is torn down before the invocation can take place.
| @@ -0,0 +1,65 @@ | |||
|
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing GPL header.
| @@ -0,0 +1,65 @@ | |||
|
|
|||
|
|
|||
| #include <utility/NativeEventFilter.hpp> | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| #include <utility/NativeEventFilter.hpp> | |
| #include "NativeEventFilter.hpp" |
|
|
||
| bool NativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) | ||
| { | ||
| if (eventType == "windows_generic_MSG") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is "windows_generic_MSG" even a possible event type outside of Windows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not, but ifdefing the entire block seemed odd to me, as this method is platform agnostic
https://doc.qt.io/qt-6/qabstractnativeeventfilter.html#nativeEventFilter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's why in their own implementations they use a generic header, but platform-specific implementations, because then you don't get weird constructs like these were the source code is sliced and diced by preprocessor macros.
It's also the approach I advise to use generally. In this case you would add NativeEventFilter_Windows.cpp, NativeEventFilter_MacOs.cpp, etc. which at the very least implement stubs to implement the full object.
The compiler will not care: If the functions return immediately or via analysis are proven to not do anything, it will not even emit a function call. But for us puny humans there will be cleanly separated implementations for each platform where the internal code is free to be custom-tailored to its platform and doesn't have to contort itself to somehow support different ones in the same implementation.
The platform-specific CrasHandler implementations follow that principle.
| @@ -0,0 +1,12 @@ | |||
| #pragma once | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing GPL header.
ec4ceb3 to
05047d3
Compare
05047d3 to
756d5fb
Compare
Description
This PR does a bit of clean up and separation of logic in OBSBasic's shutdown process and makes a number of improvements to how OBS handles being closed by things other than a normal shutdown.
commitDataRequestin favor of only saving dataI have tried to keep my changes to the shutdown flow as minimal as possible, as it is particularly delicate and very sensitive to the order of operations. Testing on all operating systems will be valuable.
Motivation and Context
We've received a lot of great feedback on the Unclean Shutdown dialog after we removed the ability to suppress it. We believe that this dialog serves an important purpose but only when it is being shown accurately. This PR aims to address a majority of the cases where it was showing up unexpected or unintended.
How Has This Been Tested?
Painstakingly signing out of Windows multiple times with OBS running in various states.
Enabled the warning for confirmation on exit with outputs active. Ran OBS with no outputs active, with virtual camera active, and with virtual camera active then clicking Exit to display the confirmation prompt prior to log off. Then tested signing out in all scenarios, and both forcing the sign out to continue, or cancelling it.
When sign out is cancelled with outputs active, OBS stays running and displays the confirmation dialog if it was not showing already. When sign out continues, OBS starts normally the following time with no unclean shutdown warning.
Types of changes
Checklist: