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.
This commit is contained in:
Torsten Dreyer 2014-08-29 15:30:25 +02:00
parent c30ce67e16
commit f33ad357e9
4 changed files with 58 additions and 10 deletions

View File

@ -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<EffectGeode*>(node);
if (!eg)
return;
Effect* effect = eg->getEffect();
if (!effect)
return;
for (vector<SGSharedPtr<Updater> >::iterator itr = effect->_extraData.begin(),
end = effect->_extraData.end();
itr != end;
++itr) {
PropertyPoller * poller
= dynamic_cast<PropertyPoller*>(itr->ptr());
if (poller)
poller->pollProperties(effect);
}
traverse(node, nv);
}
bool Effect::Key::EqualTo::operator()(const Effect::Key& lhs,
const Effect::Key& rhs) const
{

View File

@ -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<SGSharedPtr<Updater> > _extraData;
~Effect();

View File

@ -496,19 +496,17 @@ make_OSGFunctor(Obj* obj, void (Obj::*const func)(const OSGParam&))
template<typename OSGParamType, typename ObjType, typename F>
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<ObjType> _obj;
F _setter;
std::string* _propName;
std::string _propName;
};
template<typename T, typename Func>

View File

@ -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)