JDK-8215948 : [TESTBUG] gtest pseudo-JavaThreads could be more regular JavaThreads
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 13
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2018-12-28
  • Updated: 2021-07-28
  • Resolved: 2021-07-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 18
18 b06Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
In the review for JDK-8214097 the curious nature of the gtest JavaThread subclasses was discussed - in particular their lack of a java.lang.Thread instance which means we have to be careful not to execute certain JavaThread code - e.g. exit().

It was suggested these might be made more "normal". 

One way to do this would be to emulate what is done for the "service thread":

void ServiceThread::initialize() {
  EXCEPTION_MARK;

  const char* name = "Service Thread";
  Handle string = java_lang_String::create_from_str(name, CHECK);

  // Initialize thread_oop to put it into the system threadGroup
  Handle thread_group (THREAD, Universe::system_thread_group());
  Handle thread_oop = JavaCalls::construct_new_instance(
                          SystemDictionary::Thread_klass(),
                          vmSymbols::threadgroup_string_void_signature(),
                          thread_group,
                          string,
                          CHECK);

  {
    MutexLocker mu(Threads_lock);
    ServiceThread* thread =  new ServiceThread(&service_thread_entry);

    // At this point it may be possible that no osthread was created for the
    // JavaThread due to lack of memory. We would have to throw an exception
    // in that case. However, since this must work and we do not allow
    // exceptions anyway, check and abort if this fails.
    if (thread == NULL || thread->osthread() == NULL) {
      vm_exit_during_initialization("java.lang.OutOfMemoryError",
                                    os::native_thread_creation_failed_msg());
    }

    java_lang_Thread::set_thread(thread_oop(), thread);
    java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
    java_lang_Thread::set_daemon(thread_oop());
    thread->set_threadObj(thread_oop());
   _instance = thread;

    Threads::add(thread);
    Thread::start(thread);
  }

Another thing to check is that these test threads can't terminate while the creating thread may still be interacting with them. In particular os::start_thread uses the startThread_lock() of the osThread, but if the new thread terminates and deletes itself it also deletes the startThread_lock, which may still be in use by the creating thread. For normal JavaThreads this cannot happen due to synchronization in the java.lang.Thread.start() method.
Comments
Changeset: 770e2aa3 Author: David Holmes <dholmes@openjdk.org> Date: 2021-07-14 01:05:10 +0000 URL: https://git.openjdk.java.net/jdk/commit/770e2aa3c6a2bbbc578e60dc2b11300344863e70
14-07-2021

I've prototyped a change to use the new JavaThread::create_system_thread_object and JavaThread::start_internal_daemon helper functions. The ConcurrentHashTable gtest needed a slight modification to avoid creating oops while holding a VM mutex that doesn't allow going to a safepoint.
05-07-2021

[~coleenp] see description of JDK-8269466. The call to "add" is needed for "system" threads that still have to be visible (and they also don't mark themselves as is_hidden_from_external_view())
28-06-2021

It would be useful to figure out (and add a comment) why ServiceThread, MonitorDeflationThread, JfrRecorderThread don't call ThreadGroup.add. Maybe they shouldn't because they're internal threads? But I found other internal threads that did call this, like the Signal thread and the NotificationThread. Maybe it should? There's a lot of copied code creating a thread in the JVM.
28-06-2021

There are a couple of different ways that we setup the j.l.Thread for internal VM JavaThreads, so we need to decide which variant is best for the gtest threads and package it up nicely for ease of reuse. Possibly allocate_threadObj (used for JNI attaching threads) could even be used ... though as noted in the PR for JDK-8268902 the threadObj() can be NULL while the thread is attaching and in particular the allocation of the j.l.Thread instance can safepoint. But for gtest threads we may be able to have an existing JavaThread perform the allocation step - which is what happens for most of the other internal VM JavaThreads.
25-06-2021

OopHandle. GC doesn't NULL out the oop in the OopHandle until after the thread has been destroyed since it's a strong reference until after the destructor is called.
28-05-2021

Did you mean OopHandle or OopStorage here?
28-05-2021

I ran into this recently with writing a gtest with these pseudo threads and having them execute suspend in handshakes: bool HandshakeState::suspend_with_handshake() { if (_handshakee->is_exiting() || _handshakee->threadObj() == NULL) { Although with threadObj moved to OopHandle, I believe they can never be null here (unless running with pseudo-thread). Null doesn't mean what it used to mean.
28-05-2021

Moving it out of 13.
28-03-2019

Also with non-JavaThread support in GlobalCounter we might be-able to use such threads instead in some test.
09-01-2019