From: Torsten Dreyer Date: Fri, 29 Aug 2014 13:30:25 +0000 (+0200) Subject: Partial fix for crash in SGPropertyNode::fireValueChanged X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=f33ad357e928b5210c87cb8977d3cc88deba811b;p=simgear.git Partial fix for crash in SGPropertyNode::fireValueChanged The effect system used Listeners on property nodes to get the values for shader uniforms. These listeners get deleted by an osg thread causing access to freed memory when this happens while the main thread calls fireValueChanged. This patch changes the update method to polling for scalar properties. This isn't 100% threadsafe, too. But at least it does not crash anymore. --- diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index 7d961af4..f94be67a 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -1356,6 +1356,28 @@ void Effect::InitializeCallback::doUpdate(osg::Node* node, osg::NodeVisitor* nv) } } +void Effect::UpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + EffectGeode* eg = dynamic_cast(node); + if (!eg) + return; + Effect* effect = eg->getEffect(); + if (!effect) + return; + + for (vector >::iterator itr = effect->_extraData.begin(), + end = effect->_extraData.end(); + itr != end; + ++itr) { + PropertyPoller * poller + = dynamic_cast(itr->ptr()); + if (poller) + poller->pollProperties(effect); + } + + traverse(node, nv); +} + bool Effect::Key::EqualTo::operator()(const Effect::Key& lhs, const Effect::Key& rhs) const { diff --git a/simgear/scene/material/Effect.hxx b/simgear/scene/material/Effect.hxx index 0966dc1a..346c52c2 100644 --- a/simgear/scene/material/Effect.hxx +++ b/simgear/scene/material/Effect.hxx @@ -73,6 +73,17 @@ private: bool _initialized; }; +class PropertyPoller +{ +public: + PropertyPoller() {}; + virtual ~PropertyPoller() {}; + virtual void pollProperties(Effect* effect) + { + } +private: +}; + class Effect : public osg::Object { public: @@ -121,6 +132,17 @@ public: { void doUpdate(osg::Node* node, osg::NodeVisitor* nv); }; + friend struct UpdateCallback; + struct UpdateCallback : public osg::NodeCallback + { + UpdateCallback() {} + UpdateCallback(const UpdateCallback& nc, const osg::CopyOp& copyop) + : osg::NodeCallback(nc, copyop) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + }; protected: std::vector > _extraData; ~Effect(); diff --git a/simgear/scene/material/EffectBuilder.hxx b/simgear/scene/material/EffectBuilder.hxx index a919f10b..52e2cf1c 100644 --- a/simgear/scene/material/EffectBuilder.hxx +++ b/simgear/scene/material/EffectBuilder.hxx @@ -496,19 +496,17 @@ make_OSGFunctor(Obj* obj, void (Obj::*const func)(const OSGParam&)) template class ScalarChangeListener : public SGPropertyChangeListener, public InitializeWhenAdded, + public PropertyPoller, public Effect::Updater { public: ScalarChangeListener(ObjType* obj, const F& setter, const std::string& propName) - : _obj(obj), _setter(setter) + : _obj(obj), _setter(setter), _propName(propName) { - _propName = new std::string(propName); } virtual ~ScalarChangeListener() { - delete _propName; - _propName = 0; } void valueChanged(SGPropertyNode* node) { @@ -516,16 +514,20 @@ public: } void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot) { - SGPropertyNode* listenProp = makeNode(propRoot, *_propName); - delete _propName; - _propName = 0; - if (listenProp) - listenProp->addChangeListener(this, true); + _listenProp = makeNode(propRoot, _propName); +// if ( _listenProp.valid() ) +// _listenProp->addChangeListener(this, true); + } + void pollProperties(Effect* effect) + { + if( false == _listenProp.valid() ) return; + valueChanged(_listenProp); } private: + SGPropertyNode_ptr _listenProp; osg::ref_ptr _obj; F _setter; - std::string* _propName; + std::string _propName; }; template diff --git a/simgear/scene/material/EffectGeode.cxx b/simgear/scene/material/EffectGeode.cxx index c2967639..2355bb67 100644 --- a/simgear/scene/material/EffectGeode.cxx +++ b/simgear/scene/material/EffectGeode.cxx @@ -52,7 +52,9 @@ void EffectGeode::setEffect(Effect* effect) _effect = effect; if (!_effect) return; + //TODO: do we leak the callbacks or does the geode own pointer afterwards? addUpdateCallback(new Effect::InitializeCallback); + addUpdateCallback(new Effect::UpdateCallback); } void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize)