On Tuesday 13 November 2001 12:05 pm, Ken Fox wrote:
> > Are _all_ handles (PMC's, Strings, or whatever) that serve as
> > root-set elements dynamically allocated?
>
> Nope. Part of the root set includes auto C PMC handles used by
> extensions. You also have to think about hardware registers too
> if GC is running in another thread.

I'm not worried about separate threads.  "Shared" handles are already allowed 
to be slow and thus few and far between.  Locking also alleviates most of the 
hangups.  Most of my thinking involves running much of the GC within a worker 
thread (spawned by allocs), so different interpreters are, for the most part, 
independant of each other, even in garbage collection.

My ideal is to only profile at alloc time, then hand off a job to a 
gc-thread, but so far there are more problems than worthwhile (especially 
with coping GCs).  The alternative is to enforce read/write barriers on code 
and do all aspects of GCing in another thread.  This avoids much pause-time, 
but all but requires multi-threading (something I'd rather not require for 
one-liners).

>
> IMHO the easiest way to code this is to define an API that
> extension writers use to declare every PMC handle. This code
> looks ugly and encourages bugs though so a lot of people don't
> like it. Many systems treat the C stack as conservative roots.
> Those systems flush the hardware registers to the C stack
> before running the collector. The benefit is that handles
> don't need to be declared. The cost is the non-portable code
> used to scan the C stack and flush the registers.

The various texts I'm reading suggest that memory management should be a 
black-box module.  It's easier to debug and use.. They suggest that too large 
a percentage time is devoted to memory management (leak-finding), so the less 
 XS-writers have to worry about memory, the more acceptance parrot will have 
IMHO. (Even if some performance or intermitant pausing is necessary... Though 
hopefully we'll be able to provide a choice between the two at run-time).

> Another simple solution is to suspend the collector while in
> extension code (or untrusted extension code). This works for
> lots of cases, but falls apart badly in callback/event-loop
> extensions that never return.

Unfortunately, this would require hooks into the mem-mngr module, which 
violates it's black-box nature.  Not to mention the points you make. 

> One nice thing about writing Perl extensions is that the "SV *"
> can be stuck in odd places. For example, I put them in X Toolkit
> and Motif widget "user data" slots. Once the "SV *" are stuck
> in the slots I have no idea what happens to them. This works fine
> because the ref count will keep the SV alive until the widget
> dies. A hybrid ref count GC with pinned PMCs will work exactly
> the same. If we get fancier though and either use movable
> PMCs or tracing collectors, then my "user data" slots become
> roots. That will crash and burn because I don't know how to
> register them. I'd have to use a separate array for holding the
> PMCs and then stick the array indexes into the widgets.

So long as SV* equivalents are registered as foreign access, then XS modules 
shouldn't have to worry.  Unfortunately this might cause memory leaks.  
Perhaps foreign access can utilize a reference count.. XS modules that don't 
directly utilize GC-able objects, register a newly allocated handle with 
foreign access, and are required to unregister it when they're done..  When a 
handle is unregistered as many times as it's registered, it's removed from 
the foreign access area, and thus it's contents are reclaimable.  Only 
remaining problem is in how the handle was acquired (hense my original 
question), since the handle needs to be reclaimed somehow, since the 
following is possible:

PMC* ptr = malloc(sizeof(PMC)); 
ptr = malloc(sizeof(PMC)); // memory leak

If allocations instead come from gc_malloc - or more likely from the arena 
newPMC(), then once the PMC is unregistered from foreign-access, XS-code can 
safely ignore it.  The only gotcha here is that XS code has to treat 
unregistering as if the PMC were being free'd (and optimizations will 
probably do exactly that).

Heck, I'm even thinking that there should be two forms of newPMC, one to be 
used within the root-set, and one used externally.  newPMC, and newPMCR (for 
registered).

It's still too early to see what's a good direction.

>
> It's probably not worth making my job as an extension
> writer easier if it slows/complicates the rest of the GC. Most
> extension writers are pretty good at this sort of thing and
> a special utility library for pseudo-pinned PMCs wouldn't be
> any big deal.

I don't really see a need for handles to be movable (especially if they're 
arena based), but reclaiming handles might require for some sort of 
extra record-fields.  Since handles are fixed sizes and decently big 
(several integers worth), I'm wanting to prepend next/prev pointers to the 
structure and maintain from/to/free lists.  A gc-invocation navigates the 
root set and moves those elements from the "from-list" to the "to-list".  
Remaining "from-list" items get appeneded to the "free-list", which for 
arena's is a constant time.  Depending on the buffer-object reclaiming 
method, either the newly free'd handles will have their associated objects 
reclaimed, or the migrated "from->to" objects will have their associated 
objects copied.  This is an example of something that can be done in a 
separate thread.  Navigating the handles is only a constant overhead 
over navigating the root-set (which is almost always unavoidable).  If the 
root-set for each thread isn't that large, then pauses won't be that great.  
The only problem with this approach is that I'd like to hide the "prev/next" 
pointers since they are part of the black-box, and not part of the utility of 
the handles.  But this requires some uniformity on how handles are created 
(ergo always from the arena).

Again, this is all in the early stages of research.

-Michael

Reply via email to