16/09/15 12:40, David Matthews wrote:
On 15/09/2015 22:18, Phil Clayton wrote:
I think weak references could do the job. Better still, I may be able
to adapt (shamelessly copy) MLtonFinalizable:
https://github.com/MLton/mlton/blob/master/basis-library/mlton/finalizable.sig
https://github.com/MLton/mlton/blob/master/basis-library/mlton/finalizable.sml
This would have the added bonus of a common interface for finalizable
values between the compilers.
The main question is when to check the weak references. Is there some
way to register a function to be called immediately after a GC? I'll
investigate using a separate thread and the mutex which may be better
anyway.
There's no way to register a function. Because of the way the thread
system works I think the only way to do the finalisation is through a
separate thread.
Understood. I think a separate thread is better anyway.
Finalizers should also be called when the ML session exits. It appears
that functions registered with OS.Process.atExit are always run before
Poly/ML exits (whether or not there is an explicit call to
OS.Process.exit). Can you confirm that?
The intention is that that should be the case. If OS.Process.terminate
is called the functions aren't run. I have just done a test and it
appears that exiting by calling Thread.Thread.exit() doesn't run the
atExit functions either.
I think the desirable behaviour is for finalizers to be run whenever
Poly/ML is ending its own process. For example, if SIGTERM causes
Poly/ML to exit, finalizers should be run because they are typically
performing clean-up operations. Is there a way to do that?
Also, even using OS.Process.atExit and exiting via OS.Process.exit, I am
finding that remaining finalizers aren't being run. After a call to
fullGC in the at-exit function, the weakly referenced values haven't
been garbage-collected, so their finalizers aren't run. Has the
lifespan of those values has not ended at that that point? (See my
other email for the example code.)
I was wondering how to implement the 'touch' function of
MLTON_FINALIZABLE that forces a weak reference to stay alive. The
expression
ignore (PolyML.pointerEq (x, x) orelse raise Fail "touch"; print "");
seems to prevent Poly/ML optimizing the dependence on x away and works
for any type x. Bizarrely, I found that without print "", the weak
reference stayed alive. Can you think of something simpler?
I looked at the MLton documentation and couldn't understand what "touch"
was trying to achieve. Could you explain it?
"touch t" prevents finalization of t until the call has been evaluated.
"touch t" an operation that uses t to do nothing, so t cannot be
garbage-collected until the operation has finished.
My idea with weak variables in Poly was that the "token" and the item to
be finalised would be linked in such a way that they would have the same
lifetime e.g. the "token" would be paired with the item.
With these finalizable values, no "item" is required, there is only a
"token". The token can be a reference to anything so we make it a
reference to the value that finalizers will be run on. All access to
the finalizable value is by dereferencing the token, so the token is
referenced as long as the finalizable value is used. This is ensured by
having an abstract type requiring Finalizable.withValue to be used to
access the value.
Is the issue
that a global optimising compiler such as MLton could work out that the
token was not referenced even though the item was and remove it from the
pair at the last reference?
I don't think that is the issue here (as we don't have an item).
Poly/ML only does that in very limited
circumstances. Is the idea of "touch" that this counts as a reference
to the token and that you add a call to it after each reference to the
item so that the lifetime of the token is no less than the lifetime of
the item?
Yes, but as there is no item, the purpose of touch is to delay
finalization until some other event has occurred. One example use of
touch is in the implementation of Finalizable.finalizeBefore. The
'other event' is finalization of another finalizable value.
Since the token is a reference either assigning or
dereferencing it should work. Even if the result is always () that
should still count as a reference.
I find that
ignore (!value)
doesn't keep the value alive whereas
value := !value
does. That was a useful suggestion - much more preferable to my earlier
idea. The assignment is doing work whose effect isn't required but is
that an overhead worth worrying about?
Phil
_______________________________________________
polyml mailing list
[email protected]
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml