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.s...
https://github.com/MLton/mlton/blob/master/basis-library/mlton/finalizable.s...
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.
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 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?
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. 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? 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? 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.
Finally, a couple of general issues:
- I was getting some unexpected behaviour with weak references using
Poly/ML 5.5.0 - see the following example. Poly/ML 5.5.2 behaved as expected though. Does that mean 5.5.0 should be avoided?
I can't remember any specific changes in that area but it's perfectly possible there has been a bug fix. Certainly I would avoid older releases.
- The function weakArray confuses me although I doubt I will need to
use it. It's not clear why it would be called with a reference, i.e. non-NONE argument because that is duplicated for every array element. Furthermore, if it is called with a non-NONE argument and the array size is more than 1, then this can crash Poly/ML. For example, entering the following in the top-level:
val wa = Weak.weakArray (2, SOME (ref ())); PolyML.fullGC (); wa; (* seg fault *)
There's obviously a bug in that area. It appears to be associated with the fact that the same token is being used at two different places in the array.
Regards, David