[plt-scheme] Finalizer or custodian for extension's resources?

From: Dirk Gerrits (dirk at gerrits.homeip.net)
Date: Sun Jul 13 14:10:56 EDT 2003

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.




Posted on the users mailing list.