N
Noah Easterly
So, I'm working on a C extension.
One of my C functions uses a callback function, so when I wrap that
function in a method, I pass it a callback function that just wraps a
call to rb_yield().
This works great, except that when the block passed to the method
includes a 'break' statement, the end of the C function is bypassed,
and so it can't do its own cleanup.
What I'd like to do is "catch" the break somehow, so I can tell my C
function to exit and cleanup before restoring control to the ruby
script.
Is there any way to do this? I realize it could be a Bad Thing if
abused, but this is for good, I swear.
I guess I could try to pull all the memory allocation/file opening/etc
out to the containing object, but
[1] I'm not sure it's possible.
[2] It seems kind of awkward.
[3] This wouldn't solve the problem if I was linking in to an existing
object file that I didn't have source for.
Here's some toy code, if I didn't get my point across:
void func( int n, int (*callback)(void) )
{
void * mem = malloc(sizeof(int));
FILE * file = fopen("filename", "r");
int i;
// ... do stuff
for (i = 0; i < n; i++) { if (callback() < 0) { goto cleanup; } }
// ... do more stuff
cleanup:
if (mem) { free(mem); }
if (file) { fclose(file); }
}static int
meth_callback(void)
{
rb_yield(Qnil);
return 0;
}
static VALUE
yyy_meth(VALUE self, VALUE count)
{
func(FIX2INT(count), meth_callback);
return Qnil;
}require 'ext'
YYY.new.meth(100) { break }
One of my C functions uses a callback function, so when I wrap that
function in a method, I pass it a callback function that just wraps a
call to rb_yield().
This works great, except that when the block passed to the method
includes a 'break' statement, the end of the C function is bypassed,
and so it can't do its own cleanup.
What I'd like to do is "catch" the break somehow, so I can tell my C
function to exit and cleanup before restoring control to the ruby
script.
Is there any way to do this? I realize it could be a Bad Thing if
abused, but this is for good, I swear.
I guess I could try to pull all the memory allocation/file opening/etc
out to the containing object, but
[1] I'm not sure it's possible.
[2] It seems kind of awkward.
[3] This wouldn't solve the problem if I was linking in to an existing
object file that I didn't have source for.
Here's some toy code, if I didn't get my point across:
void func( int n, int (*callback)(void) )
{
void * mem = malloc(sizeof(int));
FILE * file = fopen("filename", "r");
int i;
// ... do stuff
for (i = 0; i < n; i++) { if (callback() < 0) { goto cleanup; } }
// ... do more stuff
cleanup:
if (mem) { free(mem); }
if (file) { fclose(file); }
}static int
meth_callback(void)
{
rb_yield(Qnil);
return 0;
}
static VALUE
yyy_meth(VALUE self, VALUE count)
{
func(FIX2INT(count), meth_callback);
return Qnil;
}require 'ext'
YYY.new.meth(100) { break }