[redland-dev] implicit free

Norman Gray norman at astro.gla.ac.uk
Fri Nov 25 15:37:27 CET 2011


Maxence, hello.

On 25 Nov 2011, at 14:16, Maxence Guesdon wrote:

>> 
>> These structs are therefore conceptually 'owned' by the Racket layer, so where the librdf documentation notes that a returned object is shared, I make a copy of it using one of the librdf copy-create functions. 
> 
> That is: 
> - when you retrieve an already existing object (with a foo_get... function for
>  example), you make a copy and make the gc call the free function on this
>  copy when the value is no more reachabe,

I typically wouldn't make a copy in that case, since most of these cases are documented to return a new librdf object.  That's a new object in the sense that it is the caller's (ie my) responsibility to free it when it is no longer needed.

In some cases, the library documents that the object (or string, or whatever) is a _shared_ object.  In this case, the caller must not free it.  In this case, I explicitly make a copy using, say, librdf_new_uri_from_uri: that returns a 'new' object, which is what I wrap in a scheme object and return.  Now, internally, this librdf 'copy' may be the same as the original, but with an incremented reference count, but that's nothing to do with me.

> - when you create an object, you don't make a copy, but you just embed it
>  in a racket value.

That's correct.  The created object is (implicitly) documented not to be shared, so that it's my responsibility to manage it and free it when necessary.

> Is so, that's the way I began to before being afraid of freeing objects
> still in use. I wasn't aware of the counter already used internally.

You shouldn't need to be aware of the counter used internally.  As long as you don't attempt to call librdf_free_* on an object documented to be shared, but do call librdf_free_* for every object that's not documented to be shared, you should be fine.

Below, in case it's useful, is an illustration of the code for the FFI function wrapping librdf_new_model.  All of these details are for the Racket FFI, of course, but I imagine there'll be very closely analogous things for the OCaml FFI.

static Scheme_Object* wrap_librdf_new_model (int argc, Scheme_Object **argv){
    librdf_model* model;
    librdf_world* world = 0;librdf_storage* storage = 0;char* model_uri = 0;

    /* blah blah blah handle arguments */

    if ((model = librdf_new_model(world, storage, model_uri)) == NULL) {
        scheme_signal_error("Unable to construct Model");
    }
    /* model is now a new librdf object
    {
        Scheme_Object* result = NULL;
        /* hairy bookkeeping */
        MZ_GC_DECL_REG(1);
        MZ_GC_VAR_IN_REG(0, result);
        MZ_GC_REG();
        /* wrap this in a Scheme object */
        result = scheme_make_cptr(model, scheme_intern_symbol("librdf-model"));
        /* register the new object with the appropriate custodian function */
        scheme_add_managed(NULL, result, mzrdf_model_custodian, (void*)&mzrdf_marker, 0);
        MZ_GC_UNREG();
        return result;
    }
}

And here, for comparison, is my custodian function.  This is called by the GC just before it 'forgets' about a scheme object.

void mzrdf_model_custodian(Scheme_Object *o, void* data) {
    librdf_model *model;
    /* sanity check */
    if (! (is_model_p(o))) { scheme_signal_error("librdf assertion [is_model_p(o)] failed in %s: model_custodian not given a model object; given %V instead", __func__, o); }
    /* retrieve the librdf object from the scheme object */
    model = (librdf_model *)SCHEME_CPTR_VAL(o);
    /* call the librdf_free_model function */
    if (model != NULL) librdf_free_model(model);
}



-- 
Norman Gray  :  http://nxg.me.uk



More information about the redland-dev mailing list