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: gc notes available



> > This will likely depend upon memory protection services in the host
> > os, but any os that doesn't provide this probably isn't running
> > guile in the first place. 
> 
> This is bad news for us, if it catches on.
> 
> We are putting guile to work in our router product, and that has no
> fancy memory protection. Don't forget embedded systems, even if we are
> only a few (one?) currently.


Here's an excerpt from a message I just sent Greg Harvey.  I have some
tentative problems with using memory protection:

-----

I actually think that memory protection will be much slower than doing it
all in software.  Here are the steps involved in handling a page
fault:

    1) The kernel gets the page fault, puts together a signal context,
       and invokes the handler.
    2) The handler does the bookkeeping which is the real point of the
       exercise.
    3) Now the handler has to actually do the write.  In order for
       that write to succeed without causing yet another page fault,
       you have to somehow:
	a) unprotect the page
	b) do the write
	c) re-protect the page, to catch the next write

So you're talking signal handling overhead, and at least two system
calls.  Notice also that the handler can't really find the SCM object
being modified; it only gets the address being written to, and
probably the value being written to it.  But you can't find the cell
at the head of the vector, given the address of some word in the
malloc'ed array of elements.
  
Suppose we tell people that they must call SCM_WRITE_BARRIER (obj,
new) after changing any field in OBJ to point to NEW.  So, for
example:

	SCM_VELTS (vector)[5] = some_object;
	scm_write_barrier (vector, some_object);

The thing is, they *know* when they write the code that they're going to
do a write, so they might as well call the write barrier directly.
Then you've got function call overhead (which is less than signal
dispatch overhead) and bookkeeping.  No system calls.  And you also
get the information you actually want: the object being modified.  So
you can check the generations of the objects, and if vector is older
than some_object, then you stick vector in a list of objects to be
used as roots when collecting younger generations.

The only weirdness here is: what if someone doesn't know they're
mutating an object?  What if they've just got a pointer to an SCM, and
they're storing something in it?  What if they've just got a void *,
and they're copying bytes from another void * into it?  I think the
answer here is that whoever gave them that pointer must have had the
real SCM, and it's the SCM holder's job to make sure the write barrier
gets called appropriately.  Thus:

	frob (SCM_CDRLOC (pair));
	scm_write_barrier (pair, SCM_NEWEST);

SCM_NEWEST would be a magic value which tells the write barrier, "I
don't know what I stored; I may or may not have pointers to younger
objects now."