[plt-scheme] Finalizer or custodian for extension's resources?
Hi,
I'm a bit confused on how to tackle resources that need deallocation in
MzScheme extensions. I have tried both scheme_register_finalizer on the
void* itself, and scheme_add_managed on the object containing the void*
but neither does exactly what I want. The former only seems to call the
deallocation function on garbage collection of the resource, the latter
only when the program ends. But the resource would have to be
deallocated in both cases. How can I do this?
Regards,
Dirk Gerrits
To illustrate the matter, here are the test-code and interactions which
made me arrive at the above conclusions:
#include "escheme.h"
#include <fstream>
using namespace std;
class Foo
{
public:
Foo()
{
ofstream my_log("log2.txt");
my_log << "Foo() ";
};
~Foo()
{
ofstream my_log("log2.txt", ios_base::app);
my_log << "~Foo() ";
};
};
Scheme_Object* func(void* data, int argc, Scheme_Object* argv[])
{
Foo& foo = *static_cast<Foo*>(data);
// use foo and arguments here
return scheme_void;
}
void destroy_foo(void* p, void*) // #1
void destroy_foo(Scheme_Object*, void* p) // #2
{
Foo* foo = static_cast<Foo*>(p);
foo->~Foo();
}
Scheme_Object* create_func(int argc, Scheme_Object* argv[])
{
void* foo = scheme_malloc_atomic(sizeof(Foo));
new (foo) Foo;
scheme_register_finalizer(foo, &destroy_foo, 0, 0, 0); // #1
Scheme_Object* proc = scheme_make_closed_prim_w_arity(
&func,
foo,
"func",
0, 0);
scheme_add_managed(0, proc, &destroy_foo, foo, 0); // #2
return proc;
};
extern "C" Scheme_Object* scheme_initialize(Scheme_Env* env)
{
scheme_add_global("create-func",
scheme_make_prim_w_arity(&create_func, "create-func", 0, 0),
env);
return scheme_void;
}
extern "C" Scheme_Object* scheme_reload(Scheme_Env *env)
{
return scheme_initialize(env);
}
extern "C" Scheme_Object* scheme_module_name()
{
return scheme_false;
}
Compiling it with with the #2 lines commented out (ie using a finalizer):
DrScheme: (define func (create-func))
Log after evaluation: Foo()
Log after exit: Foo()
DrScheme: (create-func) (collect-garbage)
Log after evaluation: Foo() ~Foo()
Log after exit: Foo() ~Foo()
Compiling it with with the #1 lines commented out (ie using a custodian):
DrScheme: (define func (create-func))
Log after evaluation: Foo()
Log after exit: Foo() ~Foo()
DrScheme: (create-func) (collect-garbage)
Log after evaluation: Foo()
Log after exit: Foo()
Compiling it with with the #1 lines commented out (ie using a custodian)
and with strong=1 in the call to scheme_add_managed:
DrScheme: (define func (create-func))
Log after evaluation: Foo()
Log after exit: Foo() ~Foo()
DrScheme: (create-func) (collect-garbage)
Log after evaluation: Foo()
Log after exit: Foo() ~Foo()
This last approach at least 'does the right thing', but it's too
conservative.