Thanks, this is super helpful. :)

On Monday, September 17, 2018 at 9:58:06 AM UTC-7, Matthew Flatt wrote:
>
> At Mon, 17 Sep 2018 09:34:46 -0700 (PDT), Stephen Foster wrote: 
> > But when I have two bodies that share the same velocity_func, I get a 
> > segfault: 
>
> The problem is that a callback is retained (by default) as long as the 
> function that it wraps is retained, but only a single callback is 
> retained for a given function. So, creating a second callback loses the 
> link between the function and the first callback, and the first 
> callback can be is reclaimed by the GC. 
>
> This is often a difficult problem to solve. 
>
> > *Things that didn't work* 
> > 
> > 1) Wrapping the function f in separate lambdas still gives a segfault: 
> > 
> > (set-cpBody-velocity_func! (chipmunk-body body1) 
> >                            (lambda(b g d dt) 
> >                              (f b d g dt))) 
> > 
> > (set-cpBody-velocity_func! (chipmunk-body body2) 
> >                            (lambda(b g d dt) 
> >                              (f b d g dt))) 
>
> This change makes things slightly worse, because nothing retains either 
> of those individual lambdas. 
>
> > 2) Storing a reference to the function f in a stab-in-the-dark attempt 
> to 
> > "trick the system" or "prevent some kind of mysterious garbage 
> collection" 
> > still segfaults: 
> > 
> > (define probably-silly 
> >   (list 
> >     (lambda(b g d dt) 
> >       (f b d g dt)) 
> >     (lambda(b g d dt) 
> >       (f b d g dt)))) 
> > 
> > (set-cpBody-velocity_func! (chipmunk-body body1) 
> >                            (list-ref probably-silly 0)) 
> > 
> > (set-cpBody-velocity_func! (chipmunk-body body2) 
> >                            (list-ref probably-silly 1)) 
>
> Honestly, I'm not clear on why this fails. The `probably-silly` list 
> should be retained via the module's namespace, and so both of those 
> `lambda`s should be preserved, and so both callbacks should be 
> preserved. I'm stumped. 
>
>
> > 3) Storing the function f in two separate variables also segfaults: 
> > 
> > (define (f body gravity damping dt) 
> >   (ffi:cpointer-push-tag! body 'cpBody) 
> >   (cpBodySetVelocity body (cpv 0 -10)) 
> >     
> >   ffi:_void) 
> > 
> > (define f2 f) 
>
> This does nothing, since `f` and `f2` refer to the same value. 
>
>
> > *Things that do work but feel dumb* 
> > 
> > 1) Explicitly duplicating the function verbatim: 
> > 
> > (define (f body gravity damping dt) 
> >   (ffi:cpointer-push-tag! body 'cpBody) 
> >   (cpBodySetVelocity body (cpv 0 -10)) 
> >     
> >   ffi:_void) 
> > 
> > (define (f2 body gravity damping dt) 
> >   (ffi:cpointer-push-tag! body 'cpBody) 
> >   (cpBodySetVelocity body (cpv 0 -10)) 
> >     
> >   ffi:_void) 
> > 
> > (set-cpBody-velocity_func! (chipmunk-body body1) 
> >                            f) 
> > 
> > (set-cpBody-velocity_func! (chipmunk-body body2) 
> >                            f2) 
>
> This works because each callbacks is associated to a separate function, 
> and the separate functions are retained through the module's namespace. 
>
> > 2) Duplicating the function with a macro lets me generalize the above 
> > workaround for more than two bodies, but it still feels gross. 
>
> Yes. 
>
>
> > If someone has an explanation or a better workaround, that would be 
> great.   
>
> Use `#:keep` in the `_fun` for the velocity callback. 
>
> To tie the callback's lifetime to the enclosing record, you can 
> probably use a weak hashtable mapping `cpBody` pointers to callbacks: 
>
>   (define callbacks (make-weak-hasheq)) 
>   (define current-cpBody (make-parameter #f)) 
>
>   (define _cpBodyVelocityFunc 
>      (_fun #:keep (lambda (cb) (hash-set! callbacks (current-cpBody) cb)) 
>            _pointer _cpVect _cpFloat _cpFloat -> _void)) 
>   
> where `current-cpBody` is a way of communicating the record where the 
> pointer is being stored: 
>
>   (let ([body (chipmunk-body body1)]) 
>     (parameterize ([current-cpBody body])) 
>       (set-cpBody-velocity_func! body 
>                                   f)) 
>
> Beware that `callbacks` ties the callback to a cpointer record, not to 
> the actual pointer value. Since `chipmunk-body` returns the same 
> Cpointer every time for a given `chipmunk` Racket structure, I think 
> that's ok --- but it won't be ok if you get the same body pointer from 
> Chipmunk (via the FFI) multiple times. 
>
>

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