[MLton] adding synchronous finalizers

Stephen Weeks MLton@mlton.org
Wed, 29 Sep 2004 17:07:07 -0700


> The idea of a single-threaded program manually clearing out finalizers sounds
> good, but do we really want this to be a run-time or a compile-time decision.
> Perhaps I am thinking too much about the optimizations we lose when  multiple
> threads  exist, but I would think that the distinction between multi-threaded
> and single-threaded is almost certainly going to be known  at  compile  time.
> Hence it should be set by a compile-time flag.

I agree that it will usually be known at compile time.  But I'm not
sure that it always will, so it seems more flexible to make it a bool
ref.  It's also a bit easier (although not so bad now that we have
nice support for compile-time constants).

As to the performance, I think the implementation can be set up so
that if one wants synchronous finalizers, then the GC signal handler
won't even be used.  But I'm not sure if it's possible to go the extra
step of convincing MLton's dead-code pass to eliminate all the thread
stuff.  And I'm not sure it's worth the effort -- perhaps we should
spend more effort smoothing out the performance dropoff of programs
that use threads or finalizers (actually, I'm not really sure it's
that big of a dropoff these days, but it might be).

> Speaking  of  finalizers,  I  would think that the exact same arguments would
> apply to signals.
> 
> I.e., what we really want is a  flag  (indicating  now  signal  checking  nor
> finalization  running  automatically)  and  a single function, something link
> MLton.poll of type unit -> unit which runs any finalizers  waiting  and  also
> handles any pending signals.

Makes sense, in principle.  The problem is that we expose a more
complicated interface to normal signal handlers than we do to the GC
signal handler.  Normal signal handlers are of type

	MLton.Thread.Runnable.t -> MLton.Thread.Runnable.t

while all we expose about the GC signal is the MLton.Finalizable
interface, which includes

	val addFinalizer: 'a t * ('a -> unit) -> unit

Hence, it's quite easy to understand what it means to run the
finalizers synchronously -- apply each finalizer to the appropriate
value and continue with the main thread.

For normal signal handlers, their semantics allows them to change
threads by returning a thread other than the one they are passed.  How
should we package that into a poll function?