On Wed, Aug 13, 2014 at 11:32 PM, Wes Freeman <
freem...@gmail.com> wrote:
> Yeah, the problem with the reproducible example is that it requires running
> the foundationdb service (I'm running 2.0.7) in order to test.
> I'm running OSX 10.9.4; also tested in Centos 6.4 and got similar failures.
I tried on my OS X 10.9.4 with FoundationDB 2.0.8 and finally
reproduced it after adding runtime.GC() call to notifyChannel and
various fprintf(stderr, ...) calls. Now running under GOTRACEBACK=2
gives a very interesting result:
https://gist.github.com/snaury/2c4154d86c3c2f6fecf0
There you would see that fdb_future_block_until_ready(0x4c00250) is
parked inside chanrecv1(0x4103e00, 0xc208004120, 0x0), where
0xc208004120 is the actual channel pointer. However in the closeNotify
it is in closechan(0xc2080340a8, 0x40b018f), notice that the pointer
is different. What's more, it is visible that the pointer got changed
between setting the callback and its execution. At first I thought
this was some weird moving of heap pointers in Go 1.3.1, but running
with StackDebug=2 didn't reveal any suspicious adjustments at all, so
I was at a loss why that might be.
And then it hit me. Values of chan T are already pointer. What you
pass into callback is a pointer to a pointer, but since it's actually
nowehere in locals there's nothing that could prevent it from being
collected. That's why adding it to return values helps, because it
just so happens it really needs to keep that until function returns
(that's of course until optimizer is smart enough to optimize that
return value away).
Interestingly local variables don't help, even something like this:
pch := new(chan struct{})
*pch = make(chan struct{}, 1)
C.go_set_callback(f, unsafe.Pointer(pch))
<-*pch
Doesn't make any difference. So, how is one expected to interact with
cgo in these situations, when even a local variable is not guaranteed
to keep a reference to the object, if the variable itself may be freed
after it stops being used?