RFR: 8212107: VMThread issues and cleanup [v3]

Aleksey Shipilev shade at openjdk.java.net
Wed Sep 23 13:07:23 UTC 2020


On Wed, 23 Sep 2020 08:45:00 GMT, Robbin Ehn <rehn at openjdk.org> wrote:

>> We simplify the vmThread by removing the queue and refactor the the main loop.
>> This solves the issues listed:
>> - It can create an extra safepoint directly after a safepoint.
>> - It's not safe for a non-JavaThread to add safepoint to queue while GC do oops do.
>> - The exposure of the vm operation is dangerous if it's a handshake.
>> - The code is a hornets nest with the repetition of checks and branches
>> 
>> Passes t1-8, and a benchmark run.
>> 
>> If you want a smaller diff the commits contains the incremental progress and each commit passed t1.
>
> Robbin Ehn has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Update after Coleen and David

I have only minor comments, without diving into the logic machinery. I am relying on others to review this more
substantially.

src/hotspot/share/runtime/vmThread.cpp line 389:

> 387:     if (!prev_vm_operation->allow_nested_vm_operations()) {
> 388:       fatal("Nested VM operation %s requested by operation %s",
> 389:             op->name(), vm_operation()->name());

This is better as `prev_vm_operation`, not `vm_operation()`? Saves some brain cycles reading...

src/hotspot/share/runtime/vmThread.cpp line 483:

> 481:       break;
> 482:     }
> 483:   } while(!should_terminate());

So now we have the duplicated `should_terminate()` here. Can we check it once (logically)? For example:

do {
  wait_for_operation();
  assert(_next_vm_operation != NULL, "Must have one");
  inner_execute(_next_vm_operation);
} while (!should_terminate());

If not, then it might be rewritten without change in logic this:

while (true) {
  if (should_terminate()) break;
  wait_for_operation();
  if (should_terminate()) break;
  assert(_next_vm_operation != NULL, "Must have one");
  inner_execute(_next_vm_operation);
}

src/hotspot/share/runtime/vmThread.hpp line 108:

> 106:   static VM_Operation::VMOp_Type vm_op_type()     {
> 107:     assert(Thread::current()->is_VM_thread(), "Must be");
> 108:     return _cur_vm_operation->type();

These two might just delegate and check a bit more thoroughly.

  static VM_Operation* vm_operation()             {
  static VM_Operation::VMOp_Type vm_op_type()     { return _cur_vm_operation->type(); }
  assert(Thread::current()->is_VM_thread(), "Must be");
    return _cur_vm_operation;
  }

  static VM_Operation::VMOp_Type vm_op_type()     {
    VM_Operation* op = vm_operation();
    assert (op != NULL, "sanity");
    return op->type();
  }

Haven't checked if `vm_op_type` helps readability at actual usages, maybe it is unnecessary to begin with.

src/hotspot/share/runtime/vmThread.cpp line 461:

> 459:     // We did find anything to execute, notify any waiter so they can install a new one.
> 460:     ml_op_lock.notify_all();
> 461:     ml_op_lock.wait(GuaranteedSafepointInterval);

I initially had the same concern as in my previous review: if there are multiple threads entering here, they could just
ping-pong each other with notify-wait. But then I realized this method is only called from VMThread itself. Maybe
methods like that need to be `assert(is_VM_thread())` on entry?

-------------

Marked as reviewed by shade (Reviewer).

PR: https://git.openjdk.java.net/jdk/pull/228


More information about the hotspot-dev mailing list