Re: [racket-users] Best way to destruct objects allocated with "atomic interior" malloc

2017-10-03 Thread Eric Dobson
I've actually simplified my program that causes the issues and it doesn't
need the callback or the foreign functions at all it just needs structs
with substructs.

This shows that if garbage is collected after making the substruct is
complete then the finalizer gets run, which trashes the memory I'm about to
read. The interior memory will-registration would solve this, but given
that the docs say that it shouldn't be used for small objects I don't want
to use it for every slice object in my program. I think I need to come up
with a different method for handling garbage collection of structs, or
possible judicious use of the recently added void/reference-sink once the
new release is out.

#lang racket/base

(require
  ffi/unsafe
  ffi/unsafe/alloc)

(define-cstruct _grpc-slice-refcounted
  ([bytes _pointer]
   [length _size]))

(define-cstruct _grpc-slice-inlined
  ([length _uint8]
   [bytes (_array _uint8 (+ (ctype-sizeof _size) (ctype-sizeof _pointer)
-1))]))

(define-cstruct _grpc-slice/ffi
  ([refcount _pointer]
   [data (_union _grpc-slice-refcounted _grpc-slice-inlined)]))

;; Struct that hides the raw pointer from the exposed api
(struct grpc-slice (pointer))

(define (grpc-slice-length slice)
  (define ffi-slice (grpc-slice-pointer slice))
  (if (grpc-slice/ffi-refcount ffi-slice)
  (grpc-slice-refcounted-length (union-ref (grpc-slice/ffi-data
ffi-slice) 0))
  (grpc-slice-inlined-length
(begin0
  (union-ref (grpc-slice/ffi-data ffi-slice) 1)
  (collect-garbage)

(define (make-grpc-slice)
  (define p (ptr-ref (malloc _grpc-slice/ffi) _grpc-slice/ffi))
  (memset p #x00 1 _grpc-slice/ffi)
  ;; Would call slice-unref which might free the memory in the real code.
  (register-finalizer p (lambda (p) (memset p #xFF 1 _grpc-slice/ffi)))
  (grpc-slice p))


(define s (make-grpc-slice))
(grpc-slice-length s)
(grpc-slice-length (begin0 s (set! s #f)))




On Tue, Oct 3, 2017 at 7:55 PM, Eric Dobson  wrote:

> 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  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. 

Re: [racket-users] Best way to destruct objects allocated with "atomic interior" malloc

2017-10-03 Thread Eric Dobson
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  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) )
> > (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.
> >
> > --

Re: [racket-users] Best way to destruct objects allocated with "atomic interior" malloc

2017-10-03 Thread Matthew Flatt
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) )
> (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.


[racket-users] Best way to destruct objects allocated with "atomic interior" malloc

2017-10-03 Thread Eric Dobson
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) )
(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.