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
- https://code.aone.alibaba-inc.com/ajdk/jdk8u_jdk/codereview/5309632
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
- https://code.aone.alibaba-inc.com/ajdk/jdk8u_jdk/codereview/5165311

Test Plan: wisp rcm tests

Reviewers: lei.yul, sanhong.lsh

Issue: https://aone.alibaba-inc.com/task/34331904

CR: https://code.aone.alibaba-inc.com/xcode/jdk11/codereview/5350241
  • Loading branch information
joeylee.lz committed May 2, 2021
1 parent 8375876 commit a940716
Show file tree
Hide file tree
Showing 48 changed files with 1,073 additions and 85 deletions.
3 changes: 2 additions & 1 deletion src/hotspot/share/c1/c1_Runtime1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,8 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
// Reset method handle flag.
thread->set_is_method_handle_return(false);

Handle exception(thread, ex);
Handle exception(thread, WispThread::is_current_death_pending(thread)?
(oopDesc*) Universe::wisp_thread_death_exception() : ex);
nm = CodeCache::find_nmethod(pc);
assert(nm != NULL, "this is not an nmethod");
// Adjust the pc as needed/
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 @@ -4522,6 +4522,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, k, vmSymbols::jvmParkStatus_name(), int_signature, false); \
Expand Down Expand Up @@ -4594,6 +4596,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 @@ -1643,6 +1643,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 @@ -1656,6 +1657,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 @@ -820,6 +820,7 @@
template(string_string_string_string_bool_bool_void_signature, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)V") \
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 @@ -485,7 +485,12 @@ IRT_END
IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThread* thread, oopDesc* exception))

LastFrameAccessor last_frame(thread);
Handle h_exception(thread, 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(thread, WispThread::is_current_death_pending(thread)?
(oopDesc*) Universe::wisp_thread_death_exception() : exception);
methodHandle h_method (thread, last_frame.method());
constantPoolHandle h_constants(thread, h_method->constants());
bool should_repeat;
Expand Down
11 changes: 10 additions & 1 deletion src/hotspot/share/memory/universe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ oop Universe::_out_of_memory_error_class_metaspace = NULL;
oop Universe::_out_of_memory_error_array_size = NULL;
oop Universe::_out_of_memory_error_gc_overhead_limit = NULL;
oop Universe::_out_of_memory_error_realloc_objects = NULL;
oop Universe::_wisp_thread_death_exception = NULL;
oop Universe::_tenant_death_exception = NULL;
oop Universe::_delayed_stack_overflow_error_message = NULL;
objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL;
Expand Down Expand Up @@ -208,6 +209,9 @@ void Universe::oops_do(OopClosure* f, bool do_all) {
}
f->do_oop((oop*)&_delayed_stack_overflow_error_message);
f->do_oop((oop*)&_preallocated_out_of_memory_error_array);
if (EnableCoroutine && Wisp2ThreadStop) {
f->do_oop((oop*)&_wisp_thread_death_exception);
}
f->do_oop((oop*)&_null_ptr_exception_instance);
f->do_oop((oop*)&_arithmetic_exception_instance);
f->do_oop((oop*)&_virtual_machine_error_instance);
Expand Down Expand Up @@ -1054,7 +1058,12 @@ bool universe_post_init() {
Universe::_out_of_memory_error_gc_overhead_limit =
ik->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_realloc_objects = ik->allocate_instance(CHECK_false);

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");
Universe::_wisp_thread_death_exception = InstanceKlass::cast(k)->allocate_instance(CHECK_false);
}
if (MultiTenant && TenantThreadStop) {
// Create the special exception used to kill thread
k = SystemDictionary::resolve_or_fail(vmSymbols::com_alibaba_tenant_TenantDeathException(), true, CHECK_false);
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 @@ -158,6 +158,7 @@ class Universe: AllStatic {
static oop _out_of_memory_error_array_size;
static oop _out_of_memory_error_gc_overhead_limit;
static oop _out_of_memory_error_realloc_objects;
static oop _wisp_thread_death_exception;

// preallocated cause message for delayed StackOverflowError
static oop _delayed_stack_overflow_error_message;
Expand Down Expand Up @@ -377,6 +378,7 @@ class Universe: AllStatic {
static oop out_of_memory_error_gc_overhead_limit() { return gen_out_of_memory_error(_out_of_memory_error_gc_overhead_limit); }
static oop out_of_memory_error_realloc_objects() { return gen_out_of_memory_error(_out_of_memory_error_realloc_objects); }
static oop delayed_stack_overflow_error_message() { return _delayed_stack_overflow_error_message; }
static oop wisp_thread_death_exception() { return _wisp_thread_death_exception; }

// special exception used for killing thread
static oop tenant_death_exception() { return _tenant_death_exception; }
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 @@ -210,6 +210,9 @@ int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_kla
is_tenant_death_exception = true;
}
}
bool is_force_thread_death_exception = (EnableCoroutine && Wisp2ThreadStop
&& (ex_klass == SystemDictionary::ThreadDeath_klass()
|| ex_klass->is_subtype_of(SystemDictionary::ThreadDeath_klass())));
// iterate through all entries sequentially
constantPoolHandle pool(THREAD, mh->constants());
for (int i = 0; i < length; i ++) {
Expand Down Expand Up @@ -238,6 +241,9 @@ int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_kla
&& is_tenant_death_exception && THREAD->is_Java_thread()) {
continue;
}
if (is_force_thread_death_exception) {
continue;
}
return handler_bci;
}
}
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 @@ -1328,7 +1328,8 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t
assert(thread->exception_oop() != NULL, "exception oop is found");
address handler_address = NULL;

Handle exception(thread, thread->exception_oop());
Handle exception(thread, WispThread::is_current_death_pending(thread)?
Universe::wisp_thread_death_exception() : thread->exception_oop());
address pc = thread->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 @@ -1150,7 +1150,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 All @@ -1176,7 +1176,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

UNSAFE_ENTRY(jint, Unsafe_GetMaxVectorSize(JNIEnv *env, jobject unsafe, jobject clazz))
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 @@ -4032,6 +4032,10 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
}
}

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

if (EagerAppCDS && !FLAG_IS_CMDLINE(NotFoundClassOpt)) {
NotFoundClassOpt = true;
}
Expand Down
23 changes: 21 additions & 2 deletions src/hotspot/share/runtime/coroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,10 @@ void WispThread::park(long millis, const ObjectWaiter* ow) {
if (jt->has_pending_exception()) {
assert((MultiTenant && TenantThreadStop && jt->has_tenant_death_exception()) || jt->pending_exception()->klass() == SystemDictionary::ThreadDeath_klass(),
"tenant_death_exception expected");
jt->clear_pending_exception();
if (EnableCoroutine && Wisp2ThreadStop && jt->pending_exception()->klass() == SystemDictionary::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 @@ -788,6 +791,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 `MutexLockerEx` 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;
MutexLockerEx 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 @@ -846,9 +853,18 @@ void WispThread::unpark(int task_id, bool using_wisp_park, bool proxy_unpark, Pa
}

int WispThread::get_proxy_unpark(jintArray res) {
// We need to hoist code of safepoint state out of MutexLocker to prevent safepoint deadlock problem
// See the same usage: SR_lock in `JavaThread::exit()`
ThreadBlockInVM tbivm(JavaThread::current());
// When wait()ing, GC may occur. So we shouldn't verify GC.
NoSafepointVerifier nsv(true, false);
MutexLockerEx mu(Wisp_lock, Mutex::_no_safepoint_check_flag);
while (_proxy_unpark == NULL || _proxy_unpark->is_empty()) {
Wisp_lock->wait();
// we need to use _no_safepoint_check_flag, which won't yield a safepoint.
// origin wait(false): first hold lock then do a safepoint.
// Other thread will stuck when grabbing the lock.
// current wait(true): first safepoint then hold lock to deal with the problem.
Wisp_lock->wait(Mutex::_no_safepoint_check_flag);
}
typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(res));
if (a == NULL) {
Expand Down Expand Up @@ -1012,6 +1028,9 @@ void Coroutine::after_safepoint(JavaThread* thread) {
"Only SOF/OOM/ThreadDeath/TenantDeath happens here");
// If it's a SOF / OOM / ThreadDeath / TenantDeath exception, we'd clear it
// because polling page stub shouldn't have a pending exception.
if (UseWisp2 && Wisp2ThreadStop && thread->pending_exception()->klass() == SystemDictionary::ThreadDeath_klass()) {
thread->set_pending_async_exception(thread->pending_exception());
}
thread->clear_pending_exception();
}

Expand Down
14 changes: 14 additions & 0 deletions src/hotspot/share/runtime/coroutine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,20 @@ class WispThread: public JavaThread {
static void set_wisp_booted(Thread* 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
2 changes: 2 additions & 0 deletions src/hotspot/share/runtime/globals_ext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
\
product(bool, UseWisp2, false, \
"Enable Wisp2") \
product(bool, Wisp2ThreadStop, false, \
"ThreadDeath cannot be catched") \
\
manageable(bool, PrintThreadCoroutineInfo, false, \
"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 @@ -985,6 +985,10 @@ void SafepointSynchronize::block(JavaThread *thread) {
thread->handle_special_runtime_exit_condition(
!thread->is_at_poll_safepoint() && (state != _thread_in_native_trans));
}

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

// ------------------------------------------------------------------------------------------------------
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,49 @@
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 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 a940716

Please sign in to comment.