Skip to content

Commit

Permalink
[Wisp] Port from jdk8u.
Browse files Browse the repository at this point in the history
Summary:
Port changes from Dragonwell8 and AJDK 8
Wisp Thread-based asynchronous IO implementation
Wisp WispTask memory leak in shutdown
- dragonwell-project/dragonwell8#211
Wisp ResourceContainerMXBean
- dragonwell-project/dragonwell8#206
Wisp Fix WispEventPump epollWait IllegalArgumentException
- dragonwell-project/dragonwell8#208
Wisp Shutdown Enhancement

Test Plan: wisp rcm tests

Reviewed-by: yulei

Issue:
dragonwell-project#142
  • Loading branch information
ZhaiMo15 committed Aug 28, 2023
1 parent 8f05877 commit 89f4f14
Show file tree
Hide file tree
Showing 50 changed files with 1,078 additions and 88 deletions.
5 changes: 3 additions & 2 deletions src/hotspot/share/c1/c1_Runtime1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,8 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c
// Reset method handle flag.
current->set_is_method_handle_return(false);

Handle exception(current, ex);
Handle exception(current, WispThread::is_current_death_pending(current) ?
(oopDesc*)Universe::wisp_thread_death_exception() : ex);

// This function is called when we are about to throw an exception. Therefore,
// we have to poll the stack watermark barrier to make sure that not yet safe
Expand Down Expand Up @@ -707,7 +708,7 @@ JRT_BLOCK_ENTRY(void, Runtime1::monitorenter(JavaThread* current, oopDesc* obj,
lock->set_obj(obj);
}
assert(obj == lock->obj(), "must match");
WispPostStealHandleUpdateMark w(__hm);
WispPostStealHandleUpdateMark w(current, __hm);
SharedRuntime::monitor_enter_helper(obj, lock->lock(), current);
JRT_END

Expand Down
6 changes: 6 additions & 0 deletions src/hotspot/share/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4774,6 +4774,8 @@ int com_alibaba_wisp_engine_WispTask::_activeCount_offset = 0;
int com_alibaba_wisp_engine_WispTask::_stealCount_offset = 0;
int com_alibaba_wisp_engine_WispTask::_stealFailureCount_offset = 0;
int com_alibaba_wisp_engine_WispTask::_preemptCount_offset = 0;
int com_alibaba_wisp_engine_WispTask::_shutdownPending_offset = 0;


#define WISPTASK_FIELDS_DO(macro) \
macro(_jvmParkStatus_offset, ik, vmSymbols::jvmParkStatus_name(), int_signature, false); \
Expand Down Expand Up @@ -4846,6 +4848,10 @@ int com_alibaba_wisp_engine_WispTask::get_stealFailureCount(oop obj) {
return obj->int_field(_stealFailureCount_offset);
}

bool com_alibaba_wisp_engine_WispTask::get_shutdownPending(oop obj) {
return obj->bool_field(_shutdownPending_offset);
}

#if INCLUDE_CDS
void java_nio_Buffer::serialize_offsets(SerializeClosure* f) {
BUFFER_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/classfile/javaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1837,6 +1837,7 @@ class com_alibaba_wisp_engine_WispTask: AllStatic {
static int _stealCount_offset;
static int _stealFailureCount_offset;
static int _preemptCount_offset;
static int _shutdownPending_offset;
public:
static void set_jvmParkStatus(oop obj, jint status);
static int get_jvmParkStatus(oop obj);
Expand All @@ -1850,6 +1851,7 @@ class com_alibaba_wisp_engine_WispTask: AllStatic {
static int get_stealFailureCount(oop obj);
static int get_preemptCount(oop obj);
static void set_preemptCount(oop obj, jint count);
static bool get_shutdownPending(oop obj);

static void compute_offsets();
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@
template(com_alibaba_wisp_engine_WispEventPump, "com/alibaba/wisp/engine/WispEventPump") \
template(isInCritical_name, "isInCritical") \
template(jdkParkStatus_name, "jdkParkStatus") \
template(shutdownPending_name, "shutdownPending") \
template(jvmParkStatus_name, "jvmParkStatus") \
template(id_name, "id") \
template(threadWrapper_name, "threadWrapper") \
Expand Down
7 changes: 6 additions & 1 deletion src/hotspot/share/interpreter/interpreterRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,12 @@ JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea
StackWatermarkSet::after_unwind(current);

LastFrameAccessor last_frame(current);
Handle h_exception(current, exception);
// Wisp relys on threadDeath as a special uncatchable exception to shutdown
// all running coroutines. However, exceptions throw in finally block
// will overwrite current threadDeath exception, thus we need to replace
// all exception with threadDeath after coroutine shutdown.
Handle h_exception(current, WispThread::is_current_death_pending(current) ?
(oopDesc*)Universe::wisp_thread_death_exception() : exception);
methodHandle h_method (current, last_frame.method());
constantPoolHandle h_constants(current, h_method->constants());
bool should_repeat;
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/jvmci/jvmciRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ address JVMCIRuntime::exception_handler_for_pc(JavaThread* current) {
}

JRT_BLOCK_ENTRY(void, JVMCIRuntime::monitorenter(JavaThread* current, oopDesc* obj, BasicLock* lock))
WispPostStealHandleUpdateMark w(__hm);
WispPostStealHandleUpdateMark w(current, __hm);
SharedRuntime::monitor_enter_helper(obj, lock, current);
JRT_END

Expand Down
12 changes: 11 additions & 1 deletion src/hotspot/share/memory/universe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ enum OutOfMemoryInstance { _oom_java_heap,
_oom_count };

OopHandle Universe::_out_of_memory_errors;
OopHandle Universe::_wisp_thread_death_exception;
OopHandle Universe::_delayed_stack_overflow_error_message;
OopHandle Universe::_preallocated_out_of_memory_error_array;
volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0;
Expand Down Expand Up @@ -577,6 +578,7 @@ oop Universe::out_of_memory_error_realloc_objects() {

// Throw default _out_of_memory_error_retry object as it will never propagate out of the VM
oop Universe::out_of_memory_error_retry() { return out_of_memory_errors()->obj_at(_oom_retry); }
oop Universe::wisp_thread_death_exception() { return _wisp_thread_death_exception.resolve(); }
oop Universe::delayed_stack_overflow_error_message() { return _delayed_stack_overflow_error_message.resolve(); }


Expand Down Expand Up @@ -952,6 +954,14 @@ bool universe_post_init() {
Universe::create_preallocated_out_of_memory_errors(CHECK_false);

oop instance;
Klass* k;
if (EnableCoroutine && Wisp2ThreadStop) {
// Create the special exception used to kill thread
k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_ThreadDeath(), true, CHECK_false);
assert(NULL != k, "pre-condition");
instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false);
Universe::_wisp_thread_death_exception = OopHandle(Universe::vm_global(), instance);
}
// Setup preallocated cause message for delayed StackOverflowError
if (StackReservedPages > 0) {
instance = java_lang_String::create_oop_from_str("Delayed StackOverflowError due to ReservedStackAccess annotated method", CHECK_false);
Expand All @@ -960,7 +970,7 @@ bool universe_post_init() {

// Setup preallocated NullPointerException
// (this is currently used for a cheap & dirty solution in compiler exception handling)
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_NullPointerException(), true, CHECK_false);
k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_NullPointerException(), true, CHECK_false);
instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false);
Universe::_null_ptr_exception_instance = OopHandle(Universe::vm_global(), instance);

Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/memory/universe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class Universe: AllStatic {

// preallocated error objects (no backtrace)
static OopHandle _out_of_memory_errors;
static OopHandle _wisp_thread_death_exception;

// preallocated cause message for delayed StackOverflowError
static OopHandle _delayed_stack_overflow_error_message;
Expand Down Expand Up @@ -296,6 +297,7 @@ class Universe: AllStatic {
// Throw default _out_of_memory_error_retry object as it will never propagate out of the VM
static oop out_of_memory_error_retry();
static oop delayed_stack_overflow_error_message();
static oop wisp_thread_death_exception();

// The particular choice of collected heap.
static CollectedHeap* heap() { return _collectedHeap; }
Expand Down
6 changes: 6 additions & 0 deletions src/hotspot/share/oops/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_kla
// access exception table
ExceptionTable table(mh());
int length = table.length();
bool is_force_thread_death_exception = (EnableCoroutine && Wisp2ThreadStop
&& (ex_klass == vmClasses::ThreadDeath_klass()
|| ex_klass->is_subtype_of(vmClasses::ThreadDeath_klass())));
// iterate through all entries sequentially
constantPoolHandle pool(THREAD, mh->constants());
for (int i = 0; i < length; i ++) {
Expand Down Expand Up @@ -287,6 +290,9 @@ int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_kla
}
assert(k != NULL, "klass not loaded");
if (ex_klass->is_subtype_of(k)) {
if (is_force_thread_death_exception) {
continue;
}
if (log_is_enabled(Info, exceptions)) {
ResourceMark rm(THREAD);
log_info(exceptions)("Found matching handler for exception of type \"%s\" in method \"%s\" at BCI: %d",
Expand Down
3 changes: 2 additions & 1 deletion src/hotspot/share/opto/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1284,7 +1284,8 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* c
assert(current->exception_oop() != NULL, "exception oop is found");
address handler_address = NULL;

Handle exception(current, current->exception_oop());
Handle exception(current, WispThread::is_current_death_pending(current) ?
Universe::wisp_thread_death_exception() : current->exception_oop());
address pc = current->exception_pc();

// Clear out the exception oop and pc since looking up an
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/prims/unsafe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,7 @@ JVM_ENTRY(jboolean, CoroutineSupport_stealCoroutine(JNIEnv* env, jclass klass, j
// The lock will also block coroutine switch operation,
// so we must finish the steal operation as soon as possible.
Coroutine* coro = (Coroutine*) coroPtr;
if (coro == NULL || coro->enable_steal_count() != coro->java_call_counter()) {
if (coro == NULL || coro->enable_steal_count() != coro->java_call_counter() || coro->is_yielding()) {
return false; // an Exception throws and the coroutine being stealed is exited
}
assert(coro->thread() != thread, "steal from self");
Expand Down Expand Up @@ -1022,7 +1022,7 @@ JVM_ENTRY (jboolean, CoroutineSupport_shouldThrowException0(JNIEnv* env, jclass
assert(EnableCoroutine, "pre-condition");
Coroutine* coro = (Coroutine*)coroPtr;
assert(coro == thread->current_coroutine(), "invariant");
return !coro->is_yielding() && coro->clinit_call_count() == 0;
return coro->clinit_call_count() == 0;
JVM_END

JVM_ENTRY (void, CoroutineSupport_printlnLockFree(JNIEnv* env, jclass klass, jstring info))
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/runtime/arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3985,6 +3985,10 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
}
}

if (Wisp2ThreadStop && !UseWisp2) {
vm_exit_during_initialization("Wisp2ThreadStop only works with UseWisp2");
}

// Set object alignment values.
set_object_alignment();

Expand Down
18 changes: 14 additions & 4 deletions src/hotspot/share/runtime/coroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,10 @@ void WispThread::park(long millis, const ObjectWaiter* ow) {
// the runtime can not handle the exception on monitorenter bci
// we need clear it to prevent jvm crash
if (jt->has_pending_exception()) {
jt->clear_pending_exception();
if (EnableCoroutine && Wisp2ThreadStop && jt->pending_exception()->klass() == vmClasses::ThreadDeath_klass()) {
jt->set_pending_async_exception(jt->pending_exception());
}
jt->clear_pending_exception();
}

ThreadStateTransition::transition(jt, _thread_in_vm, _thread_blocked);
Expand Down Expand Up @@ -783,6 +786,10 @@ void WispThread::unpark(int task_id, bool using_wisp_park, bool proxy_unpark, Pa

// due to the fact that we modify the priority of Wisp_lock from `non-leaf` to `special`,
// so we'd use `MutexLocker` and `_no_safepoint_check_flag` to make our program run
// We don't want to yield a safepoint here, so we use the `special` rank to prevent it:
// In UnlockNode, we will call java in Wisp. We can't yield a safepoint that may cause
// deoptimization, which is very fatal for monitors.
NoSafepointVerifier nsv;
MutexLocker mu(Wisp_lock, Mutex::_no_safepoint_check_flag);
wisp_thread->_unpark_status = WispThread::_proxy_unpark_begin;
_proxy_unpark->append(task_id);
Expand Down Expand Up @@ -843,6 +850,7 @@ int WispThread::get_proxy_unpark(jintArray res) {
NoSafepointVerifier nsv;
MutexLocker mu(Wisp_lock, Mutex::_no_safepoint_check_flag);
while (_proxy_unpark == NULL || _proxy_unpark->is_empty()) {
// we need to use _no_safepoint_check_flag, which won't yield a safepoint.
Wisp_lock->wait_without_safepoint_check();
}
typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(res));
Expand Down Expand Up @@ -1002,6 +1010,9 @@ void Coroutine::after_safepoint(JavaThread* thread) {
"Only SOF/OOM/ThreadDeath happens here");
// If it's a SOF / OOM / ThreadDeath exception, we'd clear it
// because polling page stub shouldn't have a pending exception.
if (UseWisp2 && Wisp2ThreadStop && thread->pending_exception()->klass() == vmClasses::ThreadDeath_klass()) {
thread->set_pending_async_exception(thread->pending_exception());
}
thread->clear_pending_exception();
}

Expand Down Expand Up @@ -1157,10 +1168,9 @@ WispPostStealHandleUpdateMark::WispPostStealHandleUpdateMark(JavaThread *& th1,
WispPostStealHandle h2(&tiva);
}

WispPostStealHandleUpdateMark::WispPostStealHandleUpdateMark(HandleMarkCleaner & hmc)
WispPostStealHandleUpdateMark::WispPostStealHandleUpdateMark(JavaThread *thread, HandleMarkCleaner & hmc)
{
assert(hmc.thread_ref()->is_Java_thread(), "sanity");
initialize((JavaThread*)hmc.thread_ref());
initialize(thread);

if (!_success) return;
WispPostStealHandle h(&hmc);
Expand Down
16 changes: 15 additions & 1 deletion src/hotspot/share/runtime/coroutine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,20 @@ class WispThread: public JavaThread {
static void set_wisp_booted(JavaThread* thread);
static const char *print_os_park_reason(int reason);
static const char *print_blocking_status(int status);
static const bool is_current_death_pending(JavaThread *thread) {
if (EnableCoroutine && Wisp2ThreadStop) {
if (thread->current_coroutine() == NULL) {
// Main Thread
return false;
}
if (thread->current_coroutine()->wisp_task() == NULL) {
// Blacklisted threads that are not converted to couroutines
return false;
}
return com_alibaba_wisp_engine_WispTask::get_shutdownPending(thread->current_coroutine()->wisp_task());
}
return false;
}

virtual bool is_Wisp_thread() const { return true; }

Expand Down Expand Up @@ -661,7 +675,7 @@ class WispPostStealHandleUpdateMark: public StackObj {
ThreadInVMfromJava & tiva, HandleMarkCleaner & hmc);
WispPostStealHandleUpdateMark(JavaThread *& th1, Thread *& th2, // constructor for other monitorenters
ThreadInVMfromJava & tiva);
WispPostStealHandleUpdateMark(HandleMarkCleaner & hmc);
WispPostStealHandleUpdateMark(JavaThread *thread, HandleMarkCleaner & hmc);
WispPostStealHandleUpdateMark(JavaThread *thread, ThreadBlockInVM & tbv); // constructor is used inside objectMonitor call, which is also within EnableStealMark scope.
WispPostStealHandleUpdateMark(JavaThread *thread, ThreadStateTransition & tst);
WispPostStealHandleUpdateMark(JavaThread *& th); // this is a special one, used for a fix inside EnableStealMark
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/runtime/globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2100,6 +2100,9 @@ const intx ObjectAlignmentInBytes = 8;
product(bool, UseWisp2, false, \
"Enable Wisp2") \
\
product(bool, Wisp2ThreadStop, false, \
"ThreadDeath cannot be catched") \
\
product(bool, PrintThreadCoroutineInfo, false, MANAGEABLE, \
"print the park/unpark information for thread coroutine") \
\
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/runtime/safepoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,10 @@ void SafepointSynchronize::block(JavaThread *thread) {
guarantee(thread->safepoint_state()->get_safepoint_id() == InactiveSafepointCounter,
"The safepoint id should be set only in block path");

if (EnableCoroutine) {
Coroutine::after_safepoint(thread);
}

// cross_modify_fence is done by SafepointMechanism::process_if_requested
// which is the only caller here.
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/runtime/sharedRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2148,7 +2148,7 @@ void SharedRuntime::monitor_enter_helper(oopDesc* obj, BasicLock* lock, JavaThre

// Handles the uncommon case in locking, i.e., contention or an inflated lock.
JRT_BLOCK_ENTRY(void, SharedRuntime::complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* current))
WispPostStealHandleUpdateMark w(__hm);
WispPostStealHandleUpdateMark w(current, __hm);
SharedRuntime::monitor_enter_helper(obj, lock, current);
JRT_END

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,8 @@ static ResourceContainer current() {
* Then the container state will become {@link State#DEAD}.
*/
void destroy();

Long getId();

Long getConsumedAmount(ResourceType resourceType);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.alibaba.rcm;

import com.alibaba.rcm.Constraint;
import com.alibaba.rcm.ResourceContainer;
import com.alibaba.rcm.ResourceType;
import com.alibaba.rcm.internal.AbstractResourceContainer;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public class ResourceContainerMonitor {
private static Map<Long, ResourceContainer> tenantContainerMap = new ConcurrentHashMap<>();
private static AtomicLong idGen = new AtomicLong(0);

public ResourceContainerMonitor() {
}

public static long register(ResourceContainer resourceContainer) {
long id = idGen.getAndIncrement();
tenantContainerMap.put(id, resourceContainer);
return id;
}

public static void deregister(long id) {
tenantContainerMap.remove(id);
}

public static ResourceContainer getContainerById(long id) {
return tenantContainerMap.get(id);
}

public static List<Long> getAllContainerIds() {
return new ArrayList<>(tenantContainerMap.keySet());
}

public static List<Constraint> getConstraintsById(long id) {
AbstractResourceContainer resourceContainer = (AbstractResourceContainer) tenantContainerMap.get(id);
return StreamSupport
.stream(resourceContainer.getConstraints().spliterator(), false)
.collect(Collectors.toList());
}

public long getContainerConsumedAmount(long id) {
return 0;
}

}
Loading

0 comments on commit 89f4f14

Please sign in to comment.