On 4/7/07, Kent Sibilev <ksruby / gmail.com> wrote: > On 4/7/07, Noah Easterly <noah.easterly / gmail.com> wrote: > > On Apr 7, 1:08 pm, "Kent Sibilev" <ksr... / gmail.com> wrote: > > > You should wrap your rb_yield call with rb_ensure. From README.EXT: > > > > > > VALUE rb_ensure(VALUE (*func1)(), void *arg1, void (*func2)(), void *arg2) > > > > > > Calls the function func1 with arg1 as the argument, then calls func2 > > > with arg2 if execution terminated. The return value from > > > rb_ensure() is that of func1. > > > > Hmm.... this doesn't seem to have the desired effect. I'm pretty sure > > rb_ensure() is just for handling exceptions, not breaks. > > > > According to ruby.h and the Pickaxe, the function def'n has changed a > > bit too. From Programming Ruby(2nd ed): > > > > VALUE rb_ensure(VALUE(*body)(), VALUE args, VALUE(*ensure)(), VALUE > > eargs) > > > > Executes body with the given args. Whether or not an exception is > > raised, execute ensure with the given eargs after body has completed. > > > > So it seems that rb_ensure is just for exceptions, not 'break'. I > > tried tweaking my code to use it anyway, but the ensure call is still > > bypassed when there is a break. For example: > > > > >>> lib.c > > void func( int n, int (*callback)(void) ) > > { > > printf("before callback...\n"); > > if (callback() < 0) > > goto cleanup; > > printf("after callback...\n"); > > cleanup: > > printf("in cleanup...\n"); > > } > > >>> ext.c > > static void > > my_ensure(void * ptr) > > { > > *(int *)ptr = -1; > > } > > static int > > meth_callback(void) > > { > > int retval = 0; > > rb_ensure(rb_yield, Qnil, my_ensure, &retval); > > return retval; > > } > > // ... > > >>> test.rb > > > > require 'ext' > > YYY.new.meth(100) { } # outputs "before callback...\n", "in cleanup... > > \n" > > YYY.new.meth(100) { break } # outputs "before callback...\n" > > > > What I meant was that your cleanup code should be in my_ensure > function and not in func itself. Just to prove my point: > > $ cat t.rb > def test > puts 'pre' > yield > puts 'post' > ensure > puts 'ensure' > end > > test {break} > > $ ruby t.rb > pre > ensure > > OK, maybe this code will clean things up: $ cat t.rb require 'rubygems' require 'inline' class MyTest inline do |builder| builder.prefix <<-EOC static VALUE func(VALUE arg) { printf("pre\\n"); rb_yield(arg); printf("post\\n"); return Qnil; } static VALUE cleanup(VALUE arg) { printf("ensure\\n"); return Qnil; } EOC builder.c <<-EOC void my_func() { rb_ensure(func, Qnil, cleanup, Qnil); } EOC end end MyTest.new.my_func {break} $ ruby t.rb pre ensure $ -- Kent --- http://www.datanoise.com