mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-16 17:14:41 +02:00
8257831: Suspend with handshakes
Reviewed-by: dcubed, rrich, dholmes, pchilanomate, sspitsyn
This commit is contained in:
parent
28af31db34
commit
86bd44fe80
40 changed files with 470 additions and 1081 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
|
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
|
@ -440,10 +440,6 @@ void AixAttachOperation::complete(jint result, bufferedStream* st) {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
// write operation result
|
// write operation result
|
||||||
char msg[32];
|
char msg[32];
|
||||||
sprintf(msg, "%d\n", result);
|
sprintf(msg, "%d\n", result);
|
||||||
|
@ -459,9 +455,6 @@ void AixAttachOperation::complete(jint result, bufferedStream* st) {
|
||||||
// done
|
// done
|
||||||
::close(this->socket());
|
::close(this->socket());
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,15 +465,8 @@ AttachOperation* AttachListener::dequeue() {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
AttachOperation* op = AixAttachListener::dequeue();
|
AttachOperation* op = AixAttachListener::dequeue();
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,15 +497,8 @@ int AttachListener::pd_init() {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
int ret_code = AixAttachListener::init();
|
int ret_code = AixAttachListener::init();
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -409,10 +409,6 @@ void BsdAttachOperation::complete(jint result, bufferedStream* st) {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
// write operation result
|
// write operation result
|
||||||
char msg[32];
|
char msg[32];
|
||||||
sprintf(msg, "%d\n", result);
|
sprintf(msg, "%d\n", result);
|
||||||
|
@ -427,9 +423,6 @@ void BsdAttachOperation::complete(jint result, bufferedStream* st) {
|
||||||
// done
|
// done
|
||||||
::close(this->socket());
|
::close(this->socket());
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,15 +433,8 @@ AttachOperation* AttachListener::dequeue() {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
AttachOperation* op = BsdAttachListener::dequeue();
|
AttachOperation* op = BsdAttachListener::dequeue();
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,15 +465,8 @@ int AttachListener::pd_init() {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
int ret_code = BsdAttachListener::init();
|
int ret_code = BsdAttachListener::init();
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -409,10 +409,6 @@ void LinuxAttachOperation::complete(jint result, bufferedStream* st) {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
// write operation result
|
// write operation result
|
||||||
char msg[32];
|
char msg[32];
|
||||||
sprintf(msg, "%d\n", result);
|
sprintf(msg, "%d\n", result);
|
||||||
|
@ -427,9 +423,6 @@ void LinuxAttachOperation::complete(jint result, bufferedStream* st) {
|
||||||
// done
|
// done
|
||||||
::close(this->socket());
|
::close(this->socket());
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,15 +433,8 @@ AttachOperation* AttachListener::dequeue() {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
AttachOperation* op = LinuxAttachListener::dequeue();
|
AttachOperation* op = LinuxAttachListener::dequeue();
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,15 +465,8 @@ int AttachListener::pd_init() {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
int ret_code = LinuxAttachListener::init();
|
int ret_code = LinuxAttachListener::init();
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1664,8 +1664,6 @@ void Parker::park(bool isAbsolute, jlong time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
|
OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
|
||||||
jt->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
|
|
||||||
|
|
||||||
assert(_cur_index == -1, "invariant");
|
assert(_cur_index == -1, "invariant");
|
||||||
if (time == 0) {
|
if (time == 0) {
|
||||||
|
@ -1688,11 +1686,6 @@ void Parker::park(bool isAbsolute, jlong time) {
|
||||||
// Paranoia to ensure our locked and lock-free paths interact
|
// Paranoia to ensure our locked and lock-free paths interact
|
||||||
// correctly with each other and Java-level accesses.
|
// correctly with each other and Java-level accesses.
|
||||||
OrderAccess::fence();
|
OrderAccess::fence();
|
||||||
|
|
||||||
// If externally suspended while waiting, re-suspend
|
|
||||||
if (jt->handle_special_suspend_equivalent_condition()) {
|
|
||||||
jt->java_suspend_self();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parker::unpark() {
|
void Parker::unpark() {
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "runtime/java.hpp"
|
#include "runtime/java.hpp"
|
||||||
#include "runtime/os.hpp"
|
#include "runtime/os.hpp"
|
||||||
#include "runtime/osThread.hpp"
|
#include "runtime/osThread.hpp"
|
||||||
|
#include "runtime/semaphore.inline.hpp"
|
||||||
#include "runtime/stubRoutines.hpp"
|
#include "runtime/stubRoutines.hpp"
|
||||||
#include "runtime/thread.hpp"
|
#include "runtime/thread.hpp"
|
||||||
#include "signals_posix.hpp"
|
#include "signals_posix.hpp"
|
||||||
|
@ -369,27 +370,7 @@ static int check_pending_signals() {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JavaThread *thread = JavaThread::current();
|
sig_semaphore->wait_with_safepoint_check(JavaThread::current());
|
||||||
ThreadBlockInVM tbivm(thread);
|
|
||||||
|
|
||||||
bool threadIsSuspended;
|
|
||||||
do {
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
|
|
||||||
sig_semaphore->wait();
|
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
|
|
||||||
if (threadIsSuspended) {
|
|
||||||
// The semaphore has been incremented, but while we were waiting
|
|
||||||
// another thread suspended us. We don't want to continue running
|
|
||||||
// while suspended because that would surprise the thread that
|
|
||||||
// suspended us.
|
|
||||||
sig_semaphore->signal();
|
|
||||||
|
|
||||||
thread->java_suspend_self();
|
|
||||||
}
|
|
||||||
} while (threadIsSuspended);
|
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
return 0; // Satisfy compiler
|
return 0; // Satisfy compiler
|
||||||
|
@ -1555,10 +1536,6 @@ void PosixSignals::hotspot_sigmask(Thread* thread) {
|
||||||
// - sets target osthread state to continue
|
// - sets target osthread state to continue
|
||||||
// - sends signal to end the sigsuspend loop in the SR_handler
|
// - sends signal to end the sigsuspend loop in the SR_handler
|
||||||
//
|
//
|
||||||
// Note that the SR_lock plays no role in this suspend/resume protocol,
|
|
||||||
// but is checked for NULL in SR_handler as a thread termination indicator.
|
|
||||||
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
|
|
||||||
//
|
|
||||||
// Note that resume_clear_context() and suspend_save_context() are needed
|
// Note that resume_clear_context() and suspend_save_context() are needed
|
||||||
// by SR_handler(), so that fetch_frame_from_context() works,
|
// by SR_handler(), so that fetch_frame_from_context() works,
|
||||||
// which in part is used by:
|
// which in part is used by:
|
||||||
|
@ -1603,11 +1580,11 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
|
||||||
|
|
||||||
// On some systems we have seen signal delivery get "stuck" until the signal
|
// On some systems we have seen signal delivery get "stuck" until the signal
|
||||||
// mask is changed as part of thread termination. Check that the current thread
|
// mask is changed as part of thread termination. Check that the current thread
|
||||||
// has not already terminated (via SR_lock()) - else the following assertion
|
// has not already terminated - else the following assertion
|
||||||
// will fail because the thread is no longer a JavaThread as the ~JavaThread
|
// will fail because the thread is no longer a JavaThread as the ~JavaThread
|
||||||
// destructor has completed.
|
// destructor has completed.
|
||||||
|
|
||||||
if (thread->SR_lock() == NULL) {
|
if (thread->has_terminated()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -310,10 +310,6 @@ void Win32AttachOperation::complete(jint result, bufferedStream* result_stream)
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
HANDLE hPipe = open_pipe();
|
HANDLE hPipe = open_pipe();
|
||||||
int lastError = (int)::GetLastError();
|
int lastError = (int)::GetLastError();
|
||||||
if (hPipe != INVALID_HANDLE_VALUE) {
|
if (hPipe != INVALID_HANDLE_VALUE) {
|
||||||
|
@ -351,9 +347,6 @@ void Win32AttachOperation::complete(jint result, bufferedStream* result_stream)
|
||||||
|
|
||||||
::ReleaseMutex(Win32AttachListener::mutex());
|
::ReleaseMutex(Win32AttachListener::mutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -363,15 +356,8 @@ AttachOperation* AttachListener::dequeue() {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
AttachOperation* op = Win32AttachListener::dequeue();
|
AttachOperation* op = Win32AttachListener::dequeue();
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
thread->check_and_wait_while_suspended();
|
|
||||||
|
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2207,28 +2207,7 @@ static int check_pending_signals() {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JavaThread *thread = JavaThread::current();
|
sig_sem->wait_with_safepoint_check(JavaThread::current());
|
||||||
|
|
||||||
ThreadBlockInVM tbivm(thread);
|
|
||||||
|
|
||||||
bool threadIsSuspended;
|
|
||||||
do {
|
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
|
|
||||||
sig_sem->wait();
|
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
|
|
||||||
if (threadIsSuspended) {
|
|
||||||
// The semaphore has been incremented, but while we were waiting
|
|
||||||
// another thread suspended us. We don't want to continue running
|
|
||||||
// while suspended because that would surprise the thread that
|
|
||||||
// suspended us.
|
|
||||||
sig_sem->signal();
|
|
||||||
|
|
||||||
thread->java_suspend_self();
|
|
||||||
}
|
|
||||||
} while (threadIsSuspended);
|
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
return 0; // Satisfy compiler
|
return 0; // Satisfy compiler
|
||||||
|
@ -5487,15 +5466,9 @@ void Parker::park(bool isAbsolute, jlong time) {
|
||||||
} else {
|
} else {
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
||||||
thread->set_suspend_equivalent();
|
|
||||||
|
|
||||||
WaitForSingleObject(_ParkHandle, time);
|
WaitForSingleObject(_ParkHandle, time);
|
||||||
ResetEvent(_ParkHandle);
|
ResetEvent(_ParkHandle);
|
||||||
|
|
||||||
// If externally suspended while waiting, re-suspend
|
|
||||||
if (thread->handle_special_suspend_equivalent_condition()) {
|
|
||||||
thread->java_suspend_self();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,7 @@
|
||||||
LOG_TAG(stringtable) \
|
LOG_TAG(stringtable) \
|
||||||
LOG_TAG(subclass) \
|
LOG_TAG(subclass) \
|
||||||
LOG_TAG(survivor) \
|
LOG_TAG(survivor) \
|
||||||
|
LOG_TAG(suspend) \
|
||||||
LOG_TAG(sweep) \
|
LOG_TAG(sweep) \
|
||||||
LOG_TAG(symboltable) \
|
LOG_TAG(symboltable) \
|
||||||
LOG_TAG(system) \
|
LOG_TAG(system) \
|
||||||
|
|
|
@ -2980,32 +2980,9 @@ JVM_ENTRY(void, JVM_SuspendThread(JNIEnv* env, jobject jthread))
|
||||||
JavaThread* receiver = NULL;
|
JavaThread* receiver = NULL;
|
||||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
||||||
if (is_alive) {
|
if (is_alive) {
|
||||||
// jthread refers to a live JavaThread.
|
// jthread refers to a live JavaThread, but java_suspend() will
|
||||||
{
|
// detect a thread that has started to exit and will ignore it.
|
||||||
MutexLocker ml(receiver->SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
if (receiver->is_external_suspend()) {
|
|
||||||
// Don't allow nested external suspend requests. We can't return
|
|
||||||
// an error from this interface so just ignore the problem.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (receiver->is_exiting()) { // thread is in the process of exiting
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
receiver->set_external_suspend();
|
|
||||||
}
|
|
||||||
|
|
||||||
// java_suspend() will catch threads in the process of exiting
|
|
||||||
// and will ignore them.
|
|
||||||
receiver->java_suspend();
|
receiver->java_suspend();
|
||||||
|
|
||||||
// It would be nice to have the following assertion in all the
|
|
||||||
// time, but it is possible for a racing resume request to have
|
|
||||||
// resumed this thread right after we suspended it. Temporarily
|
|
||||||
// enable this assertion if you are chasing a different kind of
|
|
||||||
// bug.
|
|
||||||
//
|
|
||||||
// assert(java_lang_Thread::thread(receiver->threadObj()) == NULL ||
|
|
||||||
// receiver->is_being_ext_suspended(), "thread is not suspended");
|
|
||||||
}
|
}
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
@ -3016,22 +2993,6 @@ JVM_ENTRY(void, JVM_ResumeThread(JNIEnv* env, jobject jthread))
|
||||||
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
|
||||||
if (is_alive) {
|
if (is_alive) {
|
||||||
// jthread refers to a live JavaThread.
|
// jthread refers to a live JavaThread.
|
||||||
|
|
||||||
// This is the original comment for this Threads_lock grab:
|
|
||||||
// We need to *always* get the threads lock here, since this operation cannot be allowed during
|
|
||||||
// a safepoint. The safepoint code relies on suspending a thread to examine its state. If other
|
|
||||||
// threads randomly resumes threads, then a thread might not be suspended when the safepoint code
|
|
||||||
// looks at it.
|
|
||||||
//
|
|
||||||
// The above comment dates back to when we had both internal and
|
|
||||||
// external suspend APIs that shared a common underlying mechanism.
|
|
||||||
// External suspend is now entirely cooperative and doesn't share
|
|
||||||
// anything with internal suspend. That said, there are some
|
|
||||||
// assumptions in the VM that an external resume grabs the
|
|
||||||
// Threads_lock. We can't drop the Threads_lock grab here until we
|
|
||||||
// resolve the assumptions that exist elsewhere.
|
|
||||||
//
|
|
||||||
MutexLocker ml(Threads_lock);
|
|
||||||
receiver->java_resume();
|
receiver->java_resume();
|
||||||
}
|
}
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
|
@ -876,7 +876,7 @@ JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
|
||||||
// We have a JavaThread* so add more state bits.
|
// We have a JavaThread* so add more state bits.
|
||||||
JavaThreadState jts = java_thread->thread_state();
|
JavaThreadState jts = java_thread->thread_state();
|
||||||
|
|
||||||
if (java_thread->is_being_ext_suspended()) {
|
if (java_thread->is_suspended()) {
|
||||||
state |= JVMTI_THREAD_STATE_SUSPENDED;
|
state |= JVMTI_THREAD_STATE_SUSPENDED;
|
||||||
}
|
}
|
||||||
if (jts == _thread_in_native) {
|
if (jts == _thread_in_native) {
|
||||||
|
@ -942,24 +942,18 @@ jvmtiError
|
||||||
JvmtiEnv::SuspendThread(JavaThread* java_thread) {
|
JvmtiEnv::SuspendThread(JavaThread* java_thread) {
|
||||||
// don't allow hidden thread suspend request.
|
// don't allow hidden thread suspend request.
|
||||||
if (java_thread->is_hidden_from_external_view()) {
|
if (java_thread->is_hidden_from_external_view()) {
|
||||||
return (JVMTI_ERROR_NONE);
|
return JVMTI_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
if (java_thread->is_suspended()) {
|
||||||
{
|
return JVMTI_ERROR_THREAD_SUSPENDED;
|
||||||
MutexLocker ml(java_thread->SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
if (java_thread->is_external_suspend()) {
|
|
||||||
// don't allow nested external suspend requests.
|
|
||||||
return (JVMTI_ERROR_THREAD_SUSPENDED);
|
|
||||||
}
|
}
|
||||||
if (java_thread->is_exiting()) { // thread is in the process of exiting
|
|
||||||
return (JVMTI_ERROR_THREAD_NOT_ALIVE);
|
|
||||||
}
|
|
||||||
java_thread->set_external_suspend();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!JvmtiSuspendControl::suspend(java_thread)) {
|
if (!JvmtiSuspendControl::suspend(java_thread)) {
|
||||||
// the thread was in the process of exiting
|
// Either the thread is already suspended or
|
||||||
return (JVMTI_ERROR_THREAD_NOT_ALIVE);
|
// it was in the process of exiting.
|
||||||
|
if (java_thread->is_exiting()) {
|
||||||
|
return JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||||
|
}
|
||||||
|
return JVMTI_ERROR_THREAD_SUSPENDED;
|
||||||
}
|
}
|
||||||
return JVMTI_ERROR_NONE;
|
return JVMTI_ERROR_NONE;
|
||||||
} /* end SuspendThread */
|
} /* end SuspendThread */
|
||||||
|
@ -970,8 +964,10 @@ JvmtiEnv::SuspendThread(JavaThread* java_thread) {
|
||||||
// results - pre-checked for NULL
|
// results - pre-checked for NULL
|
||||||
jvmtiError
|
jvmtiError
|
||||||
JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
|
JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
|
||||||
|
int self_index = -1;
|
||||||
int needSafepoint = 0; // > 0 if we need a safepoint
|
int needSafepoint = 0; // > 0 if we need a safepoint
|
||||||
ThreadsListHandle tlh;
|
JavaThread* current = JavaThread::current();
|
||||||
|
ThreadsListHandle tlh(current);
|
||||||
for (int i = 0; i < request_count; i++) {
|
for (int i = 0; i < request_count; i++) {
|
||||||
JavaThread *java_thread = NULL;
|
JavaThread *java_thread = NULL;
|
||||||
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
|
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
|
||||||
|
@ -984,38 +980,38 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm
|
||||||
results[i] = JVMTI_ERROR_NONE; // indicate successful suspend
|
results[i] = JVMTI_ERROR_NONE; // indicate successful suspend
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (java_thread->is_suspended()) {
|
||||||
{
|
|
||||||
MutexLocker ml(java_thread->SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
if (java_thread->is_external_suspend()) {
|
|
||||||
// don't allow nested external suspend requests.
|
|
||||||
results[i] = JVMTI_ERROR_THREAD_SUSPENDED;
|
results[i] = JVMTI_ERROR_THREAD_SUSPENDED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (java_thread->is_exiting()) { // thread is in the process of exiting
|
if (java_thread == current) {
|
||||||
results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
self_index = i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
java_thread->set_external_suspend();
|
|
||||||
}
|
|
||||||
if (java_thread->thread_state() == _thread_in_native) {
|
|
||||||
// We need to try and suspend native threads here. Threads in
|
|
||||||
// other states will self-suspend on their next transition.
|
|
||||||
if (!JvmtiSuspendControl::suspend(java_thread)) {
|
if (!JvmtiSuspendControl::suspend(java_thread)) {
|
||||||
// The thread was in the process of exiting. Force another
|
// Either the thread is already suspended or
|
||||||
// safepoint to make sure that this thread transitions.
|
// it was in the process of exiting.
|
||||||
needSafepoint++;
|
if (java_thread->is_exiting()) {
|
||||||
results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
results[i] = JVMTI_ERROR_THREAD_SUSPENDED;
|
||||||
needSafepoint++;
|
continue;
|
||||||
}
|
}
|
||||||
results[i] = JVMTI_ERROR_NONE; // indicate successful suspend
|
results[i] = JVMTI_ERROR_NONE; // indicate successful suspend
|
||||||
}
|
}
|
||||||
if (needSafepoint > 0) {
|
if (self_index >= 0) {
|
||||||
VM_ThreadsSuspendJVMTI tsj;
|
if (!JvmtiSuspendControl::suspend(current)) {
|
||||||
VMThread::execute(&tsj);
|
// Either the thread is already suspended or
|
||||||
|
// it was in the process of exiting.
|
||||||
|
if (current->is_exiting()) {
|
||||||
|
results[self_index] = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||||
|
} else {
|
||||||
|
results[self_index] = JVMTI_ERROR_THREAD_SUSPENDED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results[self_index] = JVMTI_ERROR_NONE; // indicate successful suspend
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// per-thread suspend results returned via results parameter
|
// per-thread suspend results returned via results parameter
|
||||||
return JVMTI_ERROR_NONE;
|
return JVMTI_ERROR_NONE;
|
||||||
|
@ -1030,11 +1026,9 @@ JvmtiEnv::ResumeThread(JavaThread* java_thread) {
|
||||||
if (java_thread->is_hidden_from_external_view()) {
|
if (java_thread->is_hidden_from_external_view()) {
|
||||||
return JVMTI_ERROR_NONE;
|
return JVMTI_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
if (!java_thread->is_suspended()) {
|
||||||
if (!java_thread->is_being_ext_suspended()) {
|
|
||||||
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JvmtiSuspendControl::resume(java_thread)) {
|
if (!JvmtiSuspendControl::resume(java_thread)) {
|
||||||
return JVMTI_ERROR_INTERNAL;
|
return JVMTI_ERROR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
@ -1060,7 +1054,7 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt
|
||||||
results[i] = JVMTI_ERROR_NONE; // indicate successful resume
|
results[i] = JVMTI_ERROR_NONE; // indicate successful resume
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!java_thread->is_being_ext_suspended()) {
|
if (!java_thread->is_suspended()) {
|
||||||
results[i] = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
results[i] = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1181,8 +1181,7 @@ MultipleStackTracesCollector::fill_frames(jthread jt, JavaThread *thr, oop threa
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thr != NULL) { // add more state bits if there is a JavaThead to query
|
if (thr != NULL) { // add more state bits if there is a JavaThead to query
|
||||||
// same as is_being_ext_suspended() but without locking
|
if (thr->is_suspended()) {
|
||||||
if (thr->is_ext_suspended() || thr->is_external_suspend()) {
|
|
||||||
state |= JVMTI_THREAD_STATE_SUSPENDED;
|
state |= JVMTI_THREAD_STATE_SUSPENDED;
|
||||||
}
|
}
|
||||||
JavaThreadState jts = thr->thread_state();
|
JavaThreadState jts = thr->thread_state();
|
||||||
|
@ -1400,7 +1399,7 @@ SetForceEarlyReturn::doit(Thread *target, bool self) {
|
||||||
HandleMark hm(current_thread);
|
HandleMark hm(current_thread);
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
if (!java_thread->is_external_suspend()) {
|
if (!java_thread->is_suspended()) {
|
||||||
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1533,7 +1532,7 @@ UpdateForPopTopFrameClosure::doit(Thread *target, bool self) {
|
||||||
JavaThread* java_thread = target->as_Java_thread();
|
JavaThread* java_thread = target->as_Java_thread();
|
||||||
assert(java_thread == _state->get_thread(), "Must be");
|
assert(java_thread == _state->get_thread(), "Must be");
|
||||||
|
|
||||||
if (!self && !java_thread->is_external_suspend()) {
|
if (!self && !java_thread->is_suspended()) {
|
||||||
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1624,7 +1623,7 @@ SetFramePopClosure::doit(Thread *target, bool self) {
|
||||||
|
|
||||||
assert(_state->get_thread() == java_thread, "Must be");
|
assert(_state->get_thread() == java_thread, "Must be");
|
||||||
|
|
||||||
if (!self && !java_thread->is_external_suspend()) {
|
if (!self && !java_thread->is_suspended()) {
|
||||||
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -765,47 +765,13 @@ VM_GetReceiver::VM_GetReceiver(
|
||||||
//
|
//
|
||||||
|
|
||||||
bool JvmtiSuspendControl::suspend(JavaThread *java_thread) {
|
bool JvmtiSuspendControl::suspend(JavaThread *java_thread) {
|
||||||
// external suspend should have caught suspending a thread twice
|
return java_thread->java_suspend();
|
||||||
|
|
||||||
// Immediate suspension required for JPDA back-end so JVMTI agent threads do
|
|
||||||
// not deadlock due to later suspension on transitions while holding
|
|
||||||
// raw monitors. Passing true causes the immediate suspension.
|
|
||||||
// java_suspend() will catch threads in the process of exiting
|
|
||||||
// and will ignore them.
|
|
||||||
java_thread->java_suspend();
|
|
||||||
|
|
||||||
// It would be nice to have the following assertion in all the time,
|
|
||||||
// but it is possible for a racing resume request to have resumed
|
|
||||||
// this thread right after we suspended it. Temporarily enable this
|
|
||||||
// assertion if you are chasing a different kind of bug.
|
|
||||||
//
|
|
||||||
// assert(java_lang_Thread::thread(java_thread->threadObj()) == NULL ||
|
|
||||||
// java_thread->is_being_ext_suspended(), "thread is not suspended");
|
|
||||||
|
|
||||||
if (java_lang_Thread::thread(java_thread->threadObj()) == NULL) {
|
|
||||||
// check again because we can get delayed in java_suspend():
|
|
||||||
// the thread is in process of exiting.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JvmtiSuspendControl::resume(JavaThread *java_thread) {
|
bool JvmtiSuspendControl::resume(JavaThread *java_thread) {
|
||||||
// external suspend should have caught resuming a thread twice
|
return java_thread->java_resume();
|
||||||
assert(java_thread->is_being_ext_suspended(), "thread should be suspended");
|
|
||||||
|
|
||||||
// resume thread
|
|
||||||
{
|
|
||||||
// must always grab Threads_lock, see JVM_SuspendThread
|
|
||||||
MutexLocker ml(Threads_lock);
|
|
||||||
java_thread->java_resume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void JvmtiSuspendControl::print() {
|
void JvmtiSuspendControl::print() {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
|
@ -817,7 +783,7 @@ void JvmtiSuspendControl::print() {
|
||||||
#else
|
#else
|
||||||
const char *name = "";
|
const char *name = "";
|
||||||
#endif /*JVMTI_TRACE */
|
#endif /*JVMTI_TRACE */
|
||||||
log_stream.print("%s(%c ", name, thread->is_being_ext_suspended() ? 'S' : '_');
|
log_stream.print("%s(%c ", name, thread->is_suspended() ? 'S' : '_');
|
||||||
if (!thread->has_last_Java_frame()) {
|
if (!thread->has_last_Java_frame()) {
|
||||||
log_stream.print("no stack");
|
log_stream.print("no stack");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -241,7 +241,6 @@ int JvmtiRawMonitor::simple_wait(Thread* self, jlong millis) {
|
||||||
ret = M_INTERRUPTED;
|
ret = M_INTERRUPTED;
|
||||||
} else {
|
} else {
|
||||||
ThreadBlockInVM tbivm(jt);
|
ThreadBlockInVM tbivm(jt);
|
||||||
jt->set_suspend_equivalent();
|
|
||||||
if (millis <= 0) {
|
if (millis <= 0) {
|
||||||
self->_ParkEvent->park();
|
self->_ParkEvent->park();
|
||||||
} else {
|
} else {
|
||||||
|
@ -307,7 +306,8 @@ void JvmtiRawMonitor::simple_notify(Thread* self, bool all) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any JavaThread will enter here with state _thread_blocked
|
// Any JavaThread will enter here with state _thread_blocked unless we
|
||||||
|
// are in single-threaded mode during startup.
|
||||||
void JvmtiRawMonitor::raw_enter(Thread* self) {
|
void JvmtiRawMonitor::raw_enter(Thread* self) {
|
||||||
void* contended;
|
void* contended;
|
||||||
JavaThread* jt = NULL;
|
JavaThread* jt = NULL;
|
||||||
|
@ -315,15 +315,28 @@ void JvmtiRawMonitor::raw_enter(Thread* self) {
|
||||||
// surprise the suspender if a "suspended" thread can still enter monitor
|
// surprise the suspender if a "suspended" thread can still enter monitor
|
||||||
if (self->is_Java_thread()) {
|
if (self->is_Java_thread()) {
|
||||||
jt = self->as_Java_thread();
|
jt = self->as_Java_thread();
|
||||||
jt->SR_lock()->lock_without_safepoint_check();
|
while (true) {
|
||||||
while (jt->is_external_suspend()) {
|
// To pause suspend requests while in blocked we must block handshakes.
|
||||||
jt->SR_lock()->unlock();
|
jt->handshake_state()->lock();
|
||||||
jt->java_suspend_self();
|
// Suspend request flag can only be set in handshakes.
|
||||||
jt->SR_lock()->lock_without_safepoint_check();
|
// By blocking handshakes, suspend request flag cannot change its value.
|
||||||
}
|
if (!jt->handshake_state()->is_suspended()) {
|
||||||
// guarded by SR_lock to avoid racing with new external suspend requests.
|
|
||||||
contended = Atomic::cmpxchg(&_owner, (Thread*)NULL, jt);
|
contended = Atomic::cmpxchg(&_owner, (Thread*)NULL, jt);
|
||||||
jt->SR_lock()->unlock();
|
jt->handshake_state()->unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
jt->handshake_state()->unlock();
|
||||||
|
|
||||||
|
// We may only be in states other than _thread_blocked when we are
|
||||||
|
// in single-threaded mode during startup.
|
||||||
|
guarantee(jt->thread_state() == _thread_blocked, "invariant");
|
||||||
|
|
||||||
|
jt->set_thread_state_fence(_thread_blocked_trans);
|
||||||
|
SafepointMechanism::process_if_requested(jt);
|
||||||
|
// We should transition to thread_in_vm and then to thread_in_vm_trans,
|
||||||
|
// but those are always treated the same as _thread_blocked_trans.
|
||||||
|
jt->set_thread_state(_thread_blocked);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
contended = Atomic::cmpxchg(&_owner, (Thread*)NULL, self);
|
contended = Atomic::cmpxchg(&_owner, (Thread*)NULL, self);
|
||||||
}
|
}
|
||||||
|
@ -344,28 +357,24 @@ void JvmtiRawMonitor::raw_enter(Thread* self) {
|
||||||
if (!self->is_Java_thread()) {
|
if (!self->is_Java_thread()) {
|
||||||
simple_enter(self);
|
simple_enter(self);
|
||||||
} else {
|
} else {
|
||||||
|
// In multi-threaded mode, we must enter this method blocked.
|
||||||
guarantee(jt->thread_state() == _thread_blocked, "invariant");
|
guarantee(jt->thread_state() == _thread_blocked, "invariant");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
jt->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self()
|
|
||||||
simple_enter(jt);
|
simple_enter(jt);
|
||||||
|
if (!SafepointMechanism::should_process(jt)) {
|
||||||
// were we externally suspended while we were waiting?
|
// Not suspended so we're done here.
|
||||||
if (!jt->handle_special_suspend_equivalent_condition()) {
|
break;
|
||||||
|
}
|
||||||
|
if (!jt->is_suspended()) {
|
||||||
|
// Not suspended so we're done here.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This thread was externally suspended
|
|
||||||
// We have reentered the contended monitor, but while we were
|
|
||||||
// waiting another thread suspended us. We don't want to reenter
|
|
||||||
// the monitor while suspended because that would surprise the
|
|
||||||
// thread that suspended us.
|
|
||||||
//
|
|
||||||
// Drop the lock
|
|
||||||
simple_exit(jt);
|
simple_exit(jt);
|
||||||
|
jt->set_thread_state_fence(_thread_blocked_trans);
|
||||||
jt->java_suspend_self();
|
SafepointMechanism::process_if_requested(jt);
|
||||||
|
// We should transition to thread_in_vm and then to thread_in_vm_trans,
|
||||||
|
// but those are always treated the same as _thread_blocked_trans.
|
||||||
|
jt->set_thread_state(_thread_blocked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,30 +420,23 @@ int JvmtiRawMonitor::raw_wait(jlong millis, Thread* self) {
|
||||||
|
|
||||||
if (self->is_Java_thread()) {
|
if (self->is_Java_thread()) {
|
||||||
JavaThread* jt = self->as_Java_thread();
|
JavaThread* jt = self->as_Java_thread();
|
||||||
|
guarantee(jt->thread_state() == _thread_in_native, "invariant");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
jt->set_suspend_equivalent();
|
if (!SafepointMechanism::should_process(jt)) {
|
||||||
if (!jt->handle_special_suspend_equivalent_condition()) {
|
// Not suspended so we're done here:
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
// We've been suspended whilst waiting and so we have to
|
|
||||||
// relinquish the raw monitor until we are resumed. Of course
|
|
||||||
// after reacquiring we have to re-check for suspension again.
|
|
||||||
// Suspension requires we are _thread_blocked, and we also have to
|
|
||||||
// recheck for being interrupted.
|
|
||||||
simple_exit(jt);
|
|
||||||
{
|
|
||||||
ThreadInVMfromNative tivm(jt);
|
|
||||||
{
|
|
||||||
ThreadBlockInVM tbivm(jt);
|
|
||||||
jt->java_suspend_self();
|
|
||||||
}
|
}
|
||||||
|
simple_exit(jt);
|
||||||
|
jt->set_thread_state_fence(_thread_in_native_trans);
|
||||||
|
SafepointMechanism::process_if_requested(jt);
|
||||||
if (jt->is_interrupted(true)) {
|
if (jt->is_interrupted(true)) {
|
||||||
ret = M_INTERRUPTED;
|
ret = M_INTERRUPTED;
|
||||||
}
|
}
|
||||||
}
|
// We should transition to thread_in_vm and then to thread_in_vm_trans,
|
||||||
|
// but those are always treated the same as _thread_in_native_trans.
|
||||||
|
jt->set_thread_state(_thread_in_native);
|
||||||
simple_enter(jt);
|
simple_enter(jt);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
guarantee(jt == _owner, "invariant");
|
guarantee(jt == _owner, "invariant");
|
||||||
} else {
|
} else {
|
||||||
assert(ret != M_INTERRUPTED, "Only JavaThreads can be interrupted");
|
assert(ret != M_INTERRUPTED, "Only JavaThreads can be interrupted");
|
||||||
|
|
|
@ -294,11 +294,6 @@ int JvmtiThreadState::cur_stack_depth() {
|
||||||
return _cur_stack_depth;
|
return _cur_stack_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JvmtiThreadState::may_be_walked() {
|
|
||||||
return (get_thread()->is_being_ext_suspended() || (JavaThread::current() == get_thread()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void JvmtiThreadState::process_pending_step_for_popframe() {
|
void JvmtiThreadState::process_pending_step_for_popframe() {
|
||||||
// We are single stepping as the last part of the PopFrame() dance
|
// We are single stepping as the last part of the PopFrame() dance
|
||||||
// so we have some house keeping to do.
|
// so we have some house keeping to do.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -312,8 +312,6 @@ class JvmtiThreadState : public CHeapObj<mtInternal> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool may_be_walked();
|
|
||||||
|
|
||||||
// Thread local event collector setter and getter methods.
|
// Thread local event collector setter and getter methods.
|
||||||
JvmtiDynamicCodeEventCollector* get_dynamic_code_event_collector() {
|
JvmtiDynamicCodeEventCollector* get_dynamic_code_event_collector() {
|
||||||
return _dynamic_code_event_collector;
|
return _dynamic_code_event_collector;
|
||||||
|
|
|
@ -521,6 +521,8 @@ static SpecialFlag const special_jvm_flags[] = {
|
||||||
{ "InitialRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
|
{ "InitialRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
|
||||||
{ "AllowRedefinitionToAddDeleteMethods", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
|
{ "AllowRedefinitionToAddDeleteMethods", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
|
||||||
{ "FlightRecorder", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
|
{ "FlightRecorder", JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
|
||||||
|
{ "SuspendRetryCount", JDK_Version::undefined(), JDK_Version::jdk(17), JDK_Version::jdk(18) },
|
||||||
|
{ "SuspendRetryDelay", JDK_Version::undefined(), JDK_Version::jdk(17), JDK_Version::jdk(18) },
|
||||||
{ "CriticalJNINatives", JDK_Version::jdk(16), JDK_Version::jdk(17), JDK_Version::jdk(18) },
|
{ "CriticalJNINatives", JDK_Version::jdk(16), JDK_Version::jdk(17), JDK_Version::jdk(18) },
|
||||||
{ "AlwaysLockClassLoader", JDK_Version::jdk(17), JDK_Version::jdk(18), JDK_Version::jdk(19) },
|
{ "AlwaysLockClassLoader", JDK_Version::jdk(17), JDK_Version::jdk(18), JDK_Version::jdk(19) },
|
||||||
{ "UseBiasedLocking", JDK_Version::jdk(15), JDK_Version::jdk(18), JDK_Version::jdk(19) },
|
{ "UseBiasedLocking", JDK_Version::jdk(15), JDK_Version::jdk(18), JDK_Version::jdk(19) },
|
||||||
|
|
|
@ -426,16 +426,6 @@ const intx ObjectAlignmentInBytes = 8;
|
||||||
"Delay in milliseconds for option AbortVMOnVMOperationTimeout") \
|
"Delay in milliseconds for option AbortVMOnVMOperationTimeout") \
|
||||||
range(0, max_intx) \
|
range(0, max_intx) \
|
||||||
\
|
\
|
||||||
/* 50 retries * (5 * current_retry_count) millis = ~6.375 seconds */ \
|
|
||||||
/* typically, at most a few retries are needed */ \
|
|
||||||
product(intx, SuspendRetryCount, 50, \
|
|
||||||
"Maximum retry count for an external suspend request") \
|
|
||||||
range(0, max_intx) \
|
|
||||||
\
|
|
||||||
product(intx, SuspendRetryDelay, 5, \
|
|
||||||
"Milliseconds to delay per retry (* current_retry_count)") \
|
|
||||||
range(0, max_intx) \
|
|
||||||
\
|
|
||||||
product(bool, MaxFDLimit, true, \
|
product(bool, MaxFDLimit, true, \
|
||||||
"Bump the number of file descriptors to maximum (Unix only)") \
|
"Bump the number of file descriptors to maximum (Unix only)") \
|
||||||
\
|
\
|
||||||
|
|
|
@ -405,14 +405,14 @@ HandshakeState::HandshakeState(JavaThread* target) :
|
||||||
_handshakee(target),
|
_handshakee(target),
|
||||||
_queue(),
|
_queue(),
|
||||||
_lock(Monitor::leaf, "HandshakeState", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never),
|
_lock(Monitor::leaf, "HandshakeState", Mutex::_allow_vm_block_flag, Monitor::_safepoint_check_never),
|
||||||
_active_handshaker()
|
_active_handshaker(),
|
||||||
|
_suspended(false),
|
||||||
|
_async_suspend_handshake(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandshakeState::add_operation(HandshakeOperation* op) {
|
void HandshakeState::add_operation(HandshakeOperation* op) {
|
||||||
// Adds are done lock free and so is arming.
|
// Adds are done lock free and so is arming.
|
||||||
// Calling this method with lock held is considered an error.
|
|
||||||
assert(!_lock.owned_by_self(), "Lock should not be held");
|
|
||||||
_queue.push(op);
|
_queue.push(op);
|
||||||
SafepointMechanism::arm_local_poll_release(_handshakee);
|
SafepointMechanism::arm_local_poll_release(_handshakee);
|
||||||
}
|
}
|
||||||
|
@ -453,22 +453,23 @@ HandshakeOperation* HandshakeState::pop() {
|
||||||
return _queue.pop(non_self_queue_filter);
|
return _queue.pop(non_self_queue_filter);
|
||||||
};
|
};
|
||||||
|
|
||||||
void HandshakeState::process_by_self() {
|
bool HandshakeState::process_by_self() {
|
||||||
assert(Thread::current() == _handshakee, "should call from _handshakee");
|
assert(Thread::current() == _handshakee, "should call from _handshakee");
|
||||||
assert(!_handshakee->is_terminated(), "should not be a terminated thread");
|
assert(!_handshakee->is_terminated(), "should not be a terminated thread");
|
||||||
assert(_handshakee->thread_state() != _thread_blocked, "should not be in a blocked state");
|
assert(_handshakee->thread_state() != _thread_blocked, "should not be in a blocked state");
|
||||||
assert(_handshakee->thread_state() != _thread_in_native, "should not be in native");
|
assert(_handshakee->thread_state() != _thread_in_native, "should not be in native");
|
||||||
ThreadInVMForHandshake tivm(_handshakee);
|
ThreadInVMForHandshake tivm(_handshakee);
|
||||||
{
|
{
|
||||||
|
// Handshakes cannot safely safepoint.
|
||||||
|
// The exception to this rule is the asynchronous suspension handshake.
|
||||||
|
// It by-passes the NSV by manually doing the transition.
|
||||||
NoSafepointVerifier nsv;
|
NoSafepointVerifier nsv;
|
||||||
process_self_inner();
|
return process_self_inner();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandshakeState::process_self_inner() {
|
bool HandshakeState::process_self_inner() {
|
||||||
while (should_process()) {
|
while (should_process()) {
|
||||||
HandleMark hm(_handshakee);
|
|
||||||
PreserveExceptionMark pem(_handshakee);
|
|
||||||
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
|
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
|
||||||
HandshakeOperation* op = pop_for_self();
|
HandshakeOperation* op = pop_for_self();
|
||||||
if (op != NULL) {
|
if (op != NULL) {
|
||||||
|
@ -477,13 +478,24 @@ void HandshakeState::process_self_inner() {
|
||||||
log_trace(handshake)("Proc handshake %s " INTPTR_FORMAT " on " INTPTR_FORMAT " by self",
|
log_trace(handshake)("Proc handshake %s " INTPTR_FORMAT " on " INTPTR_FORMAT " by self",
|
||||||
async ? "asynchronous" : "synchronous", p2i(op), p2i(_handshakee));
|
async ? "asynchronous" : "synchronous", p2i(op), p2i(_handshakee));
|
||||||
op->prepare(_handshakee, _handshakee);
|
op->prepare(_handshakee, _handshakee);
|
||||||
|
if (!async) {
|
||||||
|
HandleMark hm(_handshakee);
|
||||||
|
PreserveExceptionMark pem(_handshakee);
|
||||||
|
op->do_handshake(_handshakee);
|
||||||
|
} else {
|
||||||
|
// An asynchronous handshake may put the JavaThread in blocked state (safepoint safe).
|
||||||
|
// The destructor ~PreserveExceptionMark touches the exception oop so it must not be executed,
|
||||||
|
// since a safepoint may be in-progress when returning from the async handshake.
|
||||||
op->do_handshake(_handshakee);
|
op->do_handshake(_handshakee);
|
||||||
if (async) {
|
|
||||||
log_handshake_info(((AsyncHandshakeOperation*)op)->start_time(), op->name(), 1, 0, "asynchronous");
|
log_handshake_info(((AsyncHandshakeOperation*)op)->start_time(), op->name(), 1, 0, "asynchronous");
|
||||||
delete op;
|
delete op;
|
||||||
|
return true; // Must check for safepoints
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandshakeState::can_process_handshake() {
|
bool HandshakeState::can_process_handshake() {
|
||||||
|
@ -587,3 +599,102 @@ HandshakeState::ProcessResult HandshakeState::try_process(HandshakeOperation* ma
|
||||||
pr_ret == HandshakeState::_succeeded ? "including" : "excluding", p2i(match_op));
|
pr_ret == HandshakeState::_succeeded ? "including" : "excluding", p2i(match_op));
|
||||||
return pr_ret;
|
return pr_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HandshakeState::lock() {
|
||||||
|
_lock.lock_without_safepoint_check();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandshakeState::unlock() {
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandshakeState::do_self_suspend() {
|
||||||
|
assert(Thread::current() == _handshakee, "should call from _handshakee");
|
||||||
|
assert(_lock.owned_by_self(), "Lock must be held");
|
||||||
|
assert(!_handshakee->has_last_Java_frame() || _handshakee->frame_anchor()->walkable(), "should have walkable stack");
|
||||||
|
JavaThreadState jts = _handshakee->thread_state();
|
||||||
|
while (is_suspended()) {
|
||||||
|
_handshakee->set_thread_state(_thread_blocked);
|
||||||
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended", p2i(_handshakee));
|
||||||
|
_lock.wait_without_safepoint_check();
|
||||||
|
}
|
||||||
|
_handshakee->set_thread_state(jts);
|
||||||
|
set_async_suspend_handshake(false);
|
||||||
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " resumed", p2i(_handshakee));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the closure that prevents a suspended JavaThread from
|
||||||
|
// escaping the suspend request.
|
||||||
|
class ThreadSelfSuspensionHandshake : public AsyncHandshakeClosure {
|
||||||
|
public:
|
||||||
|
ThreadSelfSuspensionHandshake() : AsyncHandshakeClosure("ThreadSelfSuspensionHandshake") {}
|
||||||
|
void do_thread(Thread* thr) {
|
||||||
|
JavaThread* current = thr->as_Java_thread();
|
||||||
|
assert(current == Thread::current(), "Must be self executed.");
|
||||||
|
current->handshake_state()->do_self_suspend();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HandshakeState::suspend_with_handshake() {
|
||||||
|
if (_handshakee->is_exiting() ||
|
||||||
|
_handshakee->threadObj() == NULL) {
|
||||||
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " exiting", p2i(_handshakee));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (has_async_suspend_handshake()) {
|
||||||
|
if (is_suspended()) {
|
||||||
|
// Target is already suspended.
|
||||||
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " already suspended", p2i(_handshakee));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Target is going to wake up and leave suspension.
|
||||||
|
// Let's just stop the thread from doing that.
|
||||||
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " re-suspended", p2i(_handshakee));
|
||||||
|
set_suspended(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no suspend request
|
||||||
|
assert(!is_suspended(), "cannot be suspended without a suspend request");
|
||||||
|
// Thread is safe, so it must execute the request, thus we can count it as suspended
|
||||||
|
// from this point.
|
||||||
|
set_suspended(true);
|
||||||
|
set_async_suspend_handshake(true);
|
||||||
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended, arming ThreadSuspension", p2i(_handshakee));
|
||||||
|
ThreadSelfSuspensionHandshake* ts = new ThreadSelfSuspensionHandshake();
|
||||||
|
Handshake::execute(ts, _handshakee);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the closure that synchronously honors the suspend request.
|
||||||
|
class SuspendThreadHandshake : public HandshakeClosure {
|
||||||
|
bool _did_suspend;
|
||||||
|
public:
|
||||||
|
SuspendThreadHandshake() : HandshakeClosure("SuspendThread"), _did_suspend(false) {}
|
||||||
|
void do_thread(Thread* thr) {
|
||||||
|
JavaThread* target = thr->as_Java_thread();
|
||||||
|
_did_suspend = target->handshake_state()->suspend_with_handshake();
|
||||||
|
}
|
||||||
|
bool did_suspend() { return _did_suspend; }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HandshakeState::suspend() {
|
||||||
|
SuspendThreadHandshake st;
|
||||||
|
Handshake::execute(&st, _handshakee);
|
||||||
|
return st.did_suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandshakeState::resume() {
|
||||||
|
if (!is_suspended()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
if (!is_suspended()) {
|
||||||
|
assert(!_handshakee->is_suspended(), "cannot be suspended without a suspend request");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Resume the thread.
|
||||||
|
set_suspended(false);
|
||||||
|
_lock.notify();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
class HandshakeOperation;
|
class HandshakeOperation;
|
||||||
class JavaThread;
|
class JavaThread;
|
||||||
|
class SuspendThreadHandshake;
|
||||||
|
class ThreadSelfSuspensionHandshake;
|
||||||
|
|
||||||
// A handshake closure is a callback that is executed for a JavaThread
|
// A handshake closure is a callback that is executed for a JavaThread
|
||||||
// while it is in a safepoint/handshake-safe state. Depending on the
|
// while it is in a safepoint/handshake-safe state. Depending on the
|
||||||
|
@ -64,30 +66,46 @@ class Handshake : public AllStatic {
|
||||||
static void execute(AsyncHandshakeClosure* hs_cl, JavaThread* target);
|
static void execute(AsyncHandshakeClosure* hs_cl, JavaThread* target);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class JvmtiRawMonitor;
|
||||||
|
|
||||||
// The HandshakeState keeps track of an ongoing handshake for this JavaThread.
|
// The HandshakeState keeps track of an ongoing handshake for this JavaThread.
|
||||||
// VMThread/Handshaker and JavaThread are serialized with _lock making sure the
|
// VMThread/Handshaker and JavaThread are serialized with _lock making sure the
|
||||||
// operation is only done by either VMThread/Handshaker on behalf of the
|
// operation is only done by either VMThread/Handshaker on behalf of the
|
||||||
// JavaThread or by the target JavaThread itself.
|
// JavaThread or by the target JavaThread itself.
|
||||||
class HandshakeState {
|
class HandshakeState {
|
||||||
|
friend JvmtiRawMonitor;
|
||||||
|
friend ThreadSelfSuspensionHandshake;
|
||||||
|
friend SuspendThreadHandshake;
|
||||||
|
friend JavaThread;
|
||||||
// This a back reference to the JavaThread,
|
// This a back reference to the JavaThread,
|
||||||
// the target for all operation in the queue.
|
// the target for all operation in the queue.
|
||||||
JavaThread* _handshakee;
|
JavaThread* _handshakee;
|
||||||
// The queue containing handshake operations to be performed on _handshakee.
|
// The queue containing handshake operations to be performed on _handshakee.
|
||||||
FilterQueue<HandshakeOperation*> _queue;
|
FilterQueue<HandshakeOperation*> _queue;
|
||||||
// Provides mutual exclusion to this state and queue.
|
// Provides mutual exclusion to this state and queue. Also used for
|
||||||
Mutex _lock;
|
// JavaThread suspend/resume operations.
|
||||||
|
Monitor _lock;
|
||||||
// Set to the thread executing the handshake operation.
|
// Set to the thread executing the handshake operation.
|
||||||
Thread* _active_handshaker;
|
Thread* _active_handshaker;
|
||||||
|
|
||||||
bool claim_handshake();
|
bool claim_handshake();
|
||||||
bool possibly_can_process_handshake();
|
bool possibly_can_process_handshake();
|
||||||
bool can_process_handshake();
|
bool can_process_handshake();
|
||||||
void process_self_inner();
|
|
||||||
|
// Returns false if the JavaThread finished all its handshake operations.
|
||||||
|
// If the method returns true there is still potential work to be done,
|
||||||
|
// but we need to check for a safepoint before.
|
||||||
|
// (This is due to a suspension handshake which put the JavaThread in blocked
|
||||||
|
// state so a safepoint may be in-progress.)
|
||||||
|
bool process_self_inner();
|
||||||
|
|
||||||
bool have_non_self_executable_operation();
|
bool have_non_self_executable_operation();
|
||||||
HandshakeOperation* pop_for_self();
|
HandshakeOperation* pop_for_self();
|
||||||
HandshakeOperation* pop();
|
HandshakeOperation* pop();
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HandshakeState(JavaThread* thread);
|
HandshakeState(JavaThread* thread);
|
||||||
|
|
||||||
|
@ -107,10 +125,21 @@ class HandshakeState {
|
||||||
// while handshake operations are being executed, the _handshakee
|
// while handshake operations are being executed, the _handshakee
|
||||||
// must take slow path, process_by_self(), if _lock is held.
|
// must take slow path, process_by_self(), if _lock is held.
|
||||||
bool should_process() {
|
bool should_process() {
|
||||||
return !_queue.is_empty() || _lock.is_locked();
|
// The holder of the _lock can add an asynchronous handshake to queue.
|
||||||
|
// To make sure it is seen by the handshakee, the handshakee must first
|
||||||
|
// check the _lock, and if held go to slow path.
|
||||||
|
// Since the handshakee is unsafe if _lock gets locked after this check
|
||||||
|
// we know other threads cannot process any handshakes.
|
||||||
|
// Now we can check the queue to see if there is anything we should processs.
|
||||||
|
if (_lock.is_locked()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Lock check must be done before queue check, force ordering.
|
||||||
|
OrderAccess::loadload();
|
||||||
|
return !_queue.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_by_self();
|
bool process_by_self();
|
||||||
|
|
||||||
enum ProcessResult {
|
enum ProcessResult {
|
||||||
_no_operation = 0,
|
_no_operation = 0,
|
||||||
|
@ -123,6 +152,31 @@ class HandshakeState {
|
||||||
ProcessResult try_process(HandshakeOperation* match_op);
|
ProcessResult try_process(HandshakeOperation* match_op);
|
||||||
|
|
||||||
Thread* active_handshaker() const { return _active_handshaker; }
|
Thread* active_handshaker() const { return _active_handshaker; }
|
||||||
|
|
||||||
|
// Suspend/resume support
|
||||||
|
private:
|
||||||
|
// This flag is true when the thread owning this
|
||||||
|
// HandshakeState (the _handshakee) is suspended.
|
||||||
|
volatile bool _suspended;
|
||||||
|
// This flag is true while there is async handshake (trap)
|
||||||
|
// on queue. Since we do only need one, we can reuse it if
|
||||||
|
// thread gets suspended again (after a resume)
|
||||||
|
// and we have not yet processed it.
|
||||||
|
bool _async_suspend_handshake;
|
||||||
|
|
||||||
|
// Called from the suspend handshake.
|
||||||
|
bool suspend_with_handshake();
|
||||||
|
// Called from the async handshake (the trap)
|
||||||
|
// to stop a thread from continuing execution when suspended.
|
||||||
|
void do_self_suspend();
|
||||||
|
|
||||||
|
bool is_suspended() { return Atomic::load(&_suspended); }
|
||||||
|
void set_suspended(bool to) { return Atomic::store(&_suspended, to); }
|
||||||
|
bool has_async_suspend_handshake() { return _async_suspend_handshake; }
|
||||||
|
void set_async_suspend_handshake(bool to) { _async_suspend_handshake = to; }
|
||||||
|
|
||||||
|
bool suspend();
|
||||||
|
bool resume();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_RUNTIME_HANDSHAKE_HPP
|
#endif // SHARE_RUNTIME_HANDSHAKE_HPP
|
||||||
|
|
|
@ -81,10 +81,6 @@ void MonitorDeflationThread::monitor_deflation_thread_entry(JavaThread* jt, TRAP
|
||||||
// will be handled by safepoint correctly when this thread is
|
// will be handled by safepoint correctly when this thread is
|
||||||
// notified at a safepoint.
|
// notified at a safepoint.
|
||||||
|
|
||||||
// This ThreadBlockInVM object is not also considered to be
|
|
||||||
// suspend-equivalent because MonitorDeflationThread is not
|
|
||||||
// visible to external suspension.
|
|
||||||
|
|
||||||
ThreadBlockInVM tbivm(jt);
|
ThreadBlockInVM tbivm(jt);
|
||||||
|
|
||||||
MonitorLocker ml(MonitorDeflation_lock, Mutex::_no_safepoint_check_flag);
|
MonitorLocker ml(MonitorDeflation_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
|
|
@ -216,7 +216,7 @@ bool Monitor::wait_without_safepoint_check(int64_t timeout) {
|
||||||
return wait_status != 0; // return true IFF timeout
|
return wait_status != 0; // return true IFF timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Monitor::wait(int64_t timeout, bool as_suspend_equivalent) {
|
bool Monitor::wait(int64_t timeout) {
|
||||||
JavaThread* const self = JavaThread::current();
|
JavaThread* const self = JavaThread::current();
|
||||||
// Safepoint checking logically implies an active JavaThread.
|
// Safepoint checking logically implies an active JavaThread.
|
||||||
assert(self->is_active_Java_thread(), "invariant");
|
assert(self->is_active_Java_thread(), "invariant");
|
||||||
|
@ -239,25 +239,9 @@ bool Monitor::wait(int64_t timeout, bool as_suspend_equivalent) {
|
||||||
{
|
{
|
||||||
ThreadBlockInVM tbivmdc(self, &in_flight_mutex);
|
ThreadBlockInVM tbivmdc(self, &in_flight_mutex);
|
||||||
OSThreadWaitState osts(self->osthread(), false /* not Object.wait() */);
|
OSThreadWaitState osts(self->osthread(), false /* not Object.wait() */);
|
||||||
if (as_suspend_equivalent) {
|
|
||||||
self->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self()
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_status = _lock.wait(timeout);
|
wait_status = _lock.wait(timeout);
|
||||||
in_flight_mutex = this; // save for ~ThreadBlockInVM
|
in_flight_mutex = this; // save for ~ThreadBlockInVM
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
if (as_suspend_equivalent && self->handle_special_suspend_equivalent_condition()) {
|
|
||||||
// Our event wait has finished and we own the lock, but
|
|
||||||
// while we were waiting another thread suspended us. We don't
|
|
||||||
// want to hold the lock while suspended because that
|
|
||||||
// would surprise the thread that suspended us.
|
|
||||||
_lock.unlock();
|
|
||||||
self->java_suspend_self();
|
|
||||||
_lock.lock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_flight_mutex != NULL) {
|
if (in_flight_mutex != NULL) {
|
||||||
|
@ -276,9 +260,9 @@ Mutex::~Mutex() {
|
||||||
assert_owner(NULL);
|
assert_owner(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only Threads_lock, Heap_lock and SR_lock may be safepoint_check_sometimes.
|
// Only Threads_lock and Heap_lock may be safepoint_check_sometimes.
|
||||||
bool is_sometimes_ok(const char* name) {
|
bool is_sometimes_ok(const char* name) {
|
||||||
return (strcmp(name, "Threads_lock") == 0 || strcmp(name, "Heap_lock") == 0 || strcmp(name, "SR_lock") == 0);
|
return (strcmp(name, "Threads_lock") == 0 || strcmp(name, "Heap_lock") == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex::Mutex(int Rank, const char * name, bool allow_vm_block,
|
Mutex::Mutex(int Rank, const char * name, bool allow_vm_block,
|
||||||
|
@ -388,10 +372,9 @@ void Mutex::check_rank(Thread* thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locks with rank native or suspend_resume are an exception and are not
|
// Locks with rank native are an exception and are not
|
||||||
// subject to the verification rules.
|
// subject to the verification rules.
|
||||||
bool check_can_be_skipped = this->rank() == Mutex::native || this->rank() == Mutex::suspend_resume
|
bool check_can_be_skipped = this->rank() == Mutex::native || SafepointSynchronize::is_at_safepoint();
|
||||||
|| SafepointSynchronize::is_at_safepoint();
|
|
||||||
if (owned_by_self()) {
|
if (owned_by_self()) {
|
||||||
// wait() case
|
// wait() case
|
||||||
Mutex* least = get_least_ranked_lock_besides_this(locks_owned);
|
Mutex* least = get_least_ranked_lock_besides_this(locks_owned);
|
||||||
|
|
|
@ -67,8 +67,7 @@ class Mutex : public CHeapObj<mtSynchronizer> {
|
||||||
access = event + 1,
|
access = event + 1,
|
||||||
tty = access + 2,
|
tty = access + 2,
|
||||||
special = tty + 3,
|
special = tty + 3,
|
||||||
suspend_resume = special + 1,
|
oopstorage = special + 3,
|
||||||
oopstorage = suspend_resume + 2,
|
|
||||||
leaf = oopstorage + 2,
|
leaf = oopstorage + 2,
|
||||||
safepoint = leaf + 10,
|
safepoint = leaf + 10,
|
||||||
barrier = safepoint + 1,
|
barrier = safepoint + 1,
|
||||||
|
@ -123,7 +122,6 @@ class Mutex : public CHeapObj<mtSynchronizer> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const bool _allow_vm_block_flag = true;
|
static const bool _allow_vm_block_flag = true;
|
||||||
static const bool _as_suspend_equivalent_flag = true;
|
|
||||||
|
|
||||||
// Locks can be acquired with or without a safepoint check. NonJavaThreads do not follow
|
// Locks can be acquired with or without a safepoint check. NonJavaThreads do not follow
|
||||||
// the safepoint protocol when acquiring locks.
|
// the safepoint protocol when acquiring locks.
|
||||||
|
@ -222,10 +220,8 @@ class Monitor : public Mutex {
|
||||||
|
|
||||||
// Wait until monitor is notified (or times out).
|
// Wait until monitor is notified (or times out).
|
||||||
// Defaults are to make safepoint checks, wait time is forever (i.e.,
|
// Defaults are to make safepoint checks, wait time is forever (i.e.,
|
||||||
// zero), and not a suspend-equivalent condition. Returns true if wait
|
// zero). Returns true if wait times out; otherwise returns false.
|
||||||
// times out; otherwise returns false.
|
bool wait(int64_t timeout = 0);
|
||||||
bool wait(int64_t timeout = 0,
|
|
||||||
bool as_suspend_equivalent = !_as_suspend_equivalent_flag);
|
|
||||||
bool wait_without_safepoint_check(int64_t timeout = 0);
|
bool wait_without_safepoint_check(int64_t timeout = 0);
|
||||||
void notify();
|
void notify();
|
||||||
void notify_all();
|
void notify_all();
|
||||||
|
|
|
@ -259,10 +259,9 @@ class MonitorLocker: public MutexLocker {
|
||||||
assert(monitor != NULL, "NULL monitor not allowed");
|
assert(monitor != NULL, "NULL monitor not allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(int64_t timeout = 0,
|
bool wait(int64_t timeout = 0) {
|
||||||
bool as_suspend_equivalent = !Mutex::_as_suspend_equivalent_flag) {
|
|
||||||
if (_flag == Mutex::_safepoint_check_flag) {
|
if (_flag == Mutex::_safepoint_check_flag) {
|
||||||
return as_monitor()->wait(timeout, as_suspend_equivalent);
|
return as_monitor()->wait(timeout);
|
||||||
} else {
|
} else {
|
||||||
return as_monitor()->wait_without_safepoint_check(timeout);
|
return as_monitor()->wait_without_safepoint_check(timeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,9 +323,8 @@ void WatcherThread::stop() {
|
||||||
MonitorLocker mu(Terminator_lock);
|
MonitorLocker mu(Terminator_lock);
|
||||||
|
|
||||||
while (watcher_thread() != NULL) {
|
while (watcher_thread() != NULL) {
|
||||||
// This wait should make safepoint checks, wait without a timeout,
|
// This wait should make safepoint checks and wait without a timeout.
|
||||||
// and wait as a suspend-equivalent condition.
|
mu.wait(0);
|
||||||
mu.wait(0, Mutex::_as_suspend_equivalent_flag);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,8 +108,8 @@ void NotificationThread::notification_thread_entry(JavaThread* jt, TRAPS) {
|
||||||
(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification()) |
|
(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification()) |
|
||||||
(has_gc_notification_event = GCNotifier::has_event()))
|
(has_gc_notification_event = GCNotifier::has_event()))
|
||||||
== 0) {
|
== 0) {
|
||||||
// Wait as a suspend equalent until notified that there is some work to do.
|
// Wait until notified that there is some work to do.
|
||||||
ml.wait(0, true);
|
ml.wait(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,39 +403,49 @@ bool ObjectMonitor::enter(JavaThread* current) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OSThreadContendState osts(current->osthread());
|
OSThreadContendState osts(current->osthread());
|
||||||
ThreadBlockInVM tbivm(current);
|
|
||||||
|
|
||||||
// TODO-FIXME: change the following for(;;) loop to straight-line code.
|
assert(current->thread_state() == _thread_in_vm, "invariant");
|
||||||
|
|
||||||
|
current->frame_anchor()->make_walkable(current);
|
||||||
|
// Thread must be walkable before it is blocked.
|
||||||
|
// Read in reverse order.
|
||||||
|
OrderAccess::storestore();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
current->set_suspend_equivalent();
|
current->set_thread_state(_thread_blocked);
|
||||||
// cleared by handle_special_suspend_equivalent_condition()
|
|
||||||
// or java_suspend_self()
|
|
||||||
|
|
||||||
EnterI(current);
|
EnterI(current);
|
||||||
|
current->set_thread_state_fence(_thread_blocked_trans);
|
||||||
if (!current->handle_special_suspend_equivalent_condition()) break;
|
if (SafepointMechanism::should_process(current) &&
|
||||||
|
current->is_suspended()) {
|
||||||
// We have acquired the contended monitor, but while we were
|
// We have acquired the contended monitor, but while we were
|
||||||
// waiting another thread suspended us. We don't want to enter
|
// waiting another thread suspended us. We don't want to enter
|
||||||
// the monitor while suspended because that would surprise the
|
// the monitor while suspended because that would surprise the
|
||||||
// thread that suspended us.
|
// thread that suspended us.
|
||||||
//
|
|
||||||
_recursions = 0;
|
_recursions = 0;
|
||||||
_succ = NULL;
|
_succ = NULL;
|
||||||
|
// Don't need a full fence after clearing successor here because of the call to exit().
|
||||||
exit(current, false /* not_suspended */);
|
exit(current, false /* not_suspended */);
|
||||||
|
SafepointMechanism::process_if_requested(current);
|
||||||
current->java_suspend_self();
|
// Since we are going to _thread_blocked we skip setting _thread_in_vm here.
|
||||||
|
} else {
|
||||||
|
// Only exit path from for loop
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
current->set_current_pending_monitor(NULL);
|
current->set_current_pending_monitor(NULL);
|
||||||
|
|
||||||
// We cleared the pending monitor info since we've just gotten past
|
// We cleared the pending monitor info since we've just gotten past
|
||||||
// the enter-check-for-suspend dance and we now own the monitor free
|
// the enter-check-for-suspend dance and we now own the monitor free
|
||||||
// and clear, i.e., it is no longer pending. The ThreadBlockInVM
|
// and clear, i.e., it is no longer pending.
|
||||||
// destructor can go to a safepoint at the end of this block. If we
|
// We can go to a safepoint at the end of this block. If we
|
||||||
// do a thread dump during that safepoint, then this thread will show
|
// do a thread dump during that safepoint, then this thread will show
|
||||||
// as having "-locked" the monitor, but the OS and java.lang.Thread
|
// as having "-locked" the monitor, but the OS and java.lang.Thread
|
||||||
// states will still report that the thread is blocked trying to
|
// states will still report that the thread is blocked trying to
|
||||||
// acquire it.
|
// acquire it.
|
||||||
|
|
||||||
|
// Completed the tranisition.
|
||||||
|
SafepointMechanism::process_if_requested(current);
|
||||||
|
current->set_thread_state(_thread_in_vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_to_contentions(-1);
|
add_to_contentions(-1);
|
||||||
|
@ -954,25 +964,26 @@ void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) {
|
||||||
if (TryLock(current) > 0) break;
|
if (TryLock(current) > 0) break;
|
||||||
if (TrySpin(current) > 0) break;
|
if (TrySpin(current) > 0) break;
|
||||||
|
|
||||||
// State transition wrappers around park() ...
|
|
||||||
// ReenterI() wisely defers state transitions until
|
|
||||||
// it's clear we must park the thread.
|
|
||||||
{
|
{
|
||||||
OSThreadContendState osts(current->osthread());
|
OSThreadContendState osts(current->osthread());
|
||||||
ThreadBlockInVM tbivm(current);
|
|
||||||
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition()
|
assert(current->thread_state() == _thread_in_vm, "invariant");
|
||||||
// or java_suspend_self()
|
|
||||||
current->set_suspend_equivalent();
|
current->frame_anchor()->make_walkable(current);
|
||||||
|
// Thread must be walkable before it is blocked.
|
||||||
|
// Read in reverse order.
|
||||||
|
OrderAccess::storestore();
|
||||||
|
current->set_thread_state(_thread_blocked);
|
||||||
current->_ParkEvent->park();
|
current->_ParkEvent->park();
|
||||||
|
current->set_thread_state_fence(_thread_blocked_trans);
|
||||||
// were we externally suspended while we were waiting?
|
if (SafepointMechanism::should_process(current)) {
|
||||||
for (;;) {
|
if (_succ == current) {
|
||||||
if (!current->handle_special_suspend_equivalent_condition()) break;
|
_succ = NULL;
|
||||||
if (_succ == current) { _succ = NULL; OrderAccess::fence(); }
|
OrderAccess::fence(); // always do a full fence when successor is cleared
|
||||||
current->java_suspend_self();
|
|
||||||
current->set_suspend_equivalent();
|
|
||||||
}
|
}
|
||||||
|
SafepointMechanism::process_if_requested(current);
|
||||||
|
}
|
||||||
|
current->set_thread_state(_thread_in_vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try again, but just so we distinguish between futile wakeups and
|
// Try again, but just so we distinguish between futile wakeups and
|
||||||
|
@ -1526,11 +1537,15 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
|
||||||
{ // State transition wrappers
|
{ // State transition wrappers
|
||||||
OSThread* osthread = current->osthread();
|
OSThread* osthread = current->osthread();
|
||||||
OSThreadWaitState osts(osthread, true);
|
OSThreadWaitState osts(osthread, true);
|
||||||
{
|
|
||||||
ThreadBlockInVM tbivm(current);
|
|
||||||
// Thread is in thread_blocked state and oop access is unsafe.
|
|
||||||
current->set_suspend_equivalent();
|
|
||||||
|
|
||||||
|
assert(current->thread_state() == _thread_in_vm, "invariant");
|
||||||
|
|
||||||
|
{
|
||||||
|
current->frame_anchor()->make_walkable(current);
|
||||||
|
// Thread must be walkable before it is blocked.
|
||||||
|
// Read in reverse order.
|
||||||
|
OrderAccess::storestore();
|
||||||
|
current->set_thread_state(_thread_blocked);
|
||||||
if (interrupted || HAS_PENDING_EXCEPTION) {
|
if (interrupted || HAS_PENDING_EXCEPTION) {
|
||||||
// Intentionally empty
|
// Intentionally empty
|
||||||
} else if (node._notified == 0) {
|
} else if (node._notified == 0) {
|
||||||
|
@ -1540,14 +1555,16 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
|
||||||
ret = current->_ParkEvent->park(millis);
|
ret = current->_ParkEvent->park(millis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
current->set_thread_state_fence(_thread_blocked_trans);
|
||||||
// were we externally suspended while we were waiting?
|
if (SafepointMechanism::should_process(current)) {
|
||||||
if (current->handle_special_suspend_equivalent_condition()) {
|
if (_succ == current) {
|
||||||
// TODO-FIXME: add -- if succ == current then succ = null.
|
_succ = NULL;
|
||||||
current->java_suspend_self();
|
OrderAccess::fence(); // always do a full fence when successor is cleared
|
||||||
|
}
|
||||||
|
SafepointMechanism::process_if_requested(current);
|
||||||
|
}
|
||||||
|
current->set_thread_state(_thread_in_vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm
|
|
||||||
|
|
||||||
// Node may be on the WaitSet, the EntryList (or cxq), or in transition
|
// Node may be on the WaitSet, the EntryList (or cxq), or in transition
|
||||||
// from the WaitSet to the EntryList.
|
// from the WaitSet to the EntryList.
|
||||||
|
|
|
@ -871,8 +871,6 @@ int os::random() {
|
||||||
// locking.
|
// locking.
|
||||||
|
|
||||||
void os::start_thread(Thread* thread) {
|
void os::start_thread(Thread* thread) {
|
||||||
// guard suspend/resume
|
|
||||||
MutexLocker ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
OSThread* osthread = thread->osthread();
|
OSThread* osthread = thread->osthread();
|
||||||
osthread->set_state(RUNNABLE);
|
osthread->set_state(RUNNABLE);
|
||||||
pd_start_thread(thread);
|
pd_start_thread(thread);
|
||||||
|
|
|
@ -77,8 +77,10 @@ void SafepointMechanism::default_initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafepointMechanism::process(JavaThread *thread) {
|
void SafepointMechanism::process(JavaThread *thread) {
|
||||||
|
bool need_rechecking;
|
||||||
|
do {
|
||||||
if (global_poll()) {
|
if (global_poll()) {
|
||||||
// Any load in ::block must not pass the global poll load.
|
// Any load in ::block() must not pass the global poll load.
|
||||||
// Otherwise we might load an old safepoint counter (for example).
|
// Otherwise we might load an old safepoint counter (for example).
|
||||||
OrderAccess::loadload();
|
OrderAccess::loadload();
|
||||||
SafepointSynchronize::block(thread);
|
SafepointSynchronize::block(thread);
|
||||||
|
@ -86,15 +88,15 @@ void SafepointMechanism::process(JavaThread *thread) {
|
||||||
|
|
||||||
// The call to on_safepoint fixes the thread's oops and the first few frames.
|
// The call to on_safepoint fixes the thread's oops and the first few frames.
|
||||||
//
|
//
|
||||||
// The call has been carefully placed here to cater for a few situations:
|
// The call has been carefully placed here to cater to a few situations:
|
||||||
// 1) After we exit from block after a global poll
|
// 1) After we exit from block after a global poll
|
||||||
// 2) After a thread races with the disarming of the global poll and transitions from native/blocked
|
// 2) After a thread races with the disarming of the global poll and transitions from native/blocked
|
||||||
// 3) Before the handshake code is run
|
// 3) Before the handshake code is run
|
||||||
StackWatermarkSet::on_safepoint(thread);
|
StackWatermarkSet::on_safepoint(thread);
|
||||||
|
|
||||||
if (thread->handshake_state()->should_process()) {
|
need_rechecking = thread->handshake_state()->should_process() && thread->handshake_state()->process_by_self();
|
||||||
thread->handshake_state()->process_by_self();
|
|
||||||
}
|
} while (need_rechecking);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t SafepointMechanism::compute_poll_word(bool armed, uintptr_t stack_watermark) {
|
uintptr_t SafepointMechanism::compute_poll_word(bool armed, uintptr_t stack_watermark) {
|
||||||
|
@ -111,6 +113,8 @@ uintptr_t SafepointMechanism::compute_poll_word(bool armed, uintptr_t stack_wate
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafepointMechanism::update_poll_values(JavaThread* thread) {
|
void SafepointMechanism::update_poll_values(JavaThread* thread) {
|
||||||
|
assert(thread->thread_state() != _thread_blocked, "Must not be");
|
||||||
|
assert(thread->thread_state() != _thread_in_native, "Must not be");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool armed = global_poll() || thread->handshake_state()->has_operation();
|
bool armed = global_poll() || thread->handshake_state()->has_operation();
|
||||||
uintptr_t stack_watermark = StackWatermarkSet::lowest_watermark(thread);
|
uintptr_t stack_watermark = StackWatermarkSet::lowest_watermark(thread);
|
||||||
|
|
|
@ -273,7 +273,6 @@ void NMethodSweeper::handle_safepoint_request() {
|
||||||
MutexUnlocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexUnlocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
thread->java_suspend_self();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,8 +274,6 @@ Thread::Thread() {
|
||||||
_visited_for_critical_count = false;
|
_visited_for_critical_count = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_SR_lock = new Monitor(Mutex::suspend_resume, "SR_lock", true,
|
|
||||||
Monitor::_safepoint_check_sometimes);
|
|
||||||
_suspend_flags = 0;
|
_suspend_flags = 0;
|
||||||
|
|
||||||
// thread-specific hashCode stream generator state - Marsaglia shift-xor form
|
// thread-specific hashCode stream generator state - Marsaglia shift-xor form
|
||||||
|
@ -450,18 +448,13 @@ Thread::~Thread() {
|
||||||
delete last_handle_mark();
|
delete last_handle_mark();
|
||||||
assert(last_handle_mark() == NULL, "check we have reached the end");
|
assert(last_handle_mark() == NULL, "check we have reached the end");
|
||||||
|
|
||||||
// It's possible we can encounter a null _ParkEvent, etc., in stillborn threads.
|
ParkEvent::Release(_ParkEvent);
|
||||||
// We NULL out the fields for good hygiene.
|
// Set to NULL as a termination indicator for has_terminated().
|
||||||
ParkEvent::Release(_ParkEvent); _ParkEvent = NULL;
|
Atomic::store(&_ParkEvent, (ParkEvent*)NULL);
|
||||||
|
|
||||||
delete handle_area();
|
delete handle_area();
|
||||||
delete metadata_handles();
|
delete metadata_handles();
|
||||||
|
|
||||||
// SR_handler uses this as a termination indicator -
|
|
||||||
// needs to happen before os::free_thread()
|
|
||||||
delete _SR_lock;
|
|
||||||
_SR_lock = NULL;
|
|
||||||
|
|
||||||
// osthread() can be NULL, if creation of thread failed.
|
// osthread() can be NULL, if creation of thread failed.
|
||||||
if (osthread() != NULL) os::free_thread(osthread());
|
if (osthread() != NULL) os::free_thread(osthread());
|
||||||
|
|
||||||
|
@ -582,119 +575,6 @@ void Thread::send_async_exception(oop java_thread, oop java_throwable) {
|
||||||
Handshake::execute(&vm_stop, target);
|
Handshake::execute(&vm_stop, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check if an external suspend request has completed (or has been
|
|
||||||
// cancelled). Returns true if the thread is externally suspended and
|
|
||||||
// false otherwise.
|
|
||||||
bool JavaThread::is_ext_suspend_completed() {
|
|
||||||
bool did_trans_retry = false; // only do thread_in_native_trans retry once
|
|
||||||
bool do_trans_retry; // flag to force the retry
|
|
||||||
|
|
||||||
do {
|
|
||||||
do_trans_retry = false;
|
|
||||||
|
|
||||||
if (is_exiting()) {
|
|
||||||
// Thread is in the process of exiting. This is always checked
|
|
||||||
// first to reduce the risk of dereferencing a freed JavaThread.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_external_suspend()) {
|
|
||||||
// Suspend request is cancelled. This is always checked before
|
|
||||||
// is_ext_suspended() to reduce the risk of a rogue resume
|
|
||||||
// confusing the thread that made the suspend request.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_ext_suspended()) {
|
|
||||||
// thread is suspended
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we no longer do hard suspends of threads running
|
|
||||||
// native code, the target thread can be changing thread state
|
|
||||||
// while we are in this routine:
|
|
||||||
//
|
|
||||||
// _thread_in_native -> _thread_in_native_trans -> _thread_blocked
|
|
||||||
//
|
|
||||||
// We save a copy of the thread state as observed at this moment
|
|
||||||
// and make our decision about suspend completeness based on the
|
|
||||||
// copy. This closes the race where the thread state is seen as
|
|
||||||
// _thread_in_native_trans in the if-thread_blocked check, but is
|
|
||||||
// seen as _thread_blocked in if-thread_in_native_trans check.
|
|
||||||
JavaThreadState save_state = thread_state();
|
|
||||||
|
|
||||||
if (save_state == _thread_blocked && is_suspend_equivalent()) {
|
|
||||||
// If the thread's state is _thread_blocked and this blocking
|
|
||||||
// condition is known to be equivalent to a suspend, then we can
|
|
||||||
// consider the thread to be externally suspended. This means that
|
|
||||||
// the code that sets _thread_blocked has been modified to do
|
|
||||||
// self-suspension if the blocking condition releases. We also
|
|
||||||
// used to check for CONDVAR_WAIT here, but that is now covered by
|
|
||||||
// the _thread_blocked with self-suspension check.
|
|
||||||
//
|
|
||||||
// Return true since we wouldn't be here unless there was still an
|
|
||||||
// external suspend request.
|
|
||||||
return true;
|
|
||||||
} else if (save_state == _thread_in_native && frame_anchor()->walkable()) {
|
|
||||||
// Threads running native code will self-suspend on native==>VM/Java
|
|
||||||
// transitions. If its stack is walkable (should always be the case
|
|
||||||
// unless this function is called before the actual java_suspend()
|
|
||||||
// call), then the wait is done.
|
|
||||||
return true;
|
|
||||||
} else if (!did_trans_retry &&
|
|
||||||
save_state == _thread_in_native_trans &&
|
|
||||||
frame_anchor()->walkable()) {
|
|
||||||
// The thread is transitioning from thread_in_native to another
|
|
||||||
// thread state. check_safepoint_and_suspend_for_native_trans()
|
|
||||||
// will force the thread to self-suspend. If it hasn't gotten
|
|
||||||
// there yet we may have caught the thread in-between the native
|
|
||||||
// code check above and the self-suspend.
|
|
||||||
//
|
|
||||||
// Since we use the saved thread state in the if-statement above,
|
|
||||||
// there is a chance that the thread has already transitioned to
|
|
||||||
// _thread_blocked by the time we get here. In that case, we will
|
|
||||||
// make a single unnecessary pass through the logic below. This
|
|
||||||
// doesn't hurt anything since we still do the trans retry.
|
|
||||||
|
|
||||||
// Once the thread leaves thread_in_native_trans for another
|
|
||||||
// thread state, we break out of this retry loop. We shouldn't
|
|
||||||
// need this flag to prevent us from getting back here, but
|
|
||||||
// sometimes paranoia is good.
|
|
||||||
did_trans_retry = true;
|
|
||||||
|
|
||||||
// We wait for the thread to transition to a more usable state.
|
|
||||||
for (int i = 1; i <= SuspendRetryCount; i++) {
|
|
||||||
// We used to do an "os::yield_all(i)" call here with the intention
|
|
||||||
// that yielding would increase on each retry. However, the parameter
|
|
||||||
// is ignored on Linux which means the yield didn't scale up. Waiting
|
|
||||||
// on the SR_lock below provides a much more predictable scale up for
|
|
||||||
// the delay. It also provides a simple/direct point to check for any
|
|
||||||
// safepoint requests from the VMThread
|
|
||||||
|
|
||||||
// temporarily drops SR_lock while doing wait with safepoint check
|
|
||||||
// (if we're a JavaThread - the WatcherThread can also call this)
|
|
||||||
// and increase delay with each retry
|
|
||||||
if (Thread::current()->is_Java_thread()) {
|
|
||||||
SR_lock()->wait(i * SuspendRetryDelay);
|
|
||||||
} else {
|
|
||||||
SR_lock()->wait_without_safepoint_check(i * SuspendRetryDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the actual thread state instead of what we saved above
|
|
||||||
if (thread_state() != _thread_in_native_trans) {
|
|
||||||
// the thread has transitioned to another thread state so
|
|
||||||
// try all the checks (except this one) one more time.
|
|
||||||
do_trans_retry = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // end retry loop
|
|
||||||
}
|
|
||||||
} while (do_trans_retry);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GC Support
|
// GC Support
|
||||||
bool Thread::claim_par_threads_do(uintx claim_token) {
|
bool Thread::claim_par_threads_do(uintx claim_token) {
|
||||||
uintx token = _threads_do_token;
|
uintx token = _threads_do_token;
|
||||||
|
@ -1189,7 +1069,6 @@ JavaThread::JavaThread() :
|
||||||
_saved_exception_pc(nullptr),
|
_saved_exception_pc(nullptr),
|
||||||
|
|
||||||
_terminated(_not_terminated),
|
_terminated(_not_terminated),
|
||||||
_suspend_equivalent(false),
|
|
||||||
_in_deopt_handler(0),
|
_in_deopt_handler(0),
|
||||||
_doing_unsafe_access(false),
|
_doing_unsafe_access(false),
|
||||||
_do_not_unlock_if_synchronized(false),
|
_do_not_unlock_if_synchronized(false),
|
||||||
|
@ -1237,7 +1116,6 @@ JavaThread::JavaThread() :
|
||||||
|
|
||||||
_SleepEvent(ParkEvent::Allocate(this))
|
_SleepEvent(ParkEvent::Allocate(this))
|
||||||
{
|
{
|
||||||
|
|
||||||
set_jni_functions(jni_functions());
|
set_jni_functions(jni_functions());
|
||||||
|
|
||||||
#if INCLUDE_JVMCI
|
#if INCLUDE_JVMCI
|
||||||
|
@ -1563,33 +1441,12 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
|
||||||
JvmtiExport::post_thread_end(this);
|
JvmtiExport::post_thread_end(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have notified the agents that we are exiting, before we go on,
|
// The careful dance between thread suspension and exit is handled here.
|
||||||
// we must check for a pending external suspend request and honor it
|
// Since we are in thread_in_vm state and suspension is done with handshakes,
|
||||||
// in order to not surprise the thread that made the suspend request.
|
// we can just put in the exiting state and it will be correctly handled.
|
||||||
while (true) {
|
|
||||||
{
|
|
||||||
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
if (!is_external_suspend()) {
|
|
||||||
set_terminated(_thread_exiting);
|
set_terminated(_thread_exiting);
|
||||||
|
|
||||||
ThreadService::current_thread_exiting(this, is_daemon(threadObj()));
|
ThreadService::current_thread_exiting(this, is_daemon(threadObj()));
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Implied else:
|
|
||||||
// Things get a little tricky here. We have a pending external
|
|
||||||
// suspend request, but we are holding the SR_lock so we
|
|
||||||
// can't just self-suspend. So we temporarily drop the lock
|
|
||||||
// and then self-suspend.
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadBlockInVM tbivm(this);
|
|
||||||
java_suspend_self();
|
|
||||||
|
|
||||||
// We're done with this suspend request, but we have to loop around
|
|
||||||
// and check again. Eventually we will get SR_lock without a pending
|
|
||||||
// external suspend request and will be able to mark ourselves as
|
|
||||||
// exiting.
|
|
||||||
}
|
|
||||||
// no more external suspends are allowed at this point
|
|
||||||
} else {
|
} else {
|
||||||
assert(!is_terminated() && !is_exiting(), "must not be exiting");
|
assert(!is_terminated() && !is_exiting(), "must not be exiting");
|
||||||
// before_exit() has already posted JVMTI THREAD_END events
|
// before_exit() has already posted JVMTI THREAD_END events
|
||||||
|
@ -1863,12 +1720,6 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) {
|
||||||
|
|
||||||
void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
|
void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
|
||||||
|
|
||||||
// Check for pending external suspend.
|
|
||||||
if (is_external_suspend_with_lock()) {
|
|
||||||
frame_anchor()->make_walkable(this);
|
|
||||||
java_suspend_self_with_safepoint_check();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_obj_deopt_suspend()) {
|
if (is_obj_deopt_suspend()) {
|
||||||
frame_anchor()->make_walkable(this);
|
frame_anchor()->make_walkable(this);
|
||||||
wait_for_object_deoptimization();
|
wait_for_object_deoptimization();
|
||||||
|
@ -1930,164 +1781,42 @@ void JavaThread::send_thread_stop(oop java_throwable) {
|
||||||
this->interrupt();
|
this->interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// External suspension mechanism.
|
// External suspension mechanism.
|
||||||
//
|
//
|
||||||
// Tell the VM to suspend a thread when ever it knows that it does not hold on
|
// Guarantees on return (for a valid target thread):
|
||||||
// to any VM_locks and it is at a transition
|
// - Target thread will not execute any new bytecode.
|
||||||
// Self-suspension will happen on the transition out of the vm.
|
// - Target thread will not enter any new monitors.
|
||||||
// Catch "this" coming in from JNIEnv pointers when the thread has been freed
|
|
||||||
//
|
//
|
||||||
// Guarantees on return:
|
bool JavaThread::java_suspend() {
|
||||||
// + Target thread will not execute any new bytecode (that's why we need to
|
|
||||||
// force a safepoint)
|
|
||||||
// + Target thread will not enter any new monitors
|
|
||||||
//
|
|
||||||
void JavaThread::java_suspend() {
|
|
||||||
ThreadsListHandle tlh;
|
ThreadsListHandle tlh;
|
||||||
if (!tlh.includes(this) || threadObj() == NULL || is_exiting()) {
|
if (!tlh.includes(this)) {
|
||||||
return;
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " not on ThreadsList, no suspension", p2i(this));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this->handshake_state()->suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
{ MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
bool JavaThread::java_resume() {
|
||||||
if (!is_external_suspend()) {
|
ThreadsListHandle tlh;
|
||||||
// a racing resume has cancelled us; bail out now
|
if (!tlh.includes(this)) {
|
||||||
return;
|
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " not on ThreadsList, nothing to resume", p2i(this));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return this->handshake_state()->resume();
|
||||||
// suspend is done
|
|
||||||
|
|
||||||
// Warning: is_ext_suspend_completed() may temporarily drop the
|
|
||||||
// SR_lock to allow the thread to reach a stable thread state if
|
|
||||||
// it is currently in a transient thread state.
|
|
||||||
if (is_ext_suspend_completed()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Thread::current() == this) {
|
|
||||||
// Safely self-suspend.
|
|
||||||
// If we don't do this explicitly it will implicitly happen
|
|
||||||
// before we transition back to Java, and on some other thread-state
|
|
||||||
// transition paths, but not as we exit a JVM TI SuspendThread call.
|
|
||||||
// As SuspendThread(current) must not return (until resumed) we must
|
|
||||||
// self-suspend here.
|
|
||||||
ThreadBlockInVM tbivm(this);
|
|
||||||
java_suspend_self();
|
|
||||||
} else {
|
|
||||||
VM_ThreadSuspend vm_suspend;
|
|
||||||
VMThread::execute(&vm_suspend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Part II of external suspension.
|
|
||||||
// A JavaThread self suspends when it detects a pending external suspend
|
|
||||||
// request. This is usually on transitions. It is also done in places
|
|
||||||
// where continuing to the next transition would surprise the caller,
|
|
||||||
// e.g., monitor entry.
|
|
||||||
//
|
|
||||||
// Returns the number of times that the thread self-suspended.
|
|
||||||
//
|
|
||||||
// Note: DO NOT call java_suspend_self() when you just want to block current
|
|
||||||
// thread. java_suspend_self() is the second stage of cooperative
|
|
||||||
// suspension for external suspend requests and should only be used
|
|
||||||
// to complete an external suspend request.
|
|
||||||
//
|
|
||||||
int JavaThread::java_suspend_self() {
|
|
||||||
assert(thread_state() == _thread_blocked, "wrong state for java_suspend_self()");
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
// we are in the process of exiting so don't suspend
|
|
||||||
if (is_exiting()) {
|
|
||||||
clear_external_suspend();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(_anchor.walkable() || !has_last_Java_frame(),
|
|
||||||
"must have walkable stack");
|
|
||||||
|
|
||||||
MonitorLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
|
|
||||||
assert(!this->is_ext_suspended(),
|
|
||||||
"a thread trying to self-suspend should not already be suspended");
|
|
||||||
|
|
||||||
if (this->is_suspend_equivalent()) {
|
|
||||||
// If we are self-suspending as a result of the lifting of a
|
|
||||||
// suspend equivalent condition, then the suspend_equivalent
|
|
||||||
// flag is not cleared until we set the ext_suspended flag.
|
|
||||||
this->clear_suspend_equivalent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// A racing resume may have cancelled us before we grabbed SR_lock
|
|
||||||
// above. Or another external suspend request could be waiting for us
|
|
||||||
// by the time we return from SR_lock()->wait(). The thread
|
|
||||||
// that requested the suspension may already be trying to walk our
|
|
||||||
// stack and if we return now, we can change the stack out from under
|
|
||||||
// it. This would be a "bad thing (TM)" and cause the stack walker
|
|
||||||
// to crash. We stay self-suspended until there are no more pending
|
|
||||||
// external suspend requests.
|
|
||||||
while (is_external_suspend()) {
|
|
||||||
ret++;
|
|
||||||
this->set_ext_suspended();
|
|
||||||
|
|
||||||
// _ext_suspended flag is cleared by java_resume()
|
|
||||||
while (is_ext_suspended()) {
|
|
||||||
ml.wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper routine to set up the correct thread state before calling java_suspend_self.
|
|
||||||
// This is called when regular thread-state transition helpers can't be used because
|
|
||||||
// we can be in various states, in particular _thread_in_native_trans.
|
|
||||||
// We have to set the thread state directly to _thread_blocked so that it will
|
|
||||||
// be seen to be safepoint/handshake safe whilst suspended. This is also
|
|
||||||
// necessary to allow a thread in is_ext_suspend_completed, that observed the
|
|
||||||
// _thread_in_native_trans state, to proceed.
|
|
||||||
// The problem with setting thread state directly is that a
|
|
||||||
// safepoint could happen just after java_suspend_self() returns after being resumed,
|
|
||||||
// and the VM thread will see the _thread_blocked state. So we must check for a safepoint
|
|
||||||
// after restoring the state to make sure we won't leave while a safepoint is in progress.
|
|
||||||
// However, not all initial-states are allowed when performing a safepoint check, as we
|
|
||||||
// should never be blocking at a safepoint whilst in those states(*). Of these 'bad' states
|
|
||||||
// only _thread_in_native is possible when executing this code (based on our two callers).
|
|
||||||
// A thread that is _thread_in_native is already safepoint-safe and so it doesn't matter
|
|
||||||
// whether the VMThread sees the _thread_blocked state, or the _thread_in_native state,
|
|
||||||
// and so we don't need the explicit safepoint check.
|
|
||||||
// (*) See switch statement in SafepointSynchronize::block() for thread states that are
|
|
||||||
// allowed when performing a safepoint check.
|
|
||||||
|
|
||||||
void JavaThread::java_suspend_self_with_safepoint_check() {
|
|
||||||
assert(this == Thread::current(), "invariant");
|
|
||||||
JavaThreadState state = thread_state();
|
|
||||||
|
|
||||||
do {
|
|
||||||
set_thread_state(_thread_blocked);
|
|
||||||
java_suspend_self();
|
|
||||||
// The current thread could have been suspended again. We have to check for
|
|
||||||
// suspend after restoring the saved state. Without this the current thread
|
|
||||||
// might return to _thread_in_Java and execute bytecodes for an arbitrary
|
|
||||||
// long time.
|
|
||||||
set_thread_state_fence(state);
|
|
||||||
|
|
||||||
if (state != _thread_in_native) {
|
|
||||||
SafepointMechanism::process_if_requested(this);
|
|
||||||
}
|
|
||||||
} while (is_external_suspend());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for another thread to perform object reallocation and relocking on behalf of
|
// Wait for another thread to perform object reallocation and relocking on behalf of
|
||||||
// this thread.
|
// this thread.
|
||||||
// This method is very similar to JavaThread::java_suspend_self_with_safepoint_check()
|
// Raw thread state transition to _thread_blocked and back again to the original
|
||||||
// and has the same callers. It also performs a raw thread state transition to
|
// state before returning are performed. The current thread is required to
|
||||||
// _thread_blocked and back again to the original state before returning. The current
|
// change to _thread_blocked in order to be seen to be safepoint/handshake safe
|
||||||
// thread is required to change to _thread_blocked in order to be seen to be
|
// whilst suspended and only after becoming handshake safe, the other thread can
|
||||||
// safepoint/handshake safe whilst suspended and only after becoming handshake safe,
|
// complete the handshake used to synchronize with this thread and then perform
|
||||||
// the other thread can complete the handshake used to synchronize with this thread
|
// the reallocation and relocking. We cannot use the thread state transition
|
||||||
// and then perform the reallocation and relocking. We cannot use the thread state
|
// helpers because we arrive here in various states and also because the helpers
|
||||||
// transition helpers because we arrive here in various states and also because the
|
// indirectly call this method. After leaving _thread_blocked we have to check
|
||||||
// helpers indirectly call this method. After leaving _thread_blocked we have to
|
// for safepoint/handshake, except if _thread_in_native. The thread is safe
|
||||||
// check for safepoint/handshake, except if _thread_in_native. The thread is safe
|
|
||||||
// without blocking then. Allowed states are enumerated in
|
// without blocking then. Allowed states are enumerated in
|
||||||
// SafepointSynchronize::block(). See also EscapeBarrier::sync_and_suspend_*()
|
// SafepointSynchronize::block(). See also EscapeBarrier::sync_and_suspend_*()
|
||||||
|
|
||||||
|
@ -2099,10 +1828,6 @@ void JavaThread::wait_for_object_deoptimization() {
|
||||||
bool spin_wait = os::is_MP();
|
bool spin_wait = os::is_MP();
|
||||||
do {
|
do {
|
||||||
set_thread_state(_thread_blocked);
|
set_thread_state(_thread_blocked);
|
||||||
// Check if _external_suspend was set in the previous loop iteration.
|
|
||||||
if (is_external_suspend()) {
|
|
||||||
java_suspend_self();
|
|
||||||
}
|
|
||||||
// Wait for object deoptimization if requested.
|
// Wait for object deoptimization if requested.
|
||||||
if (spin_wait) {
|
if (spin_wait) {
|
||||||
// A single deoptimization is typically very short. Microbenchmarks
|
// A single deoptimization is typically very short. Microbenchmarks
|
||||||
|
@ -2130,7 +1855,7 @@ void JavaThread::wait_for_object_deoptimization() {
|
||||||
}
|
}
|
||||||
// A handshake for obj. deoptimization suspend could have been processed so
|
// A handshake for obj. deoptimization suspend could have been processed so
|
||||||
// we must check after processing.
|
// we must check after processing.
|
||||||
} while (is_obj_deopt_suspend() || is_external_suspend());
|
} while (is_obj_deopt_suspend());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
|
@ -2183,29 +1908,6 @@ void JavaThread::check_special_condition_for_native_trans(JavaThread *thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to guarantee the Threads_lock here, since resumes are not
|
|
||||||
// allowed during safepoint synchronization
|
|
||||||
// Can only resume from an external suspension
|
|
||||||
void JavaThread::java_resume() {
|
|
||||||
assert_locked_or_safepoint(Threads_lock);
|
|
||||||
|
|
||||||
// Sanity check: thread is gone, has started exiting or the thread
|
|
||||||
// was not externally suspended.
|
|
||||||
ThreadsListHandle tlh;
|
|
||||||
if (!tlh.includes(this) || is_exiting() || !is_external_suspend()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
|
|
||||||
clear_external_suspend();
|
|
||||||
|
|
||||||
if (is_ext_suspended()) {
|
|
||||||
clear_ext_suspended();
|
|
||||||
SR_lock()->notify_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
// Deoptimization
|
// Deoptimization
|
||||||
// Function for testing deoptimization
|
// Function for testing deoptimization
|
||||||
|
@ -2774,15 +2476,7 @@ bool JavaThread::sleep(jlong millis) {
|
||||||
{
|
{
|
||||||
ThreadBlockInVM tbivm(this);
|
ThreadBlockInVM tbivm(this);
|
||||||
OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */);
|
OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */);
|
||||||
|
|
||||||
this->set_suspend_equivalent();
|
|
||||||
// cleared by handle_special_suspend_equivalent_condition() or
|
|
||||||
// java_suspend_self() via check_and_wait_while_suspended()
|
|
||||||
|
|
||||||
slp->park(millis);
|
slp->park(millis);
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
this->check_and_wait_while_suspended();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update elapsed time tracking
|
// Update elapsed time tracking
|
||||||
|
@ -3706,11 +3400,11 @@ void Threads::destroy_vm() {
|
||||||
_vm_complete = false;
|
_vm_complete = false;
|
||||||
#endif
|
#endif
|
||||||
// Wait until we are the last non-daemon thread to execute
|
// Wait until we are the last non-daemon thread to execute
|
||||||
{ MonitorLocker nu(Threads_lock);
|
{
|
||||||
|
MonitorLocker nu(Threads_lock);
|
||||||
while (Threads::number_of_non_daemon_threads() > 1)
|
while (Threads::number_of_non_daemon_threads() > 1)
|
||||||
// This wait should make safepoint checks, wait without a timeout,
|
// This wait should make safepoint checks, wait without a timeout.
|
||||||
// and wait as a suspend-equivalent condition.
|
nu.wait(0);
|
||||||
nu.wait(0, Mutex::_as_suspend_equivalent_flag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventShutdown e;
|
EventShutdown e;
|
||||||
|
@ -3879,7 +3573,7 @@ void Threads::remove(JavaThread* p, bool is_daemon) {
|
||||||
// the thread might mess around with locks after this point. This can cause it
|
// the thread might mess around with locks after this point. This can cause it
|
||||||
// to do callbacks into the safepoint code. However, the safepoint code is not aware
|
// to do callbacks into the safepoint code. However, the safepoint code is not aware
|
||||||
// of this thread since it is removed from the queue.
|
// of this thread since it is removed from the queue.
|
||||||
p->set_terminated_value();
|
p->set_terminated(JavaThread::_thread_terminated);
|
||||||
|
|
||||||
// Notify threads waiting in EscapeBarriers
|
// Notify threads waiting in EscapeBarriers
|
||||||
EscapeBarrier::thread_removed(p);
|
EscapeBarrier::thread_removed(p);
|
||||||
|
|
|
@ -214,80 +214,11 @@ class Thread: public ThreadShadow {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void* allocate(size_t size, bool throw_excpt, MEMFLAGS flags = mtThread);
|
static void* allocate(size_t size, bool throw_excpt, MEMFLAGS flags = mtThread);
|
||||||
private:
|
|
||||||
|
|
||||||
// ***************************************************************
|
|
||||||
// Suspend and resume support
|
|
||||||
// ***************************************************************
|
|
||||||
//
|
|
||||||
// VM suspend/resume no longer exists - it was once used for various
|
|
||||||
// things including safepoints but was deprecated and finally removed
|
|
||||||
// in Java 7. Because VM suspension was considered "internal" Java-level
|
|
||||||
// suspension was considered "external", and this legacy naming scheme
|
|
||||||
// remains.
|
|
||||||
//
|
|
||||||
// External suspend/resume requests come from JVM_SuspendThread,
|
|
||||||
// JVM_ResumeThread, JVMTI SuspendThread, and finally JVMTI
|
|
||||||
// ResumeThread. External
|
|
||||||
// suspend requests cause _external_suspend to be set and external
|
|
||||||
// resume requests cause _external_suspend to be cleared.
|
|
||||||
// External suspend requests do not nest on top of other external
|
|
||||||
// suspend requests. The higher level APIs reject suspend requests
|
|
||||||
// for already suspended threads.
|
|
||||||
//
|
|
||||||
// The external_suspend
|
|
||||||
// flag is checked by has_special_runtime_exit_condition() and java thread
|
|
||||||
// will self-suspend when handle_special_runtime_exit_condition() is
|
|
||||||
// called. Most uses of the _thread_blocked state in JavaThreads are
|
|
||||||
// considered the same as being externally suspended; if the blocking
|
|
||||||
// condition lifts, the JavaThread will self-suspend. Other places
|
|
||||||
// where VM checks for external_suspend include:
|
|
||||||
// + mutex granting (do not enter monitors when thread is suspended)
|
|
||||||
// + state transitions from _thread_in_native
|
|
||||||
//
|
|
||||||
// In general, java_suspend() does not wait for an external suspend
|
|
||||||
// request to complete. When it returns, the only guarantee is that
|
|
||||||
// the _external_suspend field is true.
|
|
||||||
//
|
|
||||||
// wait_for_ext_suspend_completion() is used to wait for an external
|
|
||||||
// suspend request to complete. External suspend requests are usually
|
|
||||||
// followed by some other interface call that requires the thread to
|
|
||||||
// be quiescent, e.g., GetCallTrace(). By moving the "wait time" into
|
|
||||||
// the interface that requires quiescence, we give the JavaThread a
|
|
||||||
// chance to self-suspend before we need it to be quiescent. This
|
|
||||||
// improves overall suspend/query performance.
|
|
||||||
//
|
|
||||||
// _suspend_flags controls the behavior of java_ suspend/resume.
|
|
||||||
// It must be set under the protection of SR_lock. Read from the flag is
|
|
||||||
// OK without SR_lock as long as the value is only used as a hint.
|
|
||||||
// (e.g., check _external_suspend first without lock and then recheck
|
|
||||||
// inside SR_lock and finish the suspension)
|
|
||||||
//
|
|
||||||
// _suspend_flags is also overloaded for other "special conditions" so
|
|
||||||
// that a single check indicates whether any special action is needed
|
|
||||||
// eg. for async exceptions.
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
// Notes:
|
|
||||||
// 1. The suspend/resume logic no longer uses ThreadState in OSThread
|
|
||||||
// but we still update its value to keep other part of the system (mainly
|
|
||||||
// JVMTI) happy. ThreadState is legacy code (see notes in
|
|
||||||
// osThread.hpp).
|
|
||||||
//
|
|
||||||
// 2. It would be more natural if set_external_suspend() is private and
|
|
||||||
// part of java_suspend(), but that probably would affect the suspend/query
|
|
||||||
// performance. Need more investigation on this.
|
|
||||||
|
|
||||||
// suspend/resume lock: used for self-suspend
|
|
||||||
Monitor* _SR_lock;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum SuspendFlags {
|
enum SuspendFlags {
|
||||||
// NOTE: avoid using the sign-bit as cc generates different test code
|
// NOTE: avoid using the sign-bit as cc generates different test code
|
||||||
// when the sign-bit is used, and sometimes incorrectly - see CR 6398077
|
// when the sign-bit is used, and sometimes incorrectly - see CR 6398077
|
||||||
|
|
||||||
_external_suspend = 0x20000000U, // thread is asked to self suspend
|
|
||||||
_ext_suspended = 0x40000000U, // thread has self-suspended
|
|
||||||
|
|
||||||
_has_async_exception = 0x00000001U, // there is a pending async exception
|
_has_async_exception = 0x00000001U, // there is a pending async exception
|
||||||
|
|
||||||
_trace_flag = 0x00000004U, // call tracing backend
|
_trace_flag = 0x00000004U, // call tracing backend
|
||||||
|
@ -513,8 +444,6 @@ class Thread: public ThreadShadow {
|
||||||
os::set_native_thread_name(name);
|
os::set_native_thread_name(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor* SR_lock() const { return _SR_lock; }
|
|
||||||
|
|
||||||
bool has_async_exception() const { return (_suspend_flags & _has_async_exception) != 0; }
|
bool has_async_exception() const { return (_suspend_flags & _has_async_exception) != 0; }
|
||||||
|
|
||||||
inline void set_suspend_flag(SuspendFlags f);
|
inline void set_suspend_flag(SuspendFlags f);
|
||||||
|
@ -810,9 +739,13 @@ protected:
|
||||||
public:
|
public:
|
||||||
volatile intptr_t _Stalled;
|
volatile intptr_t _Stalled;
|
||||||
volatile int _TypeTag;
|
volatile int _TypeTag;
|
||||||
ParkEvent * _ParkEvent; // for Object monitors, JVMTI raw monitors,
|
ParkEvent * volatile _ParkEvent; // for Object monitors, JVMTI raw monitors,
|
||||||
// and ObjectSynchronizer::read_stable_mark
|
// and ObjectSynchronizer::read_stable_mark
|
||||||
int NativeSyncRecursion; // diagnostic
|
|
||||||
|
// Termination indicator used by the signal handler.
|
||||||
|
// _ParkEvent is just a convenient field we can NULL out after setting the JavaThread termination state
|
||||||
|
// (which can't itself be read from the signal handler if a signal hits during the Thread destructor).
|
||||||
|
bool has_terminated() { return Atomic::load(&_ParkEvent) == NULL; };
|
||||||
|
|
||||||
volatile int _OnTrap; // Resume-at IP delta
|
volatile int _OnTrap; // Resume-at IP delta
|
||||||
jint _hashStateW; // Marsaglia Shift-XOR thread-local RNG
|
jint _hashStateW; // Marsaglia Shift-XOR thread-local RNG
|
||||||
|
@ -869,6 +802,7 @@ class JavaThread: public Thread {
|
||||||
friend class JVMCIVMStructs;
|
friend class JVMCIVMStructs;
|
||||||
friend class WhiteBox;
|
friend class WhiteBox;
|
||||||
friend class ThreadsSMRSupport; // to access _threadObj for exiting_threads_oops_do
|
friend class ThreadsSMRSupport; // to access _threadObj for exiting_threads_oops_do
|
||||||
|
friend class HandshakeState;
|
||||||
private:
|
private:
|
||||||
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
|
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
|
||||||
OopHandle _threadObj; // The Java level thread object
|
OopHandle _threadObj; // The Java level thread object
|
||||||
|
@ -953,6 +887,7 @@ class JavaThread: public Thread {
|
||||||
NOT_PRODUCT(bool _requires_cross_modify_fence;) // State used by VerifyCrossModifyFence
|
NOT_PRODUCT(bool _requires_cross_modify_fence;) // State used by VerifyCrossModifyFence
|
||||||
|
|
||||||
// JavaThread termination support
|
// JavaThread termination support
|
||||||
|
public:
|
||||||
enum TerminatedTypes {
|
enum TerminatedTypes {
|
||||||
_not_terminated = 0xDEAD - 2,
|
_not_terminated = 0xDEAD - 2,
|
||||||
_thread_exiting, // JavaThread::exit() has been called for this thread
|
_thread_exiting, // JavaThread::exit() has been called for this thread
|
||||||
|
@ -961,6 +896,7 @@ class JavaThread: public Thread {
|
||||||
// only VM_Exit can set _vm_exited
|
// only VM_Exit can set _vm_exited
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
// In general a JavaThread's _terminated field transitions as follows:
|
// In general a JavaThread's _terminated field transitions as follows:
|
||||||
//
|
//
|
||||||
// _not_terminated => _thread_exiting => _thread_terminated
|
// _not_terminated => _thread_exiting => _thread_terminated
|
||||||
|
@ -968,8 +904,7 @@ class JavaThread: public Thread {
|
||||||
// _vm_exited is a special value to cover the case of a JavaThread
|
// _vm_exited is a special value to cover the case of a JavaThread
|
||||||
// executing native code after the VM itself is terminated.
|
// executing native code after the VM itself is terminated.
|
||||||
volatile TerminatedTypes _terminated;
|
volatile TerminatedTypes _terminated;
|
||||||
// suspend/resume support
|
|
||||||
volatile bool _suspend_equivalent; // Suspend equivalent condition
|
|
||||||
jint _in_deopt_handler; // count of deoptimization
|
jint _in_deopt_handler; // count of deoptimization
|
||||||
// handlers thread is in
|
// handlers thread is in
|
||||||
volatile bool _doing_unsafe_access; // Thread may fault due to unsafe access
|
volatile bool _doing_unsafe_access; // Thread may fault due to unsafe access
|
||||||
|
@ -1180,8 +1115,7 @@ class JavaThread: public Thread {
|
||||||
}
|
}
|
||||||
bool is_terminated() const;
|
bool is_terminated() const;
|
||||||
void set_terminated(TerminatedTypes t);
|
void set_terminated(TerminatedTypes t);
|
||||||
// special for Threads::remove() which is static:
|
|
||||||
void set_terminated_value();
|
|
||||||
void block_if_vm_exited();
|
void block_if_vm_exited();
|
||||||
|
|
||||||
bool doing_unsafe_access() { return _doing_unsafe_access; }
|
bool doing_unsafe_access() { return _doing_unsafe_access; }
|
||||||
|
@ -1207,98 +1141,24 @@ class JavaThread: public Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suspend/resume support for JavaThread
|
// Suspend/resume support for JavaThread
|
||||||
private:
|
bool java_suspend(); // higher-level suspension logic called by the public APIs
|
||||||
inline void set_ext_suspended();
|
bool java_resume(); // higher-level resume logic called by the public APIs
|
||||||
inline void clear_ext_suspended();
|
bool is_suspended() { return _handshake.is_suspended(); }
|
||||||
|
|
||||||
public:
|
static void check_safepoint_and_suspend_for_native_trans(JavaThread *thread);
|
||||||
void java_suspend(); // higher-level suspension logic called by the public APIs
|
// Check for async exception in addition to safepoint.
|
||||||
void java_resume(); // higher-level resume logic called by the public APIs
|
static void check_special_condition_for_native_trans(JavaThread *thread);
|
||||||
int java_suspend_self(); // low-level self-suspension mechanics
|
|
||||||
|
// Whenever a thread transitions from native to vm/java it must suspend
|
||||||
|
// if deopt suspend is present.
|
||||||
|
bool is_suspend_after_native() const {
|
||||||
|
return (_suspend_flags & (_obj_deopt JFR_ONLY(| _trace_flag))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Synchronize with another thread that is deoptimizing objects of the
|
// Synchronize with another thread that is deoptimizing objects of the
|
||||||
// current thread, i.e. reverts optimizations based on escape analysis.
|
// current thread, i.e. reverts optimizations based on escape analysis.
|
||||||
void wait_for_object_deoptimization();
|
void wait_for_object_deoptimization();
|
||||||
|
|
||||||
private:
|
|
||||||
// mid-level wrapper around java_suspend_self to set up correct state and
|
|
||||||
// check for a pending safepoint at the end
|
|
||||||
void java_suspend_self_with_safepoint_check();
|
|
||||||
|
|
||||||
public:
|
|
||||||
void check_and_wait_while_suspended() {
|
|
||||||
assert(JavaThread::current() == this, "sanity check");
|
|
||||||
|
|
||||||
bool do_self_suspend;
|
|
||||||
do {
|
|
||||||
// were we externally suspended while we were waiting?
|
|
||||||
do_self_suspend = handle_special_suspend_equivalent_condition();
|
|
||||||
if (do_self_suspend) {
|
|
||||||
// don't surprise the thread that suspended us by returning
|
|
||||||
java_suspend_self();
|
|
||||||
set_suspend_equivalent();
|
|
||||||
}
|
|
||||||
} while (do_self_suspend);
|
|
||||||
}
|
|
||||||
static void check_safepoint_and_suspend_for_native_trans(JavaThread *thread);
|
|
||||||
// Check for async exception in addition to safepoint and suspend request.
|
|
||||||
static void check_special_condition_for_native_trans(JavaThread *thread);
|
|
||||||
|
|
||||||
bool is_ext_suspend_completed();
|
|
||||||
|
|
||||||
inline void set_external_suspend();
|
|
||||||
inline void clear_external_suspend();
|
|
||||||
|
|
||||||
bool is_external_suspend() const {
|
|
||||||
return (_suspend_flags & _external_suspend) != 0;
|
|
||||||
}
|
|
||||||
// Whenever a thread transitions from native to vm/java it must suspend
|
|
||||||
// if external|deopt suspend is present.
|
|
||||||
bool is_suspend_after_native() const {
|
|
||||||
return (_suspend_flags & (_external_suspend | _obj_deopt JFR_ONLY(| _trace_flag))) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// external suspend request is completed
|
|
||||||
bool is_ext_suspended() const {
|
|
||||||
return (_suspend_flags & _ext_suspended) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_external_suspend_with_lock() const {
|
|
||||||
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
return is_external_suspend();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special method to handle a pending external suspend request
|
|
||||||
// when a suspend equivalent condition lifts.
|
|
||||||
bool handle_special_suspend_equivalent_condition() {
|
|
||||||
assert(is_suspend_equivalent(),
|
|
||||||
"should only be called in a suspend equivalence condition");
|
|
||||||
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
bool ret = is_external_suspend();
|
|
||||||
if (!ret) {
|
|
||||||
// not about to self-suspend so clear suspend equivalence
|
|
||||||
clear_suspend_equivalent();
|
|
||||||
}
|
|
||||||
// implied else:
|
|
||||||
// We have a pending external suspend request so we leave the
|
|
||||||
// suspend_equivalent flag set until java_suspend_self() sets
|
|
||||||
// the ext_suspended flag and clears the suspend_equivalent
|
|
||||||
// flag. This insures that wait_for_ext_suspend_completion()
|
|
||||||
// will return consistent values.
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// utility methods to see if we are doing some kind of suspension
|
|
||||||
bool is_being_ext_suspended() const {
|
|
||||||
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
return is_ext_suspended() || is_external_suspend();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_suspend_equivalent() const { return _suspend_equivalent; }
|
|
||||||
|
|
||||||
void set_suspend_equivalent() { _suspend_equivalent = true; }
|
|
||||||
void clear_suspend_equivalent() { _suspend_equivalent = false; }
|
|
||||||
|
|
||||||
// Thread.stop support
|
// Thread.stop support
|
||||||
void send_thread_stop(oop throwable);
|
void send_thread_stop(oop throwable);
|
||||||
AsyncRequests clear_special_runtime_exit_condition() {
|
AsyncRequests clear_special_runtime_exit_condition() {
|
||||||
|
@ -1318,17 +1178,7 @@ class JavaThread: public Thread {
|
||||||
// Return true if JavaThread has an asynchronous condition or
|
// Return true if JavaThread has an asynchronous condition or
|
||||||
// if external suspension is requested.
|
// if external suspension is requested.
|
||||||
bool has_special_runtime_exit_condition() {
|
bool has_special_runtime_exit_condition() {
|
||||||
// Because we don't use is_external_suspend_with_lock
|
return (_special_runtime_exit_condition != _no_async_condition) || is_trace_suspend() || is_obj_deopt_suspend();
|
||||||
// it is possible that we won't see an asynchronous external suspend
|
|
||||||
// request that has just gotten started, i.e., SR_lock grabbed but
|
|
||||||
// _external_suspend field change either not made yet or not visible
|
|
||||||
// yet. However, this is okay because the request is asynchronous and
|
|
||||||
// we will see the new flag value the next time through. It's also
|
|
||||||
// possible that the external suspend request is dropped after
|
|
||||||
// we have checked is_external_suspend(), we will recheck its value
|
|
||||||
// under SR_lock in java_suspend_self().
|
|
||||||
return (_special_runtime_exit_condition != _no_async_condition) ||
|
|
||||||
is_external_suspend() || is_trace_suspend() || is_obj_deopt_suspend();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_pending_unsafe_access_error() { _special_runtime_exit_condition = _async_unsafe_access_error; }
|
void set_pending_unsafe_access_error() { _special_runtime_exit_condition = _async_unsafe_access_error; }
|
||||||
|
|
|
@ -119,20 +119,6 @@ inline WXMode Thread::enable_wx(WXMode new_state) {
|
||||||
}
|
}
|
||||||
#endif // __APPLE__ && AARCH64
|
#endif // __APPLE__ && AARCH64
|
||||||
|
|
||||||
inline void JavaThread::set_ext_suspended() {
|
|
||||||
set_suspend_flag (_ext_suspended);
|
|
||||||
}
|
|
||||||
inline void JavaThread::clear_ext_suspended() {
|
|
||||||
clear_suspend_flag(_ext_suspended);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JavaThread::set_external_suspend() {
|
|
||||||
set_suspend_flag(_external_suspend);
|
|
||||||
}
|
|
||||||
inline void JavaThread::clear_external_suspend() {
|
|
||||||
clear_suspend_flag(_external_suspend);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void JavaThread::set_pending_async_exception(oop e) {
|
inline void JavaThread::set_pending_async_exception(oop e) {
|
||||||
_pending_async_exception = e;
|
_pending_async_exception = e;
|
||||||
_special_runtime_exit_condition = _async_exception;
|
_special_runtime_exit_condition = _async_exception;
|
||||||
|
@ -194,28 +180,20 @@ inline void JavaThread::set_done_attaching_via_jni() {
|
||||||
inline bool JavaThread::is_exiting() const {
|
inline bool JavaThread::is_exiting() const {
|
||||||
// Use load-acquire so that setting of _terminated by
|
// Use load-acquire so that setting of _terminated by
|
||||||
// JavaThread::exit() is seen more quickly.
|
// JavaThread::exit() is seen more quickly.
|
||||||
TerminatedTypes l_terminated = (TerminatedTypes)
|
TerminatedTypes l_terminated = Atomic::load_acquire(&_terminated);
|
||||||
Atomic::load_acquire((volatile jint *) &_terminated);
|
|
||||||
return l_terminated == _thread_exiting || check_is_terminated(l_terminated);
|
return l_terminated == _thread_exiting || check_is_terminated(l_terminated);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool JavaThread::is_terminated() const {
|
inline bool JavaThread::is_terminated() const {
|
||||||
// Use load-acquire so that setting of _terminated by
|
// Use load-acquire so that setting of _terminated by
|
||||||
// JavaThread::exit() is seen more quickly.
|
// JavaThread::exit() is seen more quickly.
|
||||||
TerminatedTypes l_terminated = (TerminatedTypes)
|
TerminatedTypes l_terminated = Atomic::load_acquire(&_terminated);
|
||||||
Atomic::load_acquire((volatile jint *) &_terminated);
|
|
||||||
return check_is_terminated(l_terminated);
|
return check_is_terminated(l_terminated);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void JavaThread::set_terminated(TerminatedTypes t) {
|
inline void JavaThread::set_terminated(TerminatedTypes t) {
|
||||||
// use release-store so the setting of _terminated is seen more quickly
|
// use release-store so the setting of _terminated is seen more quickly
|
||||||
Atomic::release_store((volatile jint *) &_terminated, (jint) t);
|
Atomic::release_store(&_terminated, t);
|
||||||
}
|
|
||||||
|
|
||||||
// special for Threads::remove() which is static:
|
|
||||||
inline void JavaThread::set_terminated_value() {
|
|
||||||
// use release-store so the setting of _terminated is seen more quickly
|
|
||||||
Atomic::release_store((volatile jint *) &_terminated, (jint) _thread_terminated);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow tracking of class initialization monitor use
|
// Allow tracking of class initialization monitor use
|
||||||
|
|
|
@ -2145,8 +2145,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
|
||||||
/* Thread::SuspendFlags enum */ \
|
/* Thread::SuspendFlags enum */ \
|
||||||
/*****************************/ \
|
/*****************************/ \
|
||||||
\
|
\
|
||||||
declare_constant(Thread::_external_suspend) \
|
|
||||||
declare_constant(Thread::_ext_suspended) \
|
|
||||||
declare_constant(Thread::_has_async_exception) \
|
declare_constant(Thread::_has_async_exception) \
|
||||||
\
|
\
|
||||||
/*******************/ \
|
/*******************/ \
|
||||||
|
|
|
@ -309,7 +309,7 @@ static void initialize_ThreadInfo_constructor_arguments(JavaCallArguments* args,
|
||||||
|
|
||||||
int thread_status = static_cast<int>(snapshot->thread_status());
|
int thread_status = static_cast<int>(snapshot->thread_status());
|
||||||
assert((thread_status & JMM_THREAD_STATE_FLAG_MASK) == 0, "Flags already set in thread_status in Thread object");
|
assert((thread_status & JMM_THREAD_STATE_FLAG_MASK) == 0, "Flags already set in thread_status in Thread object");
|
||||||
if (snapshot->is_ext_suspended()) {
|
if (snapshot->is_suspended()) {
|
||||||
thread_status |= JMM_THREAD_STATE_FLAG_SUSPENDED;
|
thread_status |= JMM_THREAD_STATE_FLAG_SUSPENDED;
|
||||||
}
|
}
|
||||||
if (snapshot->is_in_native()) {
|
if (snapshot->is_in_native()) {
|
||||||
|
|
|
@ -879,7 +879,7 @@ void ThreadSnapshot::initialize(ThreadsList * t_list, JavaThread* thread) {
|
||||||
_sleep_count = stat->sleep_count();
|
_sleep_count = stat->sleep_count();
|
||||||
|
|
||||||
_thread_status = java_lang_Thread::get_thread_status(threadObj);
|
_thread_status = java_lang_Thread::get_thread_status(threadObj);
|
||||||
_is_ext_suspended = thread->is_being_ext_suspended();
|
_is_suspended = thread->is_suspended();
|
||||||
_is_in_native = (thread->thread_state() == _thread_in_native);
|
_is_in_native = (thread->thread_state() == _thread_in_native);
|
||||||
|
|
||||||
Handle obj = ThreadService::get_current_contended_monitor(thread);
|
Handle obj = ThreadService::get_current_contended_monitor(thread);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -196,7 +196,7 @@ private:
|
||||||
OopHandle _threadObj;
|
OopHandle _threadObj;
|
||||||
JavaThreadStatus _thread_status;
|
JavaThreadStatus _thread_status;
|
||||||
|
|
||||||
bool _is_ext_suspended;
|
bool _is_suspended;
|
||||||
bool _is_in_native;
|
bool _is_in_native;
|
||||||
|
|
||||||
jlong _contended_enter_ticks;
|
jlong _contended_enter_ticks;
|
||||||
|
@ -229,7 +229,7 @@ public:
|
||||||
|
|
||||||
void set_next(ThreadSnapshot* n) { _next = n; }
|
void set_next(ThreadSnapshot* n) { _next = n; }
|
||||||
|
|
||||||
bool is_ext_suspended() { return _is_ext_suspended; }
|
bool is_suspended() { return _is_suspended; }
|
||||||
bool is_in_native() { return _is_in_native; }
|
bool is_in_native() { return _is_in_native; }
|
||||||
|
|
||||||
jlong contended_enter_count() { return _contended_enter_count; }
|
jlong contended_enter_count() { return _contended_enter_count; }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -35,8 +35,6 @@ public class Thread extends VMObject {
|
||||||
|
|
||||||
private static CIntegerField suspendFlagsField;
|
private static CIntegerField suspendFlagsField;
|
||||||
// Thread::SuspendFlags enum constants
|
// Thread::SuspendFlags enum constants
|
||||||
private static int EXTERNAL_SUSPEND;
|
|
||||||
private static int EXT_SUSPENDED;
|
|
||||||
private static int HAS_ASYNC_EXCEPTION;
|
private static int HAS_ASYNC_EXCEPTION;
|
||||||
|
|
||||||
private static AddressField activeHandlesField;
|
private static AddressField activeHandlesField;
|
||||||
|
@ -57,8 +55,6 @@ public class Thread extends VMObject {
|
||||||
Type type = db.lookupType("Thread");
|
Type type = db.lookupType("Thread");
|
||||||
|
|
||||||
suspendFlagsField = type.getCIntegerField("_suspend_flags");
|
suspendFlagsField = type.getCIntegerField("_suspend_flags");
|
||||||
EXTERNAL_SUSPEND = db.lookupIntConstant("Thread::_external_suspend").intValue();
|
|
||||||
EXT_SUSPENDED = db.lookupIntConstant("Thread::_ext_suspended").intValue();
|
|
||||||
HAS_ASYNC_EXCEPTION = db.lookupIntConstant("Thread::_has_async_exception").intValue();
|
HAS_ASYNC_EXCEPTION = db.lookupIntConstant("Thread::_has_async_exception").intValue();
|
||||||
|
|
||||||
tlabFieldOffset = type.getField("_tlab").getOffset();
|
tlabFieldOffset = type.getField("_tlab").getOffset();
|
||||||
|
@ -76,23 +72,6 @@ public class Thread extends VMObject {
|
||||||
return (int) suspendFlagsField.getValue(addr);
|
return (int) suspendFlagsField.getValue(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isExternalSuspend() {
|
|
||||||
return (suspendFlags() & EXTERNAL_SUSPEND) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExtSuspended() {
|
|
||||||
return (suspendFlags() & EXT_SUSPENDED) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBeingExtSuspended() {
|
|
||||||
return isExtSuspended() || isExternalSuspend();
|
|
||||||
}
|
|
||||||
|
|
||||||
// historical usage: checked for VM or external suspension
|
|
||||||
public boolean isAnySuspended() {
|
|
||||||
return isExtSuspended();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasAsyncException() {
|
public boolean hasAsyncException() {
|
||||||
return (suspendFlags() & HAS_ASYNC_EXCEPTION) != 0;
|
return (suspendFlags() & HAS_ASYNC_EXCEPTION) != 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -103,9 +103,6 @@ public:
|
||||||
MutexLocker ml(Threads_lock);
|
MutexLocker ml(Threads_lock);
|
||||||
Threads::add(this);
|
Threads::add(this);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void main_run() = 0;
|
virtual void main_run() = 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -129,8 +129,8 @@ public class SuspendWithCurrentThread {
|
||||||
" to suspend all tested threads including itself");
|
" to suspend all tested threads including itself");
|
||||||
ThreadToSuspend.setAllThreadsReady();
|
ThreadToSuspend.setAllThreadsReady();
|
||||||
|
|
||||||
if (!checkSuspendedStatus()) {
|
while (!checkSuspendedStatus()) {
|
||||||
throw new RuntimeException("Main: FAILED status returned from checkTestedThreadsSuspended");
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
log("Main: resuming all tested threads");
|
log("Main: resuming all tested threads");
|
||||||
|
@ -166,7 +166,6 @@ public class SuspendWithCurrentThread {
|
||||||
class ThreadToSuspend extends Thread {
|
class ThreadToSuspend extends Thread {
|
||||||
private static void log(String msg) { System.out.println(msg); }
|
private static void log(String msg) { System.out.println(msg); }
|
||||||
|
|
||||||
private static native void init();
|
|
||||||
private static native void suspendTestedThreads();
|
private static native void suspendTestedThreads();
|
||||||
private static volatile boolean allThreadsReady = false;
|
private static volatile boolean allThreadsReady = false;
|
||||||
|
|
||||||
|
@ -187,10 +186,6 @@ class ThreadToSuspend extends Thread {
|
||||||
// run thread continuously
|
// run thread continuously
|
||||||
public void run() {
|
public void run() {
|
||||||
boolean needSuspend = true;
|
boolean needSuspend = true;
|
||||||
|
|
||||||
if (isSuspender) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
threadReady = true;
|
threadReady = true;
|
||||||
|
|
||||||
// run in a loop
|
// run in a loop
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -29,7 +29,6 @@ extern "C" {
|
||||||
static jvmtiEnv* jvmti = NULL;
|
static jvmtiEnv* jvmti = NULL;
|
||||||
static jthread* threads = NULL;
|
static jthread* threads = NULL;
|
||||||
static jsize threads_count = 0;
|
static jsize threads_count = 0;
|
||||||
static jrawMonitorID agent_monitor = NULL;
|
|
||||||
|
|
||||||
#define LOG(...) \
|
#define LOG(...) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -46,18 +45,6 @@ check_jvmti_status(JNIEnv* jni, jvmtiError err, const char* msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
agent_lock(JNIEnv* jni) {
|
|
||||||
jvmtiError err = jvmti->RawMonitorEnter(agent_monitor);
|
|
||||||
check_jvmti_status(jni, err, "monitor_enter: error in JVMTI RawMonitorEnter");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
agent_unlock(JNIEnv* jni) {
|
|
||||||
jvmtiError err = jvmti->RawMonitorExit(agent_monitor);
|
|
||||||
check_jvmti_status(jni, err, "monitor_exit: error in JVMTI RawMonitorExit");
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_SuspendWithCurrentThread_registerTestedThreads(JNIEnv *jni, jclass cls, jobjectArray threadsArr) {
|
Java_SuspendWithCurrentThread_registerTestedThreads(JNIEnv *jni, jclass cls, jobjectArray threadsArr) {
|
||||||
LOG("\nregisterTestedThreads: started");
|
LOG("\nregisterTestedThreads: started");
|
||||||
|
@ -74,16 +61,6 @@ Java_SuspendWithCurrentThread_registerTestedThreads(JNIEnv *jni, jclass cls, job
|
||||||
LOG("registerTestedThreads: finished\n");
|
LOG("registerTestedThreads: finished\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is executed on the suspender thread, not the Main thread */
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_ThreadToSuspend_init(JNIEnv *jni, jclass cls) {
|
|
||||||
jvmtiError err = jvmti->CreateRawMonitor("Agent monitor", &agent_monitor);
|
|
||||||
check_jvmti_status(jni, err, "Java_ThreadToSuspend_init: error in JVMTI CreateRawMonitor");
|
|
||||||
|
|
||||||
// Main thread has to wait for the suspender thread to complete tested threads suspension
|
|
||||||
agent_lock(jni);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is executed on the suspender thread which is not Main thread */
|
/* This function is executed on the suspender thread which is not Main thread */
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_ThreadToSuspend_suspendTestedThreads(JNIEnv *jni, jclass cls) {
|
Java_ThreadToSuspend_suspendTestedThreads(JNIEnv *jni, jclass cls) {
|
||||||
|
@ -106,9 +83,6 @@ Java_ThreadToSuspend_suspendTestedThreads(JNIEnv *jni, jclass cls) {
|
||||||
}
|
}
|
||||||
LOG("suspendTestedThreads: finished\n");
|
LOG("suspendTestedThreads: finished\n");
|
||||||
|
|
||||||
// Allow the Main thread to inspect the result of tested threads suspension
|
|
||||||
agent_unlock(jni);
|
|
||||||
|
|
||||||
err = jvmti->Deallocate((unsigned char*)results);
|
err = jvmti->Deallocate((unsigned char*)results);
|
||||||
check_jvmti_status(jni, err, "suspendTestedThreads: error in JVMTI Deallocate results");
|
check_jvmti_status(jni, err, "suspendTestedThreads: error in JVMTI Deallocate results");
|
||||||
}
|
}
|
||||||
|
@ -117,10 +91,6 @@ JNIEXPORT jboolean JNICALL
|
||||||
Java_SuspendWithCurrentThread_checkTestedThreadsSuspended(JNIEnv *jni, jclass cls) {
|
Java_SuspendWithCurrentThread_checkTestedThreadsSuspended(JNIEnv *jni, jclass cls) {
|
||||||
LOG("checkTestedThreadsSuspended: started");
|
LOG("checkTestedThreadsSuspended: started");
|
||||||
|
|
||||||
// Block until the suspender thread competes the tested threads suspension
|
|
||||||
agent_lock(jni);
|
|
||||||
agent_unlock(jni);
|
|
||||||
|
|
||||||
for (int i = 0; i < threads_count; i++) {
|
for (int i = 0; i < threads_count; i++) {
|
||||||
jint state = 0;
|
jint state = 0;
|
||||||
jvmtiError err = jvmti->GetThreadState(threads[i], &state);
|
jvmtiError err = jvmti->GetThreadState(threads[i], &state);
|
||||||
|
@ -129,7 +99,7 @@ Java_SuspendWithCurrentThread_checkTestedThreadsSuspended(JNIEnv *jni, jclass cl
|
||||||
if ((state & JVMTI_THREAD_STATE_SUSPENDED) == 0) {
|
if ((state & JVMTI_THREAD_STATE_SUSPENDED) == 0) {
|
||||||
LOG("thread #%d has not been suspended yet: "
|
LOG("thread #%d has not been suspended yet: "
|
||||||
"# state: (%#x)", i, (int)state);
|
"# state: (%#x)", i, (int)state);
|
||||||
jni->FatalError("checkTestedThreadsSuspended: error: expected all tested threads suspended");
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG("checkTestedThreadsSuspended: finished\n");
|
LOG("checkTestedThreadsSuspended: finished\n");
|
||||||
|
@ -167,8 +137,6 @@ Java_SuspendWithCurrentThread_releaseTestedThreadsInfo(JNIEnv *jni, jclass cls)
|
||||||
jvmtiError err;
|
jvmtiError err;
|
||||||
|
|
||||||
LOG("\nreleaseTestedThreadsInfo: started");
|
LOG("\nreleaseTestedThreadsInfo: started");
|
||||||
err = jvmti->DestroyRawMonitor(agent_monitor);
|
|
||||||
check_jvmti_status(jni, err, "releaseTestedThreadsInfo: error in JVMTI DestroyRawMonitor");
|
|
||||||
|
|
||||||
for (int i = 0; i < threads_count; i++) {
|
for (int i = 0; i < threads_count; i++) {
|
||||||
if (threads[i] != NULL) {
|
if (threads[i] != NULL) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue