MemorySegment.close(), threads
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Jan 15 11:38:34 UTC 2020
On 15/01/2020 11:00, Michael Zucchi wrote:
>
> Evening,
>
> Has it been considered to have MemorySegment.close() work on any thread?
>
> As far as I can tell doing so wouldn't impact the other checks on
> usage and it would still 'safely' throw appropriate exceptions for
> incorrect use for anything that erroneously retained a stale reference.
>
> This would enable a couple of common processing flows which are
> currently impossible such as worker threads or parallel streams
> returning results, and using reference queues for any object that uses
> a java-allocated memory segment. This doesn't really occur very often
> as such resources are typically allocated by C (being unbeholden to
> such restrictions), and in the worst case values can be copied by
> hand-marshalling to pojos.
You can share a segment across multiple threads using the
MemorySegment::acquire method. The workflow is as follows:
1) master thread creates a segment
2) many worked threads acquire the segment
2a) at this point master thread can no longer close the segment (since
there's threads using it)
3) worked threads do work on their segment (slice?) and then close their
acquired segment - closing an acquired segment does NOT deallocate
4) once all the acquired segments have been closed by the worked
threads, the master thread can proceed closing the original segment for
good (which will deallocate)
The main reason for enforcing such a workflow (or _any_ workflow) is
that we want to avoid race conditions where a thread accesses a segment
while another closes it, which, again would lead potentially to a hard
VM crash (which the API wants to avoid).
Slight variations on this protocol have been suggested during the code
review for JDK 14 integration where all threads are on an equal footing,
and the last one closing the segment triggers deallocation. This is also
possible to achieve, we need real world validation to guide us in
picking which flavor would be more useful most of the times.
>
> But SystemABI.upcallStub() can't be changed or copied which makes a
> few things inconvenient like lambdas caching such stubs (as they can
> have no close() method), or any function/object that has a setter for
> a callback. Such a setter needs to keep the callback stub around for
> freeing later - either when the setter is invoked again or the object
> that uses it is closed and limiting that to the originating thread
> seems overbearing.
And upcall stub is a pointer into some piece of JVM-allocated code. We
can't let you peek to much into that - e.g. if you were able to copy
arbitrary bits inside the VM generated stub, you could corrupt the VM state.
That said, I agree that the life-cycle of stubs is tricky and that
coupled with the strong ownership of the memory access API results in
some discomfort. We know we're not 100% done in this part of the API,
and I'll take this piece of feedback as another evidence of that.
At some point, during design explorations on how to support multiple
threads safely, we supported a simpler model where segments were either
thread-confined, or shared. Thread-confined segments supported
deterministic allocation (close()) shared segments did not, and used a
Cleaner instead. The current design rescues deterministic deallocation
also in the concurrent case - but for stuff like this is less
convenient. E.g. I could imagine allocating an upcall stub on a shared
segment which would be automatically closed/freed when the GC determines
nobody is using it - which would make the upcall stub usable by all
threads, and make its deallocation 'safe' at the same time.
>
> As an aside, a zeroing allocateNative would also be useful just as it
> is in C: for convenience, and security.
allocateNative zeroes by default, for the reasons you mentioned. There
is a runtime property you can set to disable zeroing
("-Djdk.internal.foreign.skipZeroMemory=true"), and in the future, as we
have plans to open up some of the allocation machinery, there will
probably be allocateNative overloads with different flavors.
Maurizio
>
> Regards,
> Michael
>
More information about the panama-dev
mailing list