Skip to content

Commit

Permalink
8305670: Performance regression in LockSupport.unpark with lots of id…
Browse files Browse the repository at this point in the history
…le threads

Reviewed-by: mdoerr
Backport-of: f030937a51b95dde33ce33537ee830153b2c3b56
  • Loading branch information
GoeLin committed Jul 23, 2023
1 parent e8a8a2d commit 504ec27
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 14 deletions.
29 changes: 15 additions & 14 deletions src/hotspot/share/prims/unsafe.cpp
Expand Up @@ -829,21 +829,22 @@ UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute,

UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) {
if (jthread != NULL) {
ThreadsListHandle tlh;
JavaThread* thr = NULL;
oop java_thread = NULL;
(void) tlh.cv_internal_thread_to_JavaThread(jthread, &thr, &java_thread);
if (java_thread != NULL) {
// This is a valid oop.
if (thr != NULL) {
// The JavaThread is alive.
Parker* p = thr->parker();
HOTSPOT_THREAD_UNPARK((uintptr_t) p);
p->unpark();
}
oop thread_oop = JNIHandles::resolve_non_null(jthread);
// Get the JavaThread* stored in the java.lang.Thread object _before_
// the embedded ThreadsListHandle is constructed so we know if the
// early life stage of the JavaThread* is protected. We use acquire
// here to ensure that if we see a non-nullptr value, then we also
// see the main ThreadsList updates from the JavaThread* being added.
FastThreadsListHandle ftlh(thread_oop, java_lang_Thread::thread_acquire(thread_oop));
JavaThread* thr = ftlh.protected_java_thread();
if (thr != nullptr) {
// The still live JavaThread* is protected by the FastThreadsListHandle
// so it is safe to access.
Parker* p = thr->parker();
HOTSPOT_THREAD_UNPARK((uintptr_t) p);
p->unpark();
}
} // ThreadsListHandle is destroyed here.

} // FastThreadsListHandle is destroyed here.
} UNSAFE_END

UNSAFE_ENTRY(jint, Unsafe_GetLoadAverage0(JNIEnv *env, jobject unsafe, jdoubleArray loadavg, jint nelem)) {
Expand Down
14 changes: 14 additions & 0 deletions src/hotspot/share/runtime/threadSMR.cpp
Expand Up @@ -816,6 +816,20 @@ bool ThreadsListHandle::cv_internal_thread_to_JavaThread(jobject jthread,
return true;
}

FastThreadsListHandle::FastThreadsListHandle(oop thread_oop, JavaThread* java_thread) : _protected_java_thread(nullptr) {
assert(thread_oop != nullptr, "must be");
if (java_thread != nullptr) {
// We captured a non-nullptr JavaThread* before the _tlh was created
// so that covers the early life stage of the target JavaThread.
_protected_java_thread = java_lang_Thread::thread(thread_oop);
assert(_protected_java_thread == nullptr || _tlh.includes(_protected_java_thread), "must be");
// If we captured a non-nullptr JavaThread* after the _tlh was created
// then that covers the end life stage of the target JavaThread and we
// we know that _tlh protects the JavaThread*. The underlying atomic
// load is sufficient (no acquire necessary here).
}
}

void ThreadsSMRSupport::add_thread(JavaThread *thread){
ThreadsList *new_list = ThreadsList::add_thread(get_java_thread_list(), thread);
if (EnableThreadSMRStatistics) {
Expand Down
23 changes: 23 additions & 0 deletions src/hotspot/share/runtime/threadSMR.hpp
Expand Up @@ -320,6 +320,29 @@ class ThreadsListHandle : public StackObj {
}
};

// This stack allocated FastThreadsListHandle implements the special case
// where we want to quickly determine if a JavaThread* is protected by the
// embedded ThreadsListHandle.
//
class FastThreadsListHandle : public StackObj {
JavaThread* _protected_java_thread;
ThreadsListHandle _tlh;

public:
// The 'java_thread' parameter to the constructor must be provided
// by a java_lang_Thread::thread_acquire(thread_oop) call which gets
// us the JavaThread* stored in the java.lang.Thread object _before_
// the embedded ThreadsListHandle is constructed. We use acquire there
// to ensure that if we see a non-nullptr value, then we also see the
// main ThreadsList updates from the JavaThread* being added.
//
FastThreadsListHandle(oop thread_oop, JavaThread* java_thread);

JavaThread* protected_java_thread() {
return _protected_java_thread;
}
};

// This stack allocated JavaThreadIterator is used to walk the
// specified ThreadsList using the following style:
//
Expand Down

1 comment on commit 504ec27

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.