From: ts Date: 2007-04-09T18:39:51+09:00 Subject: Re: rb_yield(), break, and C extensions >>>>> "N" == Noah Easterly writes: N> So the original definition of func (which allocated memory, used the N> callback, freed memory, and didn't use ruby.h) won't work, I need to N> divide that into 3 parts (one to alloc, one that uses the callback, N> and one to free), and do something like: Well, the best is to let ruby manage the memory (with its GC), but if you have an original C function that you *can't* modify and you need to give it a callback, you can still write *something* like this moulon% cat a.c #include void func( int n, int (*callback)(void) ) { int i; for (i = 0; i < n; i++) { if (callback() < 0) { goto cleanup; } } rb_warn("normal exit"); cleanup: rb_warn("cleanup"); return; } static int meth_callback(void) { int state; rb_protect(rb_yield, 0, &state); if (state) { rb_thread_local_aset(rb_thread_current(), rb_intern("_test"), INT2NUM(state)); return -1; } return 0; } static VALUE yyy_meth(VALUE self, VALUE count) { VALUE res; rb_thread_local_aset(rb_thread_current(), rb_intern("_test"), INT2NUM(0)); func(FIX2INT(count), meth_callback); res = rb_thread_local_aref(rb_thread_current(), rb_intern("_test")); if (FIXNUM_P(res) && NUM2INT(res) != 0) { rb_thread_local_aset(rb_thread_current(), rb_intern("_test"), INT2NUM(0)); rb_warn("rb_jump_tag"); rb_jump_tag(NUM2INT(res)); } return Qnil; } void Init_a() { VALUE a_cM; a_cM = rb_define_class("YYY", rb_cObject); rb_define_method(a_cM, "meth", yyy_meth, 1); } moulon% moulon% cat b.rb #!/usr/bin/ruby require 'a' def m(a) puts "before" a.meth(6) { return } puts "after" end puts "before m" m(YYY.new) puts "after m" moulon% moulon% ./b.rb before m before ./b.rb:6: warning: cleanup ./b.rb:6: warning: rb_jump_tag after m moulon% Guy Decoux