On Thu, 17 Oct 2024 14:28:30 GMT, Patricio Chilano Mateo <pchilanom...@openjdk.org> wrote:
> This is the implementation of JEP 491: Synchronize Virtual Threads without > Pinning. See [JEP 491](https://bugs.openjdk.org/browse/JDK-8337395) for > further details. > > In order to make the code review easier the changes have been split into the > following initial 4 commits: > > - Changes to allow unmounting a virtual thread that is currently holding > monitors. > - Changes to allow unmounting a virtual thread blocked on synchronized trying > to acquire the monitor. > - Changes to allow unmounting a virtual thread blocked in `Object.wait()` and > its timed-wait variants. > - Changes to tests, JFR pinned event, and other changes in the JDK libraries. > > The changes fix pinning issues for all 4 ports that currently implement > continuations: x64, aarch64, riscv and ppc. Note: ppc changes were added > recently and stand in its own commit after the initial ones. > > The changes fix pinning issues when using `LM_LIGHTWEIGHT`, i.e. the default > locking mode, (and `LM_MONITOR` which comes for free), but not when using > `LM_LEGACY` mode. Note that the `LockingMode` flag has already been > deprecated ([JDK-8334299](https://bugs.openjdk.org/browse/JDK-8334299)), with > the intention to remove `LM_LEGACY` code in future releases. > > > ## Summary of changes > > ### Unmount virtual thread while holding monitors > > As stated in the JEP, currently when a virtual thread enters a synchronized > method or block, the JVM records the virtual thread's carrier platform thread > as holding the monitor, not the virtual thread itself. This prevents the > virtual thread from being unmounted from its carrier, as ownership > information would otherwise go wrong. In order to fix this limitation we will > do two things: > > - We copy the oops stored in the LockStack of the carrier to the stackChunk > when freezing (and clear the LockStack). We copy the oops back to the > LockStack of the next carrier when thawing for the first time (and clear them > from the stackChunk). Note that we currently assume carriers don't hold > monitors while mounting virtual threads. > > - For inflated monitors we now record the `java.lang.Thread.tid` of the owner > in the ObjectMonitor's `_owner` field instead of a JavaThread*. This allows > us to tie the owner of the monitor to a `java.lang.Thread` instance, rather > than to a JavaThread which is only created per platform thread. The tid is > already a 64 bit field so we can ignore issues of the counter wrapping around. > > #### General notes about this part: > > - Since virtual threads don't need to worry about holding monitors anymo... src/hotspot/cpu/x86/stubGenerator_x86_64.hpp line 602: > 600: > 601: address generate_cont_preempt_stub(); > 602: address generate_cont_resume_monitor_operation(); The declaration of `generate_cont_resume_monitor_operation` seems to be unused. src/hotspot/share/runtime/javaThread.hpp line 166: > 164: // current _vthread object, except during creation of the primordial > and JNI > 165: // attached thread cases where this field can have a temporary value. > 166: int64_t _lock_id; Following the review I wanted to better understand when `_lock_id` changes. There seems to be another exception to the rule that `_lock_id` is equal to the `tid` of the current `_vthread`. I think they won't be equal when switching temporarily from the virtual to the carrier thread in `VirtualThread::switchToCarrierThread()`. src/hotspot/share/runtime/objectMonitor.hpp line 202: > 200: > 201: // Used in LM_LEGACY mode to store BasicLock* in case of inflation by > contending thread. > 202: BasicLock* volatile _stack_locker; IIUC the new field `_stack_locker` is needed because we cannot store the `BasicLock*` anymore in the `_owner` field as it could be interpreted as a thread id by mistake. Wouldn't it be an option to have only odd thread ids? Then we could store the `BasicLock*` in the `_owner` field without loosing the information if it is a `BasicLock*` or a thread id. I think this would reduce complexity quite a bit, woudn't it? src/hotspot/share/runtime/synchronizer.cpp line 1559: > 1557: // and set the stack locker field in the monitor. > 1558: m->set_stack_locker(mark.locker()); > 1559: m->set_anonymous_owner(); // second Is it important that this is done after the stack locker is set? I think I saw another comment that indicated that order is important but I cannot find it now. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/21565#discussion_r1818523530 PR Review Comment: https://git.openjdk.org/jdk/pull/21565#discussion_r1812377293 PR Review Comment: https://git.openjdk.org/jdk/pull/21565#discussion_r1819029029 PR Review Comment: https://git.openjdk.org/jdk/pull/21565#discussion_r1818521820