From: Peter Schrammel Date: 2005-01-13T23:56:20+09:00 Subject: extending/embedding ruby (callbacks) [LONG] Hi, I try to implement an interface for fuse with ruby but fail to a strange error. You probably won't try this code because you'd have to install fuse to test it so I give some comments: I'd like to implement this as an extension so the testcode should look like this: #!/usr/bin/ruby require("RFuse") class RFuse def getdir(path,filler) Dir.foreach(path) {|x| filler.push(x,8)} end def getattr(path) end end fo=RFuse.new begin fo.main rescue f=File.new("/tmp/error","w+") f.puts "Error:" + $! f.close end The user should just extend the class with some methods which will be called back by fuse. So I have to wrap the callbacks. The interesting line is at ***. #ifdef linux /* For pread()/pwrite() */ #define _XOPEN_SOURCE 500 #endif //FOR LINUX ONLY #include #include #include #include #include #ifdef HAVE_SETXATTR #include #endif //This is a wrapper around the filler callback function struct fill_t { fuse_dirfil_t filler; fuse_dirh_t handler; }; static VALUE rfill_new(VALUE class){ VALUE self; struct fill_t *filler; self = Data_Make_Struct(class, struct fill_t, 0,free,filler); return self; } static VALUE rfill_push(VALUE self,VALUE name, VALUE type) { struct fill_t *fill; Data_Get_Struct(self,struct fill_t,fill); fill->filler(fill->handler,STR2CSTR(name),NUM2INT(type)); return self; } //------------------ static VALUE global_self; //TODO: have to avoid global vars //call getdir with that an RFiller object static int rf_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t f) { VALUE rfiller_class; VALUE rfiller_instance; struct fill_t *fillerc; rfiller_class=rb_const_get(rb_cObject,rb_intern("RFiller")); //***the following line seems to be the problem. If I comment everything out between here and "return 0" it runs okay... though nothing happens. rfiller_instance=rb_funcall(rfiller_class,rb_intern("new"),0); //BTW: I can't do the rb_class_new_instance here STRANGE! //***commenting out from here gives me strange errors (see bellow) rb_gc_register_address(&rfiller_instance);//Do I need this? Data_Get_Struct(rfiller_instance,struct fill_t,fillerc); fillerc->filler=f;//Init the filler by hand....not nice... fillerc->handler=h; rb_funcall(global_self,rb_intern("getdir"),2,rb_str_new2(path),rfiller_instance); //destroy the filler... rb_gc_unregister_address(&rfiller_instance); return 0; } //calls getattr with path and expects a File::Stat back static int rf_getattr(const char *path, struct stat *stbuf) { int res; //For testing only res = lstat(path, stbuf); return 0; } static VALUE rf_main(VALUE self){ char* argv[2]; int ret; argv[0]="test-rfuse"; argv[1]="/tmp/fuse"; struct fuse_operations *fuseop; Data_Get_Struct(self,struct fuse_operations,fuseop); ret = fuse_main(2,argv,fuseop); return Qnil; } static VALUE rf_init(VALUE self){ return self; } static VALUE rf_new(VALUE class){ VALUE self; struct fuse_operations *fuseop; self = Data_Make_Struct(class, struct fuse_operations, 0,free,fuseop); fuseop->getattr=rf_getattr; fuseop->getdir=rf_getdir; rb_obj_call_init(self,0,0); global_self=self; //TODO: hide this... return self; } void Init_RFuse() { VALUE cRFuse=rb_define_class("RFuse",rb_cObject); rb_define_singleton_method(cRFuse,"new",rf_new,0); rb_define_method(cRFuse,"initialize",rf_init,0); rb_define_method(cRFuse,"main",rf_main,0); VALUE cRFiller=rb_define_class("RFiller",rb_cObject); rb_define_singleton_method(cRFiller,"new",rfill_new,0); //rb_define_method(cRFiller,"initialize",rfill_init,0); rb_define_method(cRFiller,"push",rfill_push,2); // rb_define_method(cRFiller,"test",rfill_test,0); } After starting the progam and doing some (=up to 25) "ls /tmp/fuse" the programm crashes cat /tmp/error says: Error:stack level too deep I think that I missed some cleanupcode... Help I very much appreciated (my C isn't the best). The interface of fuse is at: http://cvs.sourceforge.net/viewcvs.py/fuse/fuse/include/fuse.h?rev=1.61&view=auto Bye Peter