[External] : Re: Can continuation support finally solve the "How do I stop this thread" problem?

Ron Pressler ron.pressler at oracle.com
Fri Sep 2 07:52:32 UTC 2022



On 1 Sep 2022, at 18:15, Archie Cobbs <archie.cobbs at gmail.com<mailto:archie.cobbs at gmail.com>> wrote:


So my question is simply what's the implementation distance between X and Y? Where X = [We are now after implementing virtual threads], and Y = [The ability to always unblock a blocked thread].

The distinction between stopping and unblocking is good, I think, because while forcibly stopping a thread can never be generally safe, unblocking it (via interruption) is a different matter. So the question, “which operations are not interruptible?” is a good one.

I’ll let Alan cover the details, but I expect some of the answer depends on OS details.

—


The Java platform (and language) currently does not impose such “isolation” limitation, but some language targeting the Java platform could, and so it could also emit interruption checks when compiling to bytecode. A language that behaves in this way is Erlang (although I don’t know if implementations targeting Java are currently maintained), but even there there are pitfalls.

You've got me curious... What are the additional pitfalls?

At the primitive operation level, Erlang ensures that when processes (their user-mode threads) share memory it is done only via atomic operations, and otherwise all sharing of data is done through message-passing. But programs then establish higher-level protocols on top of these primitives, and the existence of the processes themselves becomes shared mutable state. For example, one process might depend on another to unblock it in some way, and so arbitrary killing of processes could lead to deadlocks. So in the end, programs still have to be written with care to take into account and cooperate with that kind of “interruption.”


Even if all “dangerous” APIs are blocked, any user code could allocate as much memory as it likes, exhausting the memory available for the entire process.

Not necessarily. Bytecode rewriting could be used to track memory allocations with weak references used to track deallocations. This would impose a performance penalty of course, and the accounting wouldn't be perfectly accurate, but you could make that inaccuracy conservative so it would work for the purposes of containment.

It’s not enough to track the allocations — you also have to track the deallocations. You might be able to do that with some heavy use of JVMTI (and a very heavy cost to performance), but that would amount to not much less than modifying the VM to add such capability.


If it is also allowed to spawn platform threads at will, it can also exhaust the CPU allocation for the entire process.

Not sure I understand... with bytecode rewriting (e.g., adding checks at backward branches), you should be able to limit the total CPU utilization of a thread or group of threads. Kind of clunky for sure but it should work, right?

I guess, but you’d have to also do that for the JDK itself, because some loops could be written with calls to JDK APIs such as streams or even Arrays.sort.


OK so let me throw out a not-so hypothetical example. Oracle supports Java stored procedures<https://docs.oracle.com/database/121/JJDEV/chfive.htm#JJDEV13247>. I'm not familiar with it, but is this not implemented as server-side sandboxed code? Isn't that a valid motivating example?

I don’t know how they do it, and I wouldn’t be surprised if they don’t use stock OpenJDK, but either way I don’t think the intent is to run untrusted code (i.e. code suspected of being intentionally malicious) in stored procedures, unlike the example you gave of the shared server. I am not aware of any language of platform that could offer sufficient isolation of untrusted code in shared servers in user mode. Even on the client, where the problem is much easier and the stakes are lower, web browsers rely on process isolation to prevent a web site from taking the entire browser down.

Robust and *efficient* isolation currently requires access to operations that only kernel mode code has access to. But even if, with great care and loss in performance, you could replicate some of the work done by the kernel in user-mode, the question would be why is that worth it?

— Ron
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20220902/c5eb8bc8/attachment-0001.htm>


More information about the loom-dev mailing list