On Tue, 11 May 2021 12:13:33 GMT, Robbin Ehn <r...@openjdk.org> wrote:
>> Please consider this change which removes the manual transitions to blocked. >> This adds a preprocess template/functor which is executed in the destructor >> of 'ThreadBlockInVM' if we are going to do any processing. >> This gives us a way to backout of the object/raw monitor before suspend or >> other processing, such as a safepoint. >> >> The object monitor code could be straight forward changed to use this >> instead of manual transitions. >> >> Raw monitors on the other hand are a bit more complicated due to 'implicit' >> rules (consequences of the specs). >> Added a comment in hpp trying to explain it; we cannot simply transition >> with a raw monitor held. >> This caused the change in the destructor ~ThreadInVMfromNative() (this >> specific change have also been tested in unrelated exploration of >> transition), now this RAII does the same as we do when going to native from >> Java, just setting the state. >> Since we are going from an unsafe state, in VM, to a safe state, in native, >> we do not need to check the poll. >> That made it possible to careful use ThreadInVMfromNative in raw monitors. >> >> I also remove the early CAS in raw_enter. >> We lock a lock to do a CAS, in the uncontended case means CAS on lock then >> CAS raw monitor. >> Now we instead do a transitions, in the uncontended case means fence, CAS >> raw monitor, fence. >> (multiple fence (CAS is also a fence) very close to each other have little >> additional performance impact on contemporary hardware) >> >> Passes t1-t7 and manual stressing relevant test groups. > > Robbin Ehn has updated the pull request with a new target base due to a merge > or a rebase. The incremental webrev excludes the unrelated changes brought in > by the merge/rebase. The pull request contains two additional commits since > the last revision: > > - Merge branch 'master' into 8265753 > - Removed manual transitions Thumbs up on the over all logic. I only have minor nits and suggestions. src/hotspot/share/prims/jvmtiRawMonitor.cpp line 242: > 240: if (self->is_Java_thread()) { > 241: JavaThread* jt = self->as_Java_thread(); > 242: guarantee(jt->thread_state() == _thread_in_native, "invariant"); Thanks for making this a guarantee()! There is an existing assert() about this in: ThreadInVMfromNative -> trans() -> transition_from_native() so it doesn't have to be there for forever. src/hotspot/share/prims/jvmtiRawMonitor.cpp line 320: > 318: // JavaThreads will enter here with state _thread_in_native. > 319: void JvmtiRawMonitor::raw_enter(Thread* self) { > 320: // TODO Atomic::load on _owner field Why is this still a TODO? src/hotspot/share/prims/jvmtiRawMonitor.hpp line 42: > 40: // Important note: > 41: // Raw monitors can be used in callbacks which happen during safepoint by > the VM > 42: // thread (e.g. heapRootCallback). This means we may not > tranisition/safepoint nit typo: s/e.g./e.g.,/ nit typo: s/tranisition/transition/ src/hotspot/share/prims/jvmtiRawMonitor.hpp line 43: > 41: // Raw monitors can be used in callbacks which happen during safepoint by > the VM > 42: // thread (e.g. heapRootCallback). This means we may not > tranisition/safepoint > 43: // poll in many cases, else the agent JavaThread can deadlock with VM > thread, nit typo: s/VM thread/the VM thread/ src/hotspot/share/prims/jvmtiRawMonitor.hpp line 48: > 46: // The rules are: > 47: // - We must never safepoint poll if raw monitor is owned. > 48: // - We may safepoint poll before it is owned and after it have been > released. nit typo: s/have been/has been/ src/hotspot/share/prims/jvmtiRawMonitor.hpp line 52: > 50: // native for all operations. However we need to honor suspend request, > not > 51: // entering a monitor if suspended, and check for interrupts. Honoring > suspened > 52: // and reading interrupt flag must be done from VM state (a safepoint > unsafe nit typo: s/suspend request/a suspend request/ nit typo: s/Honoring suspened/Honoring a suspend request/ nit typo: s/interrupt flag/the interrupt flag/ (You'll probably want to reformat the changed lines a bit.) src/hotspot/share/runtime/interfaceSupport.inline.hpp line 206: > 204: ~ThreadInVMfromNative() { > 205: assert(!_thread->has_last_Java_frame() || > _thread->frame_anchor()->walkable(), "Unwalkable stack in vm->native > transition"); > 206: _thread->set_thread_state(_thread_in_native); You're losing the assertion that we're transitioning from `_thread_in_vm` to `_thread_in_native` here. Although, the constructor did verify that we were in `_thread_in_native` when we transitioned to `_thread_in_vm` so at least the first half is still verified. Can you an assertion that we're in `_thread_in_vm` here? src/hotspot/share/runtime/interfaceSupport.inline.hpp line 230: > 228: }; > 229: > 230: template <typename PRE_PROC> When you mentioned doing this with templates, I was having nightmares, but this one is not bad at all... src/hotspot/share/runtime/objectMonitor.cpp line 313: > 311: if (current->is_suspended()) { > 312: _om->_recursions = 0; > 313: _om->_succ = NULL; Please add a comment after this line: // Don't need a full fence after clearing successor here because of the call to exit(). src/hotspot/share/runtime/objectMonitor.cpp line 325: > 323: OrderAccess::fence(); // always do a full fence when successor is > cleared > 324: } > 325: _om_exit = true; Hmmm... `_om_exit` flag is misnamed here since you're "only" clearing the successor. Update: Now I see that the ClearSuccOnSuspend class is subclassed from the ExitOnSuspend, but I still find that flag a bit confusing. src/hotspot/share/runtime/objectMonitor.hpp line 309: > 307: protected: > 308: ObjectMonitor* _om; > 309: bool _om_exit; Instead of `_om_exit` maybe this should be more generic? Perhaps `_om_op_done` or something like that? ------------- Marked as reviewed by dcubed (Reviewer). PR: https://git.openjdk.java.net/jdk/pull/3875