From: Noah Easterly Date: 2007-04-08T03:10:09+09:00 Subject: Re: rb_yield(), break, and C extensions On Apr 7, 1:08 pm, "Kent Sibilev" 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" Which makes sense if, when there is no break, the my_ensure func gets called (as it should), so processing skips to cleanup, and when there is a break, the ensure func does not get called, and processing skips back to the ruby script. I suppose I could switch to having people 'raise BreakException', rather than 'break' within the block, but that seems like its hobbling the ruby language. Thanks for the idea, though!