Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > extending/embedding ruby (callbacks) [LONG]

Reply
Thread Tools

extending/embedding ruby (callbacks) [LONG]

 
 
Peter Schrammel
Guest
Posts: n/a
 
      01-13-2005
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,}
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 <linux/stat.h>

#include <ruby.h>
#include <fuse.h>
#include <errno.h>
#include <sys/statfs.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#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("R Filler"));

//***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_inter n("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_st r_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_ne w,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.p...1.61&view=auto


Bye

Peter
 
Reply With Quote
 
 
 
 
Charles Mills
Guest
Posts: n/a
 
      01-13-2005

Peter Schrammel wrote:
>(...)
> I'd like to implement this as an extension so the testcode should

look
> like this:


It may help if you explain what your trying to do a bit more.

>
> #!/usr/bin/ruby
> require("RFuse")
>
> class RFuse
> def getdir(path,filler)
> Dir.foreach(path) {|x| filler.push(x,}
> 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 <linux/stat.h>
>
> #include <ruby.h>
> #include <fuse.h>
> #include <errno.h>
> #include <sys/statfs.h>
> #ifdef HAVE_SETXATTR
> #include <sys/xattr.h>
> #endif
>
>
> //This is a wrapper around the filler callback function
> struct fill_t {
> fuse_dirfil_t filler;
> fuse_dirh_t handler;
> };
>


the function below should be registered using rb_define_alloc_func()
and is typically called rfill_alloc()

> 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("R Filler"));
>
> //***the following line seems to be the problem. If I comment

everything
> out between here and "return 0" it runs okay... though nothing

happens.
>


*** see above ***
> rfiller_instance=rb_funcall(rfiller_class,rb_inter n("new"),0);
> //BTW: I can't do the rb_class_new_instance here STRANGE!
>
> //***commenting out from here gives me strange errors (see bellow)
>


you don't need this, if your worried about rfiller_instance being GC'ed
make it volatile.
> 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;


not sure how the flow of control goes in your program but seems pretty
obvious you have infinite recursion going on right here.
>

rb_funcall(global_self,rb_intern("getdir"),2,rb_st r_new2(path),rfiller_instance);

>


don't need this either
> //destroy the filler...
> rb_gc_unregister_address(&rfiller_instance);
> return 0;
> }
>

(...)
>
> void Init_RFuse() {
> VALUE cRFuse=rb_define_class("RFuse",rb_cObject);


should be using rb_define_alloc_func() as noted above

> 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_ne w,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);
> }
>

(...)

-Charlie

 
Reply With Quote
 
 
 
 
Peter Schrammel
Guest
Posts: n/a
 
      01-13-2005
Charles Mills schrieb:
> Peter Schrammel wrote:
> It may help if you explain what your trying to do a bit more.

OK:
The ruby part just does one thing:
extend the RFuse Class with some methods:
getdir
getattr

Then it creates a RFuse object a calls main on it.

main is in C: It registers the wrapper functions "rf_getdir",
"rf_getattr" to fuse and calls the main function of fuse, so the ruby
programm is sleeping and waiting.

if somebody does a "ls /tmp/fuse" the fuse system calls the registered
function rf_getdir with 3 args:
path, handler, filler
where
path is the requested path
handler is a hanlde used by filler
filler is a function, that takes 3 args: handler,string,mode

now rf_getdir should do the following:
create an object of RFiller(set the filler fuction and the handler) and
pass the path, and the Rfiller object to self.getdir (on the ruby side).

self.getdir calls filler.push("filename",mode) and returns

the RFiller object should be destroyed now and rf_getdir is done.

The problem is:
even if I don't call ruby's getdir method I have endless recursions.

>
>
> the function below should be registered using rb_define_alloc_func()
> and is typically called rfill_alloc()


done that...thanks

>
> you don't need this, if your worried about rfiller_instance being GC'ed
> make it volatile.


how to do this? sorry my ruby extension programming is at newbie level

>
>
> not sure how the flow of control goes in your program but seems pretty
> obvious you have infinite recursion going on right here.
>

ok: But if I do just this:
static int rf_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t f)
{
VALUE rfiller_class;
VALUE rfiller_instance;
rfiller_class=rb_const_get(rb_cObject,rb_intern("R Filler"));
rfiller_instance=rb_funcall(rfiller_class,rb_inter n("new"),0);
// no call to anything!
return 0;
}

I still get the same error...
Commenting out the "rfiller_instance="... line everything is all right.

To me it seems the GC wakes up one in a while does something ...
strange. Or I run out of memory because the GC never wakes up.


Peter
 
Reply With Quote
 
Charles Mills
Guest
Posts: n/a
 
      01-13-2005

Peter Schrammel wrote:
> Charles Mills schrieb:
> > Peter Schrammel wrote:
> > It may help if you explain what your trying to do a bit more.

> OK:
> The ruby part just does one thing:
> extend the RFuse Class with some methods:
> getdir
> getattr
>
> Then it creates a RFuse object a calls main on it.
>
> main is in C: It registers the wrapper functions "rf_getdir",
> "rf_getattr" to fuse and calls the main function of fuse, so the ruby


> programm is sleeping and waiting.
>
> if somebody does a "ls /tmp/fuse" the fuse system calls the

registered
> function rf_getdir with 3 args:
> path, handler, filler
> where
> path is the requested path
> handler is a hanlde used by filler
> filler is a function, that takes 3 args: handler,string,mode
>
> now rf_getdir should do the following:
> create an object of RFiller(set the filler fuction and the handler)

and
> pass the path, and the Rfiller object to self.getdir (on the ruby

side).
>
> self.getdir calls filler.push("filename",mode) and returns
>
> the RFiller object should be destroyed now and rf_getdir is done.
>
> The problem is:
> even if I don't call ruby's getdir method I have endless recursions.
>
> >
> >
> > the function below should be registered using

rb_define_alloc_func()
> > and is typically called rfill_alloc()

>
> done that...thanks
>
> >
> > you don't need this, if your worried about rfiller_instance being

GC'ed
> > make it volatile.

>
> how to do this? sorry my ruby extension programming is at newbie

level

no worries. you should read this:
http://www.rubygarden.com/ruby/ruby?...CAndExtensions

volatile is a C keyword/qualifier.

>
> >
> >
> > not sure how the flow of control goes in your program but seems

pretty
> > obvious you have infinite recursion going on right here.
> >

> ok: But if I do just this:
> static int rf_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t

f)
> {
> VALUE rfiller_class;
> VALUE rfiller_instance;
> rfiller_class=rb_const_get(rb_cObject,rb_intern("R Filler"));
> rfiller_instance=rb_funcall(rfiller_class,rb_inter n("new"),0);
> // no call to anything!
> return 0;
> }
>
> I still get the same error...
> Commenting out the "rfiller_instance="... line everything is all

right.
>
> To me it seems the GC wakes up one in a while does something ...
> strange. Or I run out of memory because the GC never wakes up.
>


Maybe you should start with something smaller. Probably something that
doesn't use function pointers. Perhaps there is a way to test the
classes individually... or you could add some sanity tests.

-Charlie

 
Reply With Quote
 
ts
Guest
Posts: n/a
 
      01-14-2005
>>>>> "P" == Peter Schrammel <(E-Mail Removed)> writes:


try it with

P> static VALUE rf_main(VALUE self){
P> char* argv[2];
P> int ret;
P> argv[0]="test-rfuse";
P> argv[1]="/tmp/fuse";

char* argv[3];
int ret;
argv[0]="-s";
argv[1]="test-rfuse";
argv[2]="/tmp/fuse";

P> struct fuse_operations *fuseop;

P> Data_Get_Struct(self,struct fuse_operations,fuseop);
P> ret = fuse_main(2,argv,fuseop);

ret = fuse_main(3,argv,fuseop);

P> return Qnil;
P> }

or something like this


Guy Decoux


 
Reply With Quote
 
ts
Guest
Posts: n/a
 
      01-14-2005
>>>>> "t" == ts <(E-Mail Removed)> writes:

This is wrong ((

t> argv[0]="-s";
t> argv[1]="test-rfuse";
t> argv[2]="/tmp/fuse";

argv[0]="test-rfuse";
argv[1]="/tmp/fuse";
argv[2]="-s";

Guy Decoux




 
Reply With Quote
 
Peter Schrammel
Guest
Posts: n/a
 
      01-14-2005
ts schrieb:
>>>>>>"t" == ts <(E-Mail Removed)> writes:

>
>
> This is wrong ((
>
> t> argv[0]="-s";
> t> argv[1]="test-rfuse";
> t> argv[2]="/tmp/fuse";
>
> argv[0]="test-rfuse";
> argv[1]="/tmp/fuse";
> argv[2]="-s";
>
> Guy Decoux


Yes... that's it. It wasn't ruby's fault at all but some kind of race
conditions with multithreaded FUSE. Thanks everybody.

Peter
 
Reply With Quote
 
Asbjørn Reglund Thorsen
Guest
Posts: n/a
 
      01-15-2005
---259931839-1996686507-1105794351=:19693
Content-Type: MULTIPART/MIXED; BOUNDARY="-259931839-1996686507-1105794351=:19693"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---259931839-1996686507-1105794351=:19693
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE


I`m having trouble with an interface to a c++ library. It seems like=20
Ruby`s GC is collecting objects that it shouldn`t. I have read the=20
SWIG-Ruby
documentation on the matter, but I am unsure of where to put the markfunc=
=20
, and how to get it to interact with my program.

My interface file : mHeat1.i
My Ruby code : run.rb

require 'mHeat1'

menu =3D MHeat1::MenuSystem.new
menu.init("Ruby Interface", "This is so cool !")
heat =3D MHeat1::Heat1.new
heat.define(menu)
heat.scan
heat.solveProblem
heat.resultReport

The problem is the MenuSystem, I found out by using gdb:
gdb ruby
(gdb)run run.rb

=2E..

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16384 (LWP 1345)]
0x00000089 in ?? ()
(gdb) where
#0 0x00000089 in ?? ()
#1 0x40388c19 in free_MenuSystem () from ./mHeat1.so
#2 0x0806f636 in rb_gc_call_finalizer_at_exit () at gc.c:1858
#3 0x08053e34 in ruby_finalize_1 () at eval.c:1418
#4 0x08053f43 in ruby_cleanup (ex=3D0) at eval.c:1453
#5 0x08054081 in ruby_stop (ex=3D135573240) at eval.c:1484
#6 0x080540ef in ruby_run () at eval.c:1505
#7 0x08052245 in main (argc=3D135573240, argv=3D0x814aef8, envp=3D0xbffff0=
20)
at main.c:46

Is it possible to use the %marcfunc directive in this case ? And how ?
I am a n00b at this, so I`d really like some help/tips.

</asbj=F8rn>
---259931839-1996686507-1105794351=:19693--
---259931839-1996686507-1105794351=:19693--


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Ruby extension (C++) on OS X [ruby 1.8.2] and Google-Sketchup [ruby 1.8.5] Nicholas Ruby 3 01-28-2007 01:48 AM
The Ruby Edge - Digg for Ruby and Ruby On Rails roschler Ruby 0 10-15-2006 11:35 PM
ruby-talk, comp.lang.ruby, ruby-talk-google Phrogz Ruby 4 09-06-2006 06:43 PM
#!/usr/bin/ruby , #!/usr/bin/ruby -w , #!/usr/bin/ruby -T?, #!/usr/bin/ruby -T1... anne001 Ruby 1 04-23-2006 03:02 PM
[ANN] ruby-freedb, ruby-serialport, ruby-mp3info moved to Rubyforge guillaume.pierronnet@ratp.fr Ruby 0 08-31-2003 11:57 PM



Advertisments