-
Notifications
You must be signed in to change notification settings - Fork 269
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
use QTimer to update plugins #1095
Conversation
Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>
What steps would I take to cause the crash without this PR in place? |
I think the easiest way is to test this with a reliable crash is the jennuine/edit_material_colors branch that targets Dome. The following steps would then be:
Without this PR, it will either crash on step (2) when you click on the visual or at some point in step (3) |
Codecov Report
@@ Coverage Diff @@
## ign-gazebo3 #1095 +/- ##
===============================================
+ Coverage 77.56% 77.75% +0.19%
===============================================
Files 208 222 +14
Lines 11385 12683 +1298
===============================================
+ Hits 8831 9862 +1031
- Misses 2554 2821 +267
Continue to review full report at Codecov.
|
@@ -431,10 +436,9 @@ void ComponentInspector::Update(const UpdateInfo &, | |||
// Add component to list | |||
else | |||
{ | |||
// TODO(louise) Blocking here is not the best idea | |||
QMetaObject::invokeMethod(&this->dataPtr->componentsModel, |
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.
If we the Update
function is called from the Qt thread, I would think we shouldn't need to use invokeMethod
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 thought that as well but when I change this invokeMethod
to be:
item = this->dataPtr->componentsModel.AddComponentType(typeId);
even after dfabb5c it seg faults here: https://github.com/ignitionrobotics/ign-gazebo/blob/95fad0d32e3c015bd377e76856fdd2c2129d033f/src/gui/plugins/component_inspector/ComponentInspector.cc#L648
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 tried that, but it didn't crash for me for rolling_shapes.sdf
. Which world did you try it on?
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.
Changing QMetaObject::invokeMethod(&this->dataPtr->componentsModel, "RemoveComponentType",...
to a regular functions seems to break functionality of the ComponentInspector even though it doesn't crash, so maybe it's better to leave it as is. It's using Qt::QueuedConnection
, which I think means it's executed after the thread goes to sleep after calling all the UpdatePlugin
functions. So the timing may be important to keep the functionality.
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 tried that, but it didn't crash for me for rolling_shapes.sdf. Which world did you try it on?
I tested shapes.sdf
, the crash happens after you select one of the entities in the entity tree.
Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>
src/gui/GuiRunner.cc
Outdated
@@ -137,7 +115,7 @@ void GuiRunner::OnState(const msgs::SerializedStepMap &_msg) | |||
|
|||
// Update all plugins | |||
this->updateInfo = convert<UpdateInfo>(_msg.stats()); | |||
this->UpdatePlugins(); | |||
QMetaObject::invokeMethod(this, "UpdatePlugins", 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 think using Qt::DirectConnection
is the same as calling the function directly and will have the same thread safety issues. Can you use Qt::QueuedConnection
instead?
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.
Actually, I think you'll need Qt::BlockingQueuedConnection
because we'd want to wait until UpdatePlugins
has finished before calling ClearNewlyCreatedEntities()
and ProcessRemoveEntityRequests
.
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.
Thank you for pointing that out. I've updated it to use Qt::BlockingQueuedConnection
de2e098 instead because we need UpdatePlugins
to happen before these calls: https://github.com/ignitionrobotics/ign-gazebo/blob/dfabb5c38fced067d99edf09aeafa2d9ac991496/src/gui/GuiRunner.cc#L119-L120
(If we used Qt::QueuedConnection
then try to remove an entity it will still appear in the scene.)
Since the signaling thread is a ign-transport
thread and not the Qt
thread, there should not be any deadlock issues.
Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>
src/gui/GuiRunner.cc
Outdated
@@ -137,7 +115,8 @@ void GuiRunner::OnState(const msgs::SerializedStepMap &_msg) | |||
|
|||
// Update all plugins | |||
this->updateInfo = convert<UpdateInfo>(_msg.stats()); | |||
this->UpdatePlugins(); | |||
QMetaObject::invokeMethod(this, "UpdatePlugins", | |||
Qt::BlockingQueuedConnection); |
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'm getting consistent crashes on shutdown if simulation is playing. Here's the backtrace:
#0 0x00007f0940fb1274 in std::_Rb_tree_increment(std::_Rb_tree_node_base*) () at /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00007f09422de761 in std::_Rb_tree_iterator<std::pair<std::set<unsigned long, std::less<unsigned long>, std::allocator<unsigned long> > const, ignition::gazebo::v3::detail::View> >::operator++() (this=<synthetic pointer>) at /usr/include/c++/9/bits/stl_tree.h:285
#2 ignition::gazebo::v3::EntityComponentManager::ClearNewlyCreatedEntities() (this=<optimized out>)
at /home/chapulina/dev_focal/ws_citadel/src/ign-gazebo/src/EntityComponentManager.cc:177
#3 0x00007f0942544207 in ignition::gazebo::v3::GuiRunner::OnState(ignition::msgs::SerializedStepMap const&) (this=
0x5603a97b0300, _msg=...) at /home/chapulina/dev_focal/ws_citadel/src/ign-gazebo/src/gui/GuiRunner.cc:122
#4 0x00007f094255c6c9 in std::function<void (ignition::msgs::SerializedStepMap const&, ignition::transport::v8::MessageInfo const&)>::operator()(ignition::msgs::SerializedStepMap const&, ignition::transport::v8::MessageInfo const&) const
(__args#1=..., __args#0=..., this=0x7f091c027b10) at /usr/include/c++/9/bits/std_function.h:683
#5 ignition::transport::v8::SubscriptionHandler<ignition::msgs::SerializedStepMap>::RunLocalCallback(google::protobuf::Message const&, ignition::transport::v8::MessageInfo const&) (this=0x7f091c027ab0, _msg=..., _info=...)
at /home/chapulina/dev_focal/ws_citadel/install/include/ignition/transport8/ignition/transport/SubscriptionHandler.hh:220
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.
Hopefully fixed by 5bd0107
Reorganize code so that the `ecm` and `updateInfo` variables are only accessed from the Qt thread. Signed-off-by: Addisu Z. Taddese <addisu@openrobotics.org>
…into jennuine/thread_safe_update Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>
Signed-off-by: Jenn Nguyen <jenn@openrobotics.org>
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.
Great work, awesome idea to use QTimer
👍 Thank you for addressing those Blocking here is not the best idea TODOs! 😄
I stress-tested this with various component inspectors and joint position control, and it seems to be pretty stable at runtime!
I'm still getting shutdown crashes though 😕 It's easy to reproduce with this world:
https://app.ignitionrobotics.org/OpenRobotics/fuel/worlds/NAO%20joint%20control
The crashes don't come with useful backtraces and just point to
#2 Object "/usr/lib/x86_64-linux-gnu/libQt5Qml.so.5", at 0x7f9e9cbea418, in QQmlPropertyCache::~QQmlPropertyCache()
I suspect this is more about the destruction order within these plugins than the update loop itself, so I think it can be addressed later.
🦟 Bug fix
Summary
GuiRunner
was creating a thread to call plugins'Update
functions and accessing GUI items, which was not entirely thread safe since GUI operations should not be done off the Qt GUI thread. This has been replaced by using aQTimer
to signal theUpdatePlugins
function every 33 ms, which should now make allUpdate
calls thread safe.Checklist
codecheck
passed (See contributing)Note to maintainers: Remember to use Squash-Merge