That's very helpful, thanks very much!
On Wednesday, September 28, 2016 at 10:33:04 PM UTC+1, Yichao Yu wrote: > > On Wed, Sep 28, 2016 at 5:16 PM, Christian Rorvik > <christia...@gmail.com <javascript:>> wrote: > > Thanks! I'll try this tomorrow. So similar to what you've done here? > > > https://github.com/yuyichao/FunctionWrappers.jl/blob/master/src/FunctionWrappers.jl#L40 > > > Correct. Also https://github.com/JuliaPy/PyCall.jl/pull/267 > > > > > I can't remember if I actually called that explicitly, but I believe > what I > > ended up with was similar to here: > > http://julialang.org/blog/2013/05/callback, where they use > > unsafe_pointer_to_objref to recover the function object. > > unsafe_pointer_to_objref is ok. It's unsafe in the sense that you > almost guarantee a segfault if it is not used correctly. > pointer_from_objref is less unsafe in that you might not get a > segfault if the GC is nice to you today. > > Ref https://github.com/JuliaLang/julia/issues/15857 for why > pointer_from_objref is bad if you call it on arbitrary object (mostly > immutables). Essentially the compiler is free to give you garbage if > you call it on immutables or the pointer you get back might not be the > pointer that you stored somewhere else since the pointer value is > supposed to be insignificant, only the content is, for immutables. > > > > > On Wednesday, September 28, 2016 at 10:06:51 PM UTC+1, Yichao Yu wrote: > >> > >> On Wed, Sep 28, 2016 at 5:00 PM, Christian Rorvik > >> <christia...@gmail.com> wrote: > >> > I don't have the code at hand right now (it's at work), but what I > was > >> > doing > >> > was something like > >> > > >> > type Wrapper{Arg} > >> > cfun::Ptr{Void} > >> > cobj::Ptr{Void} > >> > obj > >> > > >> > function Wrapper{T}(f::T) > >> > return new(cfunction(call_wrapper, Void, (Ref{T}, Arg)), > >> > pointer_from_objref(f), f) > >> > end > >> > end > >> > >> This is wrong, You shouldn't ever call `pointer_from_objref` for > >> unknown object. The right way to handl this is > >> > >> type Wrapper{Arg} > >> cfun::Ptr{Void} > >> cobj::Ptr{Void} > >> obj > >> function Wrapper{T}(f::T) > >> to_root = Base.cconvert(Ref{T}, f) > >> ptr = Base.unsafe_convert(Ref{T}, to_root) > >> return new(cfunction(call_wrapper, Void, (Ref{T}, Arg)), > >> Ptr{Void}(ptr), to_root) > >> end > >> end > >> > >> > >> > > >> > Where call_wrapper would invoke the closure. I had to change > >> > call_wrapper to > >> > receive the closure as Ptr{T} and call unsafe_pointer_to_objref and > then > >> > call it. > >> > > >> > > >> > On Wednesday, September 28, 2016 at 9:50:47 PM UTC+1, Yichao Yu > wrote: > >> >> > >> >> On Wed, Sep 28, 2016 at 4:36 PM, Christian Rorvik > >> >> <christia...@gmail.com> wrote: > >> >> > GC of code turned out to be a red herring. After isolating the > >> >> > instance > >> >> > of a > >> >> > call that was crashing, and getting right up to it, GDB was kind > >> >> > enough > >> >> > to > >> >> > get its knickers in a twist and segfault itself every time I > stepped > >> >> > instruction by instruction to find the precise point of failure > >> >> > (backtrace > >> >> > after segfault looked pretty meaningless). > >> >> > > >> >> > What it tunred out to be a was a Ref vs Ptr problem, where in > Julia I > >> >> > have a > >> >> > callback wrapper that receives a pointer to the closure. I was > taking > >> >> > this > >> >> > as Ref{T} and invoking it with a pointer from the C code. This > worked > >> >> > all > >> >> > fine and dandy, but somehow caused the object to be collected (I'm > >> >> > guessing). I can see how what I did was wrong, but I can't see how > it > >> >> > would > >> >> > lead to something being collected when there still exists roots > >> >> > pointing > >> >> > to > >> >> > it. If anything I would possibly expect a leak. Nonetheless, bit > of a > >> >> > wild > >> >> > goose chase. > >> >> > >> >> It's unclear what exactly you mean but just to be clear > `cfunction(f, > >> >> Ret, Tuple{Ref{Int}})` expect a pointer to a julia boxed `Int` that > is > >> >> rooted somewhere during the execution of the julia callback > function. > >> >> It is illegal to pass it a bare C `intptr_t*` (that doesn't point to > >> >> julia memory of a boxed Int) and it is illegal to generates it with > >> >> `ccall(..., (Ptr{Int},), &i)`. > >> >> > >> >> > > >> >> > > >> >> > On Wednesday, September 28, 2016 at 5:22:49 PM UTC+1, Christian > >> >> > Rorvik > >> >> > wrote: > >> >> >> > >> >> >> I'm not yet a 100% sure what is happening in my application, but > I'm > >> >> >> embedding Julia and using cfunction() to generate C-callable > >> >> >> functions > >> >> >> that > >> >> >> at a later time invoke the registered julia code. I use a fairly > >> >> >> standard > >> >> >> pattern I think, of passing a pointer to a julia object that is > >> >> >> retain > >> >> >> in C > >> >> >> and later passed down to the callback created by cfunction, and > from > >> >> >> there > >> >> >> resolved to the original real Julia reference type, invoking a > >> >> >> closure. > >> >> >> The > >> >> >> closure itself is retained in some global state to prevent > garbage > >> >> >> collection. What appears to be happening however, is the code at > the > >> >> >> landing > >> >> >> site for the cfunction returned pointer is at some point garbage > >> >> >> collection > >> >> >> (or at least corrupted), as my program, after a while of running, > >> >> >> will > >> >> >> segfault upon invoking the callback (after many previously > >> >> >> successful > >> >> >> callbacks). It segfaults because it hits invalid code, and it's > not > >> >> >> that > >> >> >> some state is missing when running the code. > >> >> >> > >> >> >> Is this to be be expected, and what's the right way to ensure the > >> >> >> code > >> >> >> isn't GC'd? >