Simon Marlow | 1 Dec 2008 17:17
Picon

Re: Weak pointers and STM

John Meacham wrote:
> Are there any caveats to using weak pointers and STM together? in
> particular, the two cases I am interested in are
> 
> 1. is using 'deRefWeak' fully safe inside 'unsafeIOtoSTM'? As in, will
> it combine arbitrary STM actions with checking if a weak pointer is
> still valid atomically?

You certainly can't use STM to wait until the result of deRefWeak changes 
with retry.  but that's probably not what you're asking.  It's certainly 
not atomic, in that the result of deRefWeak might be different at different 
points in the transaction.  Hmm, what property is it you want here?

> 2. is using an atomically retry safe inside of a finalizer? Will it
> introduce any concurrency bottlenecks or can I just consider code run in
> a finalizer just like code run in any other thread? 

Yes. Once running, a finalizer is just like another thread, with one 
exception: we batch finalizers that start together in a single thread, so 
if these finalizers need to communicate with each other, a deadlock could 
ensue.  This is fixable without too much difficulty though, so let us know 
if it is a problem for you.

> I just wanted to be sure before I base an integral component of a projects design
> on these working properly.

I'd be wary about relying on unsafeIOToSTM in any significant way.  We know 
it has some pretty severe drawbacks, for one thing if the transaction is 
aborted then the IO computation is just discarded, not sent an exception or 
anything (I think we have a ticket filed for this).
(Continue reading)

John Meacham | 2 Dec 2008 15:24
Favicon

Re: Weak pointers and STM

Well, the actual problem I am trying to solve involves properly
reclaiming elements in a  circularly linked list (next and prev pointers
are TVars). I have a linked list and I need to be able to remove values
from the list when all references to the node no longer exist, not
counting the linked list references themselves.

Using Weak pointers inside the list itself doesn't work, since if an
element is collected, you also lose the information needed to stitch up
the list.

Originally, I had a wacky plan involving weak pointers in the nodes
themselves pointing to sentinal nodes, when the sentinal was collected,
I then know I can delete the node. The idea was that I can lazily delete
entire chains of nodes rather than one by one. I gave up on that idea.
(deRefWeak not working in STM was sort of a show stopper, and it was
overly complicated)

So now I have a scheme whereby I attach a finalizer to a proxy thunk.

> data TimeStamp = TimeStamp TS
>
> data TS = TS {
>     tsWord :: TVar Word64,
>     tsPrev :: TVar TS,
>     tsNext :: TVar TS
>     }

so, the finalizer attached to 'TimeStamp' values simply deletes the
value it points to from the linked list. The module interface ensures
that only 'TimeStamp' values can escape and each has a finalizer
(Continue reading)

Simon Marlow | 4 Dec 2008 10:09
Picon

Re: Weak pointers and STM

John Meacham wrote:
> Well, the actual problem I am trying to solve involves properly
> reclaiming elements in a  circularly linked list (next and prev pointers
> are TVars). I have a linked list and I need to be able to remove values
> from the list when all references to the node no longer exist, not
> counting the linked list references themselves.
> 
> Using Weak pointers inside the list itself doesn't work, since if an
> element is collected, you also lose the information needed to stitch up
> the list.
> 
> Originally, I had a wacky plan involving weak pointers in the nodes
> themselves pointing to sentinal nodes, when the sentinal was collected,
> I then know I can delete the node. The idea was that I can lazily delete
> entire chains of nodes rather than one by one. I gave up on that idea.
> (deRefWeak not working in STM was sort of a show stopper, and it was
> overly complicated)
> 
> So now I have a scheme whereby I attach a finalizer to a proxy thunk.
> 
> 
>> data TimeStamp = TimeStamp TS
>>
>> data TS = TS {
>>     tsWord :: TVar Word64,
>>     tsPrev :: TVar TS,
>>     tsNext :: TVar TS
>>     }
> 
> so, the finalizer attached to 'TimeStamp' values simply deletes the
(Continue reading)

Claus Reinke | 7 Dec 2008 13:12

Re: Weak pointers and STM

> Adding finalizers to arbitrary objects was useful for the memo table 
> application we had in mind when weak pointers were introduced, but for all 
> the other applications I've come across since then, we really want to add 
> finalizers to objects whose lifetimes are under programmer control.  Notice 
> how ForeignPtrs attach the finalizer carefully to the MutVar# inside the 
> ForeignPtr, not the ForeignPtr itself.

One application that was effectively killed by GHC's approach to
finalizers was GHood (I lost interest when it became apparent that
GHC was moving away from giving any kinds of guarantees about
finalizers). The idea was that, just as unsafePerformIO gives us a
way to instrument the evaluator, so finalizers could have given us a 
way to instrument garbage collection. Then GHood could not only
have shown when which parts of which structure are first observed
(how and when structures get unfolded) but also (roughly) when 
which parts of which structure become unreachable (how and when
structures disappear again). That would have made a very nice tool.

But it would have needed finalizers on arbitrary objects that are
actually guaranteed to be run, preferably promptly, but not early. 
Given the application, I would have considered wrapping/annotating 
those objects in some transparent way, not visible to the original 
program, but forcing the memory manager to keep track of that 
object even if that means worse code. Only that there are no guarantees 
whatsoever on these finalizers anymore (there were some back then, 
but it emerged that they weren't backed up by the implementation). 

Which also hurts other, table-like, applications: I have an application 
where I need to keep track of synchronous communication channels, 
basically: advance each live channel at every step. Now, I would like 
(Continue reading)

John Meacham | 7 Dec 2008 12:15
Favicon

Re: Weak pointers and STM

On Thu, Dec 04, 2008 at 09:09:06AM +0000, Simon Marlow wrote:
>> So now I have a scheme whereby I attach a finalizer to a proxy thunk.
>>
>>
>>> data TimeStamp = TimeStamp TS
>>>
>>> data TS = TS {
>>>     tsWord :: TVar Word64,
>>>     tsPrev :: TVar TS,
>>>     tsNext :: TVar TS
>>>     }
>>
>> so, the finalizer attached to 'TimeStamp' values simply deletes the
>> value it points to from the linked list.
>
> What you want here is to attach the finalizer to one of the TVars, 
> probably tsWord.  Attaching the finalizer to Timestamp is very risky: the 
> compiler is free to optimise the Timestamp wrapper away, regardless of 
> how much you hide in the module API.  For example, consider an operation 
> on Timestamp: once the operation has looked inside the Timestamp wrapper, 
> it no longer holds a pointer to it, so the finalizer might run, even 
> though the operation is still working on the TS.  A function that is 
> strict in Timestamp will have a worker that takes the unboxed TS, and 
> might even re-wrap it in a new Timestamp (with no finalizer, of course).

but wouldn't a finalizer attached to any of these TVar's never run since
they are all references from the circularly linked list? I am not quite
sure where you are advocating adding the finalizer.

>> While I am wishing for things,
(Continue reading)

Sterling Clover | 3 Dec 2008 03:10
Picon

Re: Weak pointers and STM


basically, what would be really nice is if there were something like

> registerCommitIO :: IO () -> STM ()

where all IO actions registered with this function (within an atomically
block) are executed exactly once if and only if the atomically block
commits. The IO action is not run within the STM block, notably

       atomically $ do foo; registerCommitIO bar; baz

is equivalent to

       atomically (do foo; baz) >> bar

This is easy enough to whip up with a monad transformer over STM. I think the AdvSTM implementations [1] are rather complicated and heavyweight, but they give a general picture of how to proceed. A simple ReaderT with a TChan should do the trick quite nicely.


Regards,
Sterl.

p.s. as for the issue of the Ord instance, I wonder if tsWord needs to be a TVar or if an IVar or IORef would be sufficient?
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

Gmane