-
Notifications
You must be signed in to change notification settings - Fork 36.2k
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
qt: Call setParent() in the parent's context #18948
Conversation
The needless of
Comments are adjusted according to @ryanofsky's suggestions: |
Concept ACK, but now it must destroy wallet models on quit, or am I wrong? |
Correct. Aren't they destroyed now? |
Where? |
It seems the procedure starts in this destructor: bitcoin/src/interfaces/wallet.cpp Line 507 in f71a3a8
and through the bitcoin/src/qt/walletcontroller.cpp Lines 122 to 134 in f71a3a8
it ends here: bitcoin/src/qt/walletcontroller.cpp Lines 145 to 156 in f71a3a8
|
Yes, but it should also delete when wallet controller is deleted. |
From the |
None. But before this change wallet models were owned and managed by wallet controller. I just think that it shouldn't depend on whether or not wallets are unloaded before destroying the window on exit. Suppose that with multiprocess you want to just restart the GUI process, in that case you want to just teardown the GUI, which includes wallet models. |
seems to work(quick check), but i still like the solution from branch 18. |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
I agree this is important for robustness and safety. Now I can see the following ways to move on:
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -110,7 +110,7 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, nullptr);
// Handler callback runs in a different thread so fix wallet model thread affinity.
wallet_model->moveToThread(thread());
- wallet_model->setParent(this);
+ QTimer::singleShot(0, this, [wallet_model, this]() { wallet_model->setParent(this); });
m_wallets.push_back(wallet_model);
// WalletModel::startPollBalance needs to be called in a thread managed by
Which way is preferable? |
let promag decide what he prefers. sidenote: walletmodel's parent is set later - i hope - Queued Connection |
Concept ACK |
Updated d6afd1c -> 679b548 (pr18948.01 -> pr18948.02, diff):
|
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.
With lambda slots we could make this more elegant, something like:
WalletModel* wallet_model;
QMetaObject::invokeMethod(this, [this, &wallet_model] {
wallet_model = new WalletModel(this);
// ...
}, GUIUtil::blockingGUIThreadConnection());
Unfortunately, |
Ah yes, too soon then 😅 |
Not sure about the context, but it's trivial to replace this method. You can write a 2-line function that just connects the lambda to a temporary object slot and triggers the object. e.g. |
679b548
to
2d6672e
Compare
Reworked. The previous implementation was broken due to the fact the
As this place is the only in the code base, I've chosen a different approach, that would be more convenient when migration to Qt 5.10+ occurs. |
src/qt/walletcontroller.cpp
Outdated
}, GUIUtil::blockingGUIThreadConnection()); | ||
#else | ||
{ | ||
QEventLoop event_loop; |
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.
In commit "qt: Call setParent() in the parent's context" (3200c44)
This workaround is confusing and I think should have some kind of comment explaining what it is doing and how it works. I think the goal is to get setParent to run in the the GUI thread rather than the calling thread, and to have the calling thread block until setParent returns. But it's unclear why setParent needs to run on the gui thread, or why setting a single shot timer would block until after the timer runs (instead of scheduling the timer asynchronously), or how declaring an event_loop
variable that is never referenced would have any effect.
Honestly I think the stack overflow approach from https://github.com/ryanofsky/bitcoin/blob/eacd34144c1ee989c9ab43eb439fecca76addc76/src/qt/async_update.h#L18-L23 #18948 (comment) seems simpler and more lightweight, but this subjective. Any workaround seems fine if it has an explanation.
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.
WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, nullptr); | ||
// Handler callback runs in a different thread so fix wallet model thread affinity. | ||
WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, | ||
nullptr /* required for the following moveToThread() call */); |
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.
In commit "qt: Improve comments in WalletController::getOrCreateWallet()" (2d6672e)
Nice comments, these do a good job of explaining the context
2d6672e
to
34b83a1
Compare
Updated 2d6672e -> 34b83a1 (pr18948.03 -> pr18948.04, diff):
|
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.
Code review ACK 34b83a1. Just suggested changes since review (thanks!) avoiding using preprocessor and timer.
@promag can you take a look here again? |
utACK 34b83a1 |
This is a replacement of the QMetaObject::invokeMethod functor overload which is available in Qt 5.10+. Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
setParent(parent) calls sendEvent(parent, QChildEvent) that implies running in the thread which created the parent object.
34b83a1
to
8963b2c
Compare
Rebased 34b83a1 -> 8963b2c (pr18948.04 -> pr18948.05) due to the conflict with bitcoin-core/gui#46. |
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.
Code review ACK 8963b2c. No changes since last review, just rebase because of conflict on some adjacent lines
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.
utACK 8963b2c
8963b2c qt: Improve comments in WalletController::getOrCreateWallet() (Hennadii Stepanov) 5fcfee6 qt: Call setParent() in the parent's context (Hennadii Stepanov) 5659e73 qt: Add ObjectInvoke template function (Hennadii Stepanov) Pull request description: The `setParent(parent)` internally calls `QCoreApplication::sendEvent(parent, QChildEvent)` that implies running in the thread which created the parent object. That is not the case always, and an internal assertion fails in the debug mode. Steps to reproduce this issue on master (007e15d) on Linux Mint 20 (x86_64): ``` $ make -C depends DEBUG=1 $ CONFIG_SITE=$PWD/depends/x86_64-pc-linux-gnu/share/config.site ./configure $ make $ QT_FATAL_WARNINGS=1 lldb src/qt/bitcoin-qt -- --regtest -debug=qt (lldb) target create "src/qt/bitcoin-qt" Current executable set to '/home/hebasto/GitHub/bitcoin/src/qt/bitcoin-qt' (x86_64). (lldb) settings set -- target.run-args "--regtest" "-debug=qt" (lldb) run Process 431562 launched: '/home/hebasto/GitHub/bitcoin/src/qt/bitcoin-qt' (x86_64) # load wallet via GUI Process 431562 stopped * thread #24, name = 'QThread', stop reason = signal SIGABRT frame #0: 0x00007ffff794518b libc.so.6`__GI_raise(sig=2) at raise.c:51:1 (lldb) bt * thread #24, name = 'QThread', stop reason = signal SIGABRT * frame #0: 0x00007ffff794518b libc.so.6`__GI_raise(sig=2) at raise.c:51:1 frame #1: 0x00007ffff7924859 libc.so.6`__GI_abort at abort.c:79:7 frame #2: 0x0000555556508ec4 bitcoin-qt`::qt_message_fatal((null)=<unavailable>, context=<unavailable>, message=<unavailable>) at qlogging.cpp:1690:15 frame #3: 0x00005555565099cf bitcoin-qt`QMessageLogger::fatal(this=<unavailable>, msg=<unavailable>) const at qlogging.cpp:796:21 frame #4: 0x000055555650479d bitcoin-qt`qt_assert_x(where=<unavailable>, what=<unavailable>, file=<unavailable>, line=<unavailable>) at qglobal.cpp:3088:46 frame #5: 0x0000555556685733 bitcoin-qt`QCoreApplicationPrivate::checkReceiverThread(receiver=0x0000555557b27510) at qcoreapplication.cpp:557:5 frame #6: 0x00005555567ced86 bitcoin-qt`QApplication::notify(this=0x00007fffffffd4a0, receiver=0x0000555557b27510, e=0x00007fff9a7f8ce0) at qapplication.cpp:2956:27 frame #7: 0x0000555556685d31 bitcoin-qt`QCoreApplication::notifyInternal2(receiver=0x0000555557b27510, event=0x00007fff9a7f8ce0) at qcoreapplication.cpp:1024:24 frame #8: 0x00005555566c9224 bitcoin-qt`QObjectPrivate::setParent_helper(QObject*) [inlined] QCoreApplication::sendEvent(event=<unavailable>, receiver=<unavailable>) at qcoreapplication.h:233:59 frame #9: 0x00005555566c9210 bitcoin-qt`QObjectPrivate::setParent_helper(this=0x00007fff85855260, o=0x0000555557b27510) at qobject.cpp:2036 frame #10: 0x00005555566c9b41 bitcoin-qt`QObject::setParent(this=<unavailable>, parent=<unavailable>) at qobject.cpp:1980:24 frame #11: 0x0000555555710be8 bitcoin-qt`WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet, std::default_delete<interfaces::Wallet> >) + 2534 ... ``` Fixes bitcoin#18835. ACKs for top commit: ryanofsky: Code review ACK 8963b2c. No changes since last review, just rebase because of conflict on some adjacent lines jonasschnelli: utACK 8963b2c Tree-SHA512: fef615904168717df3d8a0bd85eccc3eef990cc3e66c9fa280c8ef08ea009a7cb5a2a4f868ed0be3c0fe5bf683e8465850b5958deb896fdadd22d296186c9586
5659e73 has been reverted in bitcoin-core/gui#587. |
The
setParent(parent)
internally callsQCoreApplication::sendEvent(parent, QChildEvent)
that implies running in the thread which created the parent object. That is not the case always, and an internal assertion fails in the debug mode.Steps to reproduce this issue on master (007e15d) on Linux Mint 20 (x86_64):
Fixes #18835.