Parsing it out in atomic mode probably will work, I'll look at that. The
callback method I described is actually not how it works, and it is a bit
more complicated (involving a separate place and blocking foreign calls),
but I can do all of the decomposing work in atomic mode. I think I'm
avoiding atomic mode because in a multithreaded system it would be somewhat
expensive operation, but that might not hold in Racket.

The other option I'm looking at is to construct the racket child struct
reference before handing it off to the foreign library, and having them be
responsible for deallocating their fields and then decrementing a ref count
on the parent whose will will only be responsible for freeing the direct
memory.

The will functionality I'm describing is different than current wills as
current wills are ready when the cpointer is unreachable not when the
memory pointed to by the cpointer is collectable.

#lang racket
(require ffi/unsafe)


(define p1 (malloc 'atomic-interior 100))

(define port (current-output-port))
(register-finalizer p1 (lambda (p1) (displayln 'dead port)))
(define p2 (ptr-add p1 10))
(set! p1 #f)
(collect-garbage)
(sleep 4)

In this example it wouldn't print "dead" because p2 is still holding the
memory alive even though p1 is dead. But if p2 was cleared then it would
get printed.



On Tue, Oct 3, 2017 at 7:04 PM, Matthew Flatt <mfl...@cs.utah.edu> wrote:

> Is the work to parse out the values short enough that you can do it
> atomically in response to the notification that says the data is ready?
> If so, it's probably best to parse and free in atomic mode. Or can you
> at least atomically separate out references to children, where
> finalizers can sensibly be attached to the individual references?
>
> If not, then I don't have a better idea than the approach you describe.
> I don't quite follow why you'd need new functionality from wills, since
> a will procedure on a cpointer already receives the cpointer back when
> there are otherwise no references to the cpointer.
>
> At Tue, 3 Oct 2017 18:39:04 -0700, Eric Dobson wrote:
> > I'm dealing with some foreign apis that want to be passed long lived
> output
> > pointers to structs. The apis eventually call back indicating that the
> > struct has been filled in appropriately and then I want to read out the
> > values and deallocate the structs. I'm using atomic interior memory for
> > these structs as they don't need to hold GCable values themselves and
> they
> > need to not be moved while the foreign library has a pointer to them.
> Once
> > they are back I need to construct derived pointers to the sub structs and
> > parse out all the different parameters.
> >
> > The issue I'm running into is reliably destroying the struct when I'm
> done
> > parsing out all the values. If it was as simple as freeing the memory, it
> > would be easy as I can rely on the GC to do that. But it is not as the
> > struct has pointer fields that may have been initialized by the foreign
> > library and thus I need to actively run destructor code to free those
> > subparts before freeing the struct. This seems like a good use for
> > will-executors, but the issue with those is that they are attached to
> > racket values not the underlying memory object. And in this case because
> > the memory is allocated with 'atomic-interior', it is possible for the
> > original pointer to no longer be needed and only derived pointers needed.
> >
> > I'm thinking there may be clever ways with making sure that every derived
> > pointer either maintains an explicit reference or increments a reference
> > count on the original pointer, but I'm worried that is very complicated
> and
> > likely to be broken. The easiest solution for me would be to have
> something
> > like a will that could be attached to a 'cpointer?' value and would be
> > called back with a fresh 'cpointer?' value that pointed at the same
> address
> > once there were only weak references to the object. Is this possible or
> > does anyone see a better solution?
> >
> >
> > Example:
> >
> > ;; Child corresponds to a byte array
> > (define-cstruct _child ([ptr _pointer] [len _int])
> > ;; Parent has two inlined children
> > (define-cstruct _parent ([child1 _child] [child2 _child]))
> >
> > ;; When the parent is to be cleaned up I need to ensure that the two
> > children have their 'ptr' fields passed to free.
> >
> > ;; The issue is in a function that wants to decompose the parent into
> > children pointers and use their values:
> > (define (child->bytes c) <elided>)
> > (define (parent->bytes p)
> >   (bytes-append (child->bytes (parent-child1 p)) #"." (child->bytes
> > (parent-child2 p))))
> >
> > ;; In this after the parent-child2 call, there is no strong reference to
> p
> > so if this was the last reference to it, GC could happen before
> > child->bytes was called and determine that p was unreachable and so any
> > wills would become ready. Thus I cannot free the underlying memory in a
> > will.
> >
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send an
> > email to racket-users+unsubscr...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to