extending/embedding ruby (callbacks) [LONG]

Discussion in 'Ruby' started by Peter Schrammel, Jan 13, 2005.

  1. 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 <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("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
    Peter Schrammel, Jan 13, 2005
    #1
    1. Advertising

  2. 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,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 <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("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.
    >


    *** see above ***
    > 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)
    >


    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_str_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_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);
    > }
    >

    (...)

    -Charlie
    Charles Mills, Jan 13, 2005
    #2
    1. Advertising

  3. 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("RFiller"));
    rfiller_instance=rb_funcall(rfiller_class,rb_intern("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
    Peter Schrammel, Jan 13, 2005
    #3
  4. 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?action=browse&id=GCAndExtensions

    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("RFiller"));
    > rfiller_instance=rb_funcall(rfiller_class,rb_intern("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
    Charles Mills, Jan 13, 2005
    #4
  5. Peter Schrammel

    ts Guest

    >>>>> "P" == Peter Schrammel <> 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
    ts, Jan 14, 2005
    #5
  6. Peter Schrammel

    ts Guest

    >>>>> "t" == ts <> 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
    ts, Jan 14, 2005
    #6
  7. ts schrieb:
    >>>>>>"t" == ts <> 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
    Peter Schrammel, Jan 14, 2005
    #7
  8. [n00b] C++ extensions, GC, Ruby and SWIG

    ---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--
    Asbjørn Reglund Thorsen, Jan 15, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. George Marsaglia

    Assigning unsigned long to unsigned long long

    George Marsaglia, Jul 8, 2003, in forum: C Programming
    Replies:
    1
    Views:
    659
    Eric Sosman
    Jul 8, 2003
  2. Daniel Rudy

    unsigned long long int to long double

    Daniel Rudy, Sep 19, 2005, in forum: C Programming
    Replies:
    5
    Views:
    1,178
    Peter Shaggy Haywood
    Sep 20, 2005
  3. Mathieu Dutour

    long long and long

    Mathieu Dutour, Jul 17, 2007, in forum: C Programming
    Replies:
    4
    Views:
    460
    santosh
    Jul 24, 2007
  4. Basile STARYNKEVITCH
    Replies:
    0
    Views:
    102
    Basile STARYNKEVITCH
    Sep 2, 2003
  5. John Smith

    embedding ruby (*not* extending)

    John Smith, Mar 27, 2008, in forum: Ruby
    Replies:
    7
    Views:
    120
    Bill Kelly
    Mar 28, 2008
Loading...

Share This Page