Skip to content
Snippets Groups Projects
Commit a69d373e authored by Lars Kanis's avatar Lars Kanis
Browse files

Fix Segfault while GC'ing FXWindows

FXWindow destructor calls recalc() and changeFocus() of it's parent windows.
Since these methods are routed back to Ruby code, but calling Ruby code from
GC isn't a good idea, we mark the parent window as "in_gc", so that it will
ignore recalc() and changeFocus() calls completely.

The parent window should also be scheduled to be free'd. In the other case,
the child window would have been marked as used.
parent e14c5565
Branches
Tags
No related merge requests found
...@@ -85,11 +85,15 @@ static st_table * FXRuby_Objects; ...@@ -85,11 +85,15 @@ static st_table * FXRuby_Objects;
* struct. It identifies the Ruby instance associated with a C++ object. * struct. It identifies the Ruby instance associated with a C++ object.
* It also indicates whether this is merely a "borrowed" reference to * It also indicates whether this is merely a "borrowed" reference to
* some C++ object (i.e. it's not one we need to destroy later). * some C++ object (i.e. it's not one we need to destroy later).
*
* in_gc is set for FXWindows that are in garbage collection and must
* not call ruby code anymore.
*/ */
struct FXRubyObjDesc { struct FXRubyObjDesc {
VALUE obj; VALUE obj;
bool borrowed; bool borrowed;
bool in_gc;
}; };
...@@ -110,6 +114,7 @@ VALUE FXRbNewPointerObj(void *ptr,swig_type_info* ty){ ...@@ -110,6 +114,7 @@ VALUE FXRbNewPointerObj(void *ptr,swig_type_info* ty){
obj=SWIG_Ruby_NewPointerObj(ptr,ty,1); obj=SWIG_Ruby_NewPointerObj(ptr,ty,1);
desc->obj=obj; desc->obj=obj;
desc->borrowed=true; desc->borrowed=true;
desc->in_gc=false;
st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t>(desc)); st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t>(desc));
return obj; return obj;
} }
...@@ -140,6 +145,25 @@ bool FXRbIsBorrowed(void* ptr){ ...@@ -140,6 +145,25 @@ bool FXRbIsBorrowed(void* ptr){
} }
} }
bool FXRbSetInGC(const void* ptr, bool enabled){
FXASSERT(ptr!=0);
FXRubyObjDesc *desc;
if(st_lookup(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t *>(&desc))!=0){
desc->in_gc=enabled;
return enabled;
}
return false;
}
bool FXRbIsInGC(const void* ptr){
FXASSERT(ptr!=0);
FXRubyObjDesc *desc;
if(st_lookup(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t *>(&desc))!=0){
return desc->in_gc;
}
return false;
}
/** /**
* FXRbConvertPtr() is just a wrapper around SWIG_Ruby_ConvertPtr(). * FXRbConvertPtr() is just a wrapper around SWIG_Ruby_ConvertPtr().
...@@ -211,6 +235,7 @@ void FXRbRegisterRubyObj(VALUE rubyObj,const void* foxObj) { ...@@ -211,6 +235,7 @@ void FXRbRegisterRubyObj(VALUE rubyObj,const void* foxObj) {
if(FXMALLOC(&desc,FXRubyObjDesc,1)){ if(FXMALLOC(&desc,FXRubyObjDesc,1)){
desc->obj=rubyObj; desc->obj=rubyObj;
desc->borrowed=false; desc->borrowed=false;
desc->in_gc=false;
st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(const_cast<void*>(foxObj)),reinterpret_cast<st_data_t>(desc)); st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(const_cast<void*>(foxObj)),reinterpret_cast<st_data_t>(desc));
} }
else{ else{
...@@ -1301,6 +1326,7 @@ void FXRbRange2LoHi(VALUE range,FXdouble& lo,FXdouble& hi){ ...@@ -1301,6 +1326,7 @@ void FXRbRange2LoHi(VALUE range,FXdouble& lo,FXdouble& hi){
void FXRbCallVoidMethod(FXObject* recv, ID func) { void FXRbCallVoidMethod(FXObject* recv, ID func) {
VALUE obj=FXRbGetRubyObj(recv,false); VALUE obj=FXRbGetRubyObj(recv,false);
FXASSERT(!NIL_P(obj)); FXASSERT(!NIL_P(obj));
FXASSERT(!FXRbIsInGC(recv));
rb_funcall(obj,func,0,NULL); rb_funcall(obj,func,0,NULL);
} }
......
...@@ -149,7 +149,7 @@ inline void klass ## _dropDisable(klass* self){ \ ...@@ -149,7 +149,7 @@ inline void klass ## _dropDisable(klass* self){ \
FXRbCallVoidMethod(this,rb_intern("killFocus")); \ FXRbCallVoidMethod(this,rb_intern("killFocus")); \
} \ } \
void cls::changeFocus(FXWindow* child){ \ void cls::changeFocus(FXWindow* child){ \
FXRbCallVoidMethod(this,rb_intern("changeFocus"),child); \ if(!FXRbIsInGC(this)) FXRbCallVoidMethod(this,rb_intern("changeFocus"),child); \
} \ } \
void cls::setDefault(FXbool enable){ \ void cls::setDefault(FXbool enable){ \
FXRbCallVoidMethod(this,rb_intern("setDefault"),enable); \ FXRbCallVoidMethod(this,rb_intern("setDefault"),enable); \
...@@ -173,7 +173,7 @@ inline void klass ## _dropDisable(klass* self){ \ ...@@ -173,7 +173,7 @@ inline void klass ## _dropDisable(klass* self){ \
FXRbCallVoidMethod(this,rb_intern("position"),x,y,w,h); \ FXRbCallVoidMethod(this,rb_intern("position"),x,y,w,h); \
} \ } \
void cls::recalc(){ \ void cls::recalc(){ \
FXRbCallVoidMethod(this,rb_intern("recalc")); \ if(!FXRbIsInGC(this)) FXRbCallVoidMethod(this,rb_intern("recalc")); \
} \ } \
void cls::reparent(FXWindow* father,FXWindow* other){ \ void cls::reparent(FXWindow* father,FXWindow* other){ \
FXRbCallVoidMethod(this,rb_intern("reparent"),father,other); \ FXRbCallVoidMethod(this,rb_intern("reparent"),father,other); \
......
...@@ -73,6 +73,8 @@ VALUE showHelper(VALUE self, int argc, VALUE *argv, TYPE *p, swig_type_info *typ ...@@ -73,6 +73,8 @@ VALUE showHelper(VALUE self, int argc, VALUE *argv, TYPE *p, swig_type_info *typ
// Wrapper around SWIG_Ruby_NewPointerObj() // Wrapper around SWIG_Ruby_NewPointerObj()
VALUE FXRbNewPointerObj(void *ptr, swig_type_info *typeinfo); VALUE FXRbNewPointerObj(void *ptr, swig_type_info *typeinfo);
bool FXRbIsBorrowed(void* ptr); bool FXRbIsBorrowed(void* ptr);
bool FXRbSetInGC(const void* ptr, bool enabled);
bool FXRbIsInGC(const void* ptr);
// Wrapper around SWIG_TypeQuery() // Wrapper around SWIG_TypeQuery()
swig_type_info *FXRbTypeQuery(const char *name); swig_type_info *FXRbTypeQuery(const char *name);
...@@ -322,6 +324,7 @@ template<class TYPE> ...@@ -322,6 +324,7 @@ template<class TYPE>
void FXRbCallVoidMethod(FXObject* recv,ID func, TYPE& arg){ void FXRbCallVoidMethod(FXObject* recv,ID func, TYPE& arg){
VALUE obj=FXRbGetRubyObj(recv,false); VALUE obj=FXRbGetRubyObj(recv,false);
FXASSERT(!NIL_P(obj)); FXASSERT(!NIL_P(obj));
FXASSERT(!FXRbIsInGC(recv));
rb_funcall(obj,func,1,to_ruby(arg)); rb_funcall(obj,func,1,to_ruby(arg));
} }
...@@ -336,6 +339,7 @@ template<class TYPE> ...@@ -336,6 +339,7 @@ template<class TYPE>
void FXRbCallVoidMethod(const FXObject* recv, ID func, TYPE& arg){ void FXRbCallVoidMethod(const FXObject* recv, ID func, TYPE& arg){
VALUE obj=FXRbGetRubyObj(recv,false); VALUE obj=FXRbGetRubyObj(recv,false);
FXASSERT(!NIL_P(obj)); FXASSERT(!NIL_P(obj));
FXASSERT(!FXRbIsInGC(recv));
rb_funcall(obj,func,1,to_ruby(arg)); rb_funcall(obj,func,1,to_ruby(arg));
} }
......
...@@ -53,6 +53,11 @@ void FXRbObject::markfunc(FXObject* obj){ ...@@ -53,6 +53,11 @@ void FXRbObject::markfunc(FXObject* obj){
FXTRACE((100,"%s::markfunc(%p)\n",obj?obj->getClassName():"FXRbObject",obj)); FXTRACE((100,"%s::markfunc(%p)\n",obj?obj->getClassName():"FXRbObject",obj));
} }
static void FXRbSetInGCRecursive(FXWindow *window, bool enabled){
FXRbSetInGC( window, true );
if(window->getParent()) FXRbSetInGCRecursive( window->getParent(), enabled );
}
void FXRbObject::freefunc(FXObject* self){ void FXRbObject::freefunc(FXObject* self){
if(self!=0){ if(self!=0){
...@@ -66,6 +71,17 @@ void FXRbObject::freefunc(FXObject* self){ ...@@ -66,6 +71,17 @@ void FXRbObject::freefunc(FXObject* self){
FXASSERT(classname!=0); FXASSERT(classname!=0);
FXASSERT(strlen(classname)>3); FXASSERT(strlen(classname)>3);
if(classname[0]=='F' && classname[1]=='X' && classname[2]=='R' && classname[3]=='b'){ if(classname[0]=='F' && classname[1]=='X' && classname[2]=='R' && classname[3]=='b'){
// FXWindow destructor calls recalc() and changeFocus() of it's parent window.
// Since these methods are routed back to Ruby code, but calling Ruby code from
// GC isn't a good idea, we mark the parent window as "in_gc", so that it will
// ignore recalc() and changeFocus() calls completely.
// The parent window should also be scheduled to be free'd. In the other case,
// the child window would have been marked as used.
if(self->isMemberOf(FXMETACLASS(FXWindow))){
if(FXWindow *parent = dynamic_cast<FXWindow*>(self)->getParent()){
FXRbSetInGCRecursive( parent, true );
}
}
delete self; delete self;
} }
else{ else{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment