This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Guile, C, and Garbage Collection


I'd like to add some information in addition to what Maciej has
said.

Daniel R Risacher <risacher@worldnet.att.net> writes:

[...]

> Suppose your C library has data types Foo and Bar.  
> A Foo can contain a pointer to a Bar.  You write the functions
> Clib-make-new-foo, Clib-make-new-bar, and
> Clib-foo-set-pointer-to-bar. 

[...]

> What is the "right way" to solve this dilemma?  Is there one?

Yes, in my view there is a "right way".

The problem you're describing, keeping track of references and
allocated memory, is the natural task for the garbage collector.

So, you have to tell the garbage collector that Foo points to Bar
somehow.  Luckily, this is possible and quite easy.

The natural way to wrap C data types in Guile is by using smobs:

*** Declaration of the C level structure containing a reference to bar

struct foo {
  ...
  SCM bar;
  ...
};

*** This is the type tag

long foo_type;

*** The constructor

SCM_PROC (s_make_foo, "make-foo", 0, 0, 0, scm_make_foo);

SCM
scm_make_foo ()
{
  SCM z;
  char *foo = scm_must_malloc (sizeof (struct foo), s_make_foo);
  SCM_NEWCELL (z);
  SCM_DEFER_INTS;
  SCM_SETCDR (z, foo);
  SCM_SETCAR (z, foo_type);
  SCM_ALLOW_INTS;
  return z;
}

*** This function tells the garbage collector how to mark foo objects.
*** This is where we make it aware of the reference to bar.

static SCM
markfoo (SCM obj)
{
  SCM_SETGC8MARK (obj);  /* Mark the smob itself. */
  /* The garbage collector continues to mark whatever we return. */
  return ((struct foo *) SCM_CDR (obj))->bar;
}

*** Tell Guile how to free foo objects.

static scm_sizet 
freefoo (SCM obj)
{
  scm_must_free ((char*) SCM_CDR (obj));
  return sizeof (struct foo);
}

*** Tell Guile how to print foo objects.

static int 
prinarb (exp, port, pstate)
     SCM exp;
     SCM port;
     scm_print_state *pstate;
{
  scm_gen_puts (scm_regular_string, "#<foo>", port);
  return 1;
}

*** This struct defines the smob data type foo

static scm_smobfuns foosmob =
{
  markfoo, freefoo, prinfoo, 0
};

*** This is the init function of the file defining foo.
*** Use `guile-snarf' to produce "foo.x".  (See libguile Makefile.)

void
scm_init_foo ()
{
  foo_type = scm_newsmob (&foosmob);
#include "foo.x"
}


Above, I have assumed that `bar' is also wrapped by a smob type, and
that the foo struct points to this Scheme object.  As Maciej said,
things needs to be handled differently if we lack a pointer to the
Scheme object, but this is a situation I'd try to avoid.

Best regards,
/mdj