diff --git a/make/CompileJavaClasses.gmk b/make/CompileJavaClasses.gmk
index 10f5b533a585b328bfa068c0496acc425a344f98..188ccc1742fbf3cebac72cf2470bbeacf6535ba9 100644
--- a/make/CompileJavaClasses.gmk
+++ b/make/CompileJavaClasses.gmk
@@ -264,6 +264,11 @@ ifndef OPENJDK
$(wildcard $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS_API_DIR)/classes)
endif
+LINUX_SRC_DIRS :=
+ifeq ($(OPENJDK_TARGET_OS), linux)
+ LINUX_SRC_DIRS += $(JDK_TOPDIR)/src/linux/classes
+endif
+
MACOSX_SRC_DIRS :=
ifeq ($(OPENJDK_TARGET_OS), macosx)
MACOSX_SRC_DIRS += $(JDK_TOPDIR)/src/macosx/classes
@@ -328,6 +333,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JDK,\
SRC:=$(JDK_TOPDIR)/src/share/classes \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes \
$(MACOSX_SRC_DIRS) \
+ $(LINUX_SRC_DIRS) \
$(AIX_SRC_DIRS) \
$(JDK_OUTPUTDIR)/gensrc \
$(JDK_OUTPUTDIR)/gensrc_no_srczip \
diff --git a/make/CreateJars.gmk b/make/CreateJars.gmk
index 4fe038f64e036ede1b1b4339e9d53c44aa5656ee..12be408d8b42efc02654d15f8347b832637eda58 100644
--- a/make/CreateJars.gmk
+++ b/make/CreateJars.gmk
@@ -562,7 +562,8 @@ EXPORTED_PRIVATE_PKGS = com.oracle.net \
com.alibaba.management \
com.alibaba.jvm.gc \
com.alibaba.rcm \
- com.alibaba.tenant
+ com.alibaba.tenant \
+ com.alibaba.wisp.engine \
$(IMAGES_OUTPUTDIR)/symbols/_the.symbols: $(IMAGES_OUTPUTDIR)/lib/rt.jar
$(RM) -r $(IMAGES_OUTPUTDIR)/symbols/META-INF/sym
diff --git a/make/data/classlist/classlist.linux b/make/data/classlist/classlist.linux
index 86a2a150bec267ee48271596b14c2c8336156d62..9ab2398b60c69e31d64fe24f10b4526434de3548 100644
--- a/make/data/classlist/classlist.linux
+++ b/make/data/classlist/classlist.linux
@@ -2565,4 +2565,7 @@ com/alibaba/tenant/TenantException
com/alibaba/tenant/TenantState
com/alibaba/tenant/TenantGlobals
com/alibaba/tenant/TenantContainerFactory
+com/dyn/Coroutine
+com/alibaba/wisp/engine/WispEngine
+com/alibaba/wisp/engine/WispSysmon
# eea35d9d56e0006e
\ No newline at end of file
diff --git a/make/lib/CoreLibraries.gmk b/make/lib/CoreLibraries.gmk
index ffdeb712b3112b5e2d80796c400eeda0667c1a51..019106e9e8d2a52bf075c80a58fd7923d21ad9d6 100644
--- a/make/lib/CoreLibraries.gmk
+++ b/make/lib/CoreLibraries.gmk
@@ -144,6 +144,7 @@ LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/l
$(JDK_TOPDIR)/src/share/native/com/alibaba/jwarmup \
$(JDK_TOPDIR)/src/share/native/com/alibaba/jvm/gc \
$(JDK_TOPDIR)/src/share/native/com/alibaba/tenant \
+ $(JDK_TOPDIR)/src/share/native/java/dyn \
$(JDK_TOPDIR)/src/share/native/sun/misc \
$(JDK_TOPDIR)/src/share/native/sun/reflect \
$(JDK_TOPDIR)/src/share/native/java/util \
@@ -151,6 +152,11 @@ LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/l
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/common \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/util
+# Wisp only supports Linux
+ifeq ($(OPENJDK_TARGET_OS), linux)
+ LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/linux/native/com/alibaba/wisp/engine
+endif
+
ifeq ($(OPENJDK_TARGET_OS), windows)
LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/util/locale/provider
else ifeq ($(OPENJDK_TARGET_OS), macosx)
diff --git a/make/mapfiles/libjava/mapfile-vers b/make/mapfiles/libjava/mapfile-vers
index 85f287d3d365ae798eca149d7f73fdcd9ec0c82a..cf92f270221be7a48a1258065cacee3ac873b7e4 100644
--- a/make/mapfiles/libjava/mapfile-vers
+++ b/make/mapfiles/libjava/mapfile-vers
@@ -221,6 +221,10 @@ SUNWprivate_1.1 {
Java_com_alibaba_jwarmup_JWarmUp_registerNatives;
Java_com_alibaba_tenant_TenantGlobals_getTenantFlags;
Java_com_alibaba_jvm_gc_ElasticHeapMXBeanImpl_registerNatives;
+ Java_com_alibaba_wisp_engine_WispEngine_registerNatives;
+ Java_com_alibaba_wisp_engine_WispSysmon_registerNatives;
+ Java_com_alibaba_wisp_engine_WispTask_registerNatives;
+ Java_java_dyn_Coroutine_registerNatives;
Java_java_lang_Throwable_fillInStackTrace;
Java_java_lang_Throwable_getStackTraceDepth;
Java_java_lang_Throwable_getStackTraceElement;
diff --git a/make/mapfiles/libjava/reorder-x86 b/make/mapfiles/libjava/reorder-x86
index 05792d0e304f82f458aa709da124b7f45c0519f7..cf32a6eec0bc64413e01c726ce43e6772a59cee6 100644
--- a/make/mapfiles/libjava/reorder-x86
+++ b/make/mapfiles/libjava/reorder-x86
@@ -13,6 +13,10 @@ text: .text%Java_java_lang_Thread_registerNatives;
text: .text%Java_com_alibaba_tenant_TenantGlobals_getTenantFlags;
text: .text%Java_com_alibaba_jwarmup_JWarmUp_registerNatives;
text: .text%Java_com_alibaba_jvm_gc_ElasticHeapMXBeanImpl_registerNatives;
+text: .text%Java_com_alibaba_wisp_engine_WispEngine_registerNatives;
+text: .text%Java_com_alibaba_wisp_engine_WispSysmon_registerNatives;
+text: .text%Java_com_alibaba_wisp_engine_WispTask_registerNatives;
+text: .text%Java_java_dyn_Coroutine_registerNatives;
text: .text%Java_java_security_AccessController_getStackAccessControlContext;
text: .text%Java_java_security_AccessController_getInheritedAccessControlContext;
text: .text%Java_java_lang_ClassLoader_registerNatives;
diff --git a/make/mapfiles/libnio/mapfile-linux b/make/mapfiles/libnio/mapfile-linux
index bdfaa45f13f9a789716cd12a21e45fda87348d08..55afed516212177133ce57b135e35d6eccc714a6 100644
--- a/make/mapfiles/libnio/mapfile-linux
+++ b/make/mapfiles/libnio/mapfile-linux
@@ -49,6 +49,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_EPoll_epollCreate;
Java_sun_nio_ch_EPoll_epollCtl;
Java_sun_nio_ch_EPoll_epollWait;
+ Java_sun_nio_ch_EPoll_errnoENOENT;
Java_sun_nio_ch_EPollPort_close0;
Java_sun_nio_ch_EPollPort_drain1;
Java_sun_nio_ch_EPollPort_interrupt;
diff --git a/src/linux/classes/com/alibaba/wisp/engine/StealAwareRunnable.java b/src/linux/classes/com/alibaba/wisp/engine/StealAwareRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a1336927384b8b8038f425c68ae48613bb20b09
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/StealAwareRunnable.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+
+/**
+ * An runnable that is aware of work stealing.
+ */
+public interface StealAwareRunnable extends Runnable {
+
+ /**
+ * @return if that runnable could be stolen
+ */
+ default boolean isStealEnable() {
+ return true;
+ }
+
+ /**
+ * Set this runnable's {@link #isStealEnable} to given value
+ */
+ default void setStealEnable(boolean b) {
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/TaskDispatcher.java b/src/linux/classes/com/alibaba/wisp/engine/TaskDispatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc5d62d6e3ec8b93c62ddcb8d6ac4a84a36250b7
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/TaskDispatcher.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+class TaskDispatcher implements StealAwareRunnable {
+ private final ClassLoader ctxClassLoader;
+ private final long enqueueTime;
+ private final Runnable target;
+ private final String name;
+ private final Thread thread;
+
+ TaskDispatcher(ClassLoader ctxClassLoader, Runnable target, String name, Thread thread) {
+ this.ctxClassLoader = ctxClassLoader;
+ this.enqueueTime = WispEngine.getNanoTime();
+ this.target = target;
+ this.name = name;
+ this.thread = thread;
+ }
+
+ @Override
+ public void run() {
+ WispCarrier current = WispCarrier.current();
+ current.countEnqueueTime(enqueueTime);
+ current.runTaskInternal(target, name, thread,
+ ctxClassLoader == null ? current.current.ctxClassLoader : ctxClassLoader);
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/ThreadAsWisp.java b/src/linux/classes/com/alibaba/wisp/engine/ThreadAsWisp.java
new file mode 100644
index 0000000000000000000000000000000000000000..eedf53ff7b201d6f7efdaa3a0d0d5e35bb70a5a1
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/ThreadAsWisp.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import java.util.stream.Stream;
+
+/**
+ * Convert Thread.start() to Wisp without changing application's code.
+ *
+ * Note that ThreadAsWisp is not wisp core logic, just a wrapper of wisp
+ * coroutine create API which is used by jdk threading library, so we can
+ * use objectMonitor here.
+ */
+class ThreadAsWisp {
+ private final static String JAVA_LANG_PKG = "package:java.lang";
+
+ private static int nonDaemonCount;
+ private static Thread preventShutdownThread;
+
+
+ /**
+ * Try to "start thread" as wisp if all listed condition is satisfied:
+ *
+ * 1. not in java.lang or blacklisted package/class
+ * 2. not a WispEngine internal Thread
+ * 3. allThreadAsWisp is true and not match the blacklist
+ *
+ * @param thread the thread
+ * @param target thread's target field
+ * @return if condition is satisfied and thread is started as wisp
+ */
+ static boolean tryStart(Thread thread, Runnable target) {
+ if (!WispConfiguration.ALL_THREAD_AS_WISP
+ || WispEngine.isEngineThread(thread)
+ || matchBlackList(thread, target)) {
+ return false;
+ }
+
+ if (!thread.isDaemon()) {
+ synchronized (ThreadAsWisp.class) {
+ if (nonDaemonCount++ == 0) { // start a non-daemon thread to prevent jvm exit
+ assert preventShutdownThread == null;
+ preventShutdownThread = new PreventShutdownThread();
+ preventShutdownThread.start();
+ }
+ }
+ }
+
+ // pthread_create always return before new thread started, so we should not wait here
+ WispEngine.JLA.setWispAlive(thread, true); // thread.isAlive() should be true
+ WispEngine.current().startAsThread(thread, thread.getName(), thread);
+ return true;
+ }
+
+ /**
+ * Refer to hotspot JavaThread::exit():
+ *
+ * 1. Call Thread.exit() to clean up threadGroup
+ * 2. Notify threads wait on Thread.join()
+ * 3. exit jvm if all non-daemon thread is exited
+ *
+ * @param thread exited thread
+ */
+ static void exit(Thread thread) {
+ WispEngine.JLA.threadExit(thread);
+ synchronized (thread) {
+ thread.notifyAll();
+ }
+ if (!thread.isDaemon()) {
+ synchronized (ThreadAsWisp.class) {
+ if (--nonDaemonCount == 0) {
+ assert preventShutdownThread != null && !preventShutdownThread.isInterrupted();
+ preventShutdownThread.interrupt();
+ preventShutdownThread = null;
+ }
+ }
+ }
+ }
+
+ private static boolean matchBlackList(Thread thread, Runnable target) {
+ return Stream.concat(Stream.of(JAVA_LANG_PKG), WispConfiguration.getThreadAsWispBlacklist().stream())
+ .anyMatch(s -> {
+ Class> clazz = (target == null ? thread : target).getClass();
+ // Java code could start a thread by passing a `target` Runnable argument
+ // or override Thread.run() method;
+ // if `target` is null, we're processing the override situation, so we need
+ // to check the thread object's class.
+ String[] sp = s.split(":");
+ if (sp.length != 2) {
+ return false;
+ }
+ switch (sp[0]) {
+ case "class":
+ return sp[1].equals(clazz.getName());
+ case "package":
+ Package pkg = clazz.getPackage();
+ String pkgName = pkg == null ? "" : pkg.getName();
+ return sp[1].equals(pkgName);
+ case "name":
+ return wildCardMatch(thread.getName(), sp[1]);
+ default:
+ return false;
+ }
+ });
+ }
+
+ private static boolean wildCardMatch(String s, String p) {
+ return s.matches(p.replace("?", ".?").replace("*", ".*"));
+ }
+
+
+ private static class PreventShutdownThread extends Thread {
+ // help us monitor if PreventShutdownThread start/exit too much times.
+ // startCount should very close to 1 for most applications
+ private static int startCount;
+
+ private PreventShutdownThread() {
+ super(WispEngine.DAEMON_THREAD_GROUP, "Wisp-Prevent-Shutdown-" + startCount++);
+ setDaemon(false); // the daemon attribute is inherited from parent, set to false explicitly
+ }
+
+ @Override
+ public synchronized void run() {
+ while (true) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ } // class PreventShutdownThread
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/TimeOut.java b/src/linux/classes/com/alibaba/wisp/engine/TimeOut.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9f78b4194d1b33216c3c1ddf202e3f1bc45e3e9
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/TimeOut.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Represents {@link WispTask} related time out
+ */
+public class TimeOut {
+ final WispTask task;
+ long deadlineNano;
+ boolean canceled = false;
+ /**
+ * its position in the heapArray, -1 indicates that TimeOut has been deleted
+ */
+ private final boolean fromJvm;
+ private int queueIdx;
+ private TimerManager manager;
+
+ /**
+ * @param task related {@link WispTask}
+ * @param deadlineNano wake up related {@link WispTask} at {@code deadline} if not canceled
+ */
+ public TimeOut(WispTask task, long deadlineNano, boolean fromJvm) {
+ this.task = task;
+ this.deadlineNano = deadlineNano;
+ this.fromJvm = fromJvm;
+ }
+
+ /**
+ * @return {@code true} if and only if associated timer is expired.
+ */
+ public boolean expired() {
+ return !canceled && System.nanoTime() >= deadlineNano;
+ }
+
+ /**
+ * unpark the blocked task
+ */
+ void doUnpark() {
+ if (fromJvm) {
+ task.unpark();
+ } else {
+ task.jdkUnpark();
+ }
+ }
+
+ /**
+ * We use minimum heap algorithm to get the minimum deadline of all timers,
+ * also keep every TimeOut's queueIdx(its position in heap) so that we can easily
+ * remove it.
+ */
+ static class TimerManager {
+ Queue queue = new Queue();
+ ConcurrentLinkedQueue rmQ = new ConcurrentLinkedQueue<>();
+
+ void copyTimer(Queue copiedQueue) {
+ copiedQueue.size = 0;
+ for (TimeOut timeOut : copiedQueue.queue) {
+ if (timeOut != null) {
+ addTimer(timeOut);
+ }
+ }
+ }
+
+ void addTimer(TimeOut timeOut) {
+ timeOut.deadlineNano = overflowFree(timeOut.deadlineNano, queue.peek());
+ timeOut.manager = this;
+ queue.offer(timeOut);
+ }
+
+ void cancelTimer(TimeOut timeOut) {
+ if (timeOut.queueIdx != -1) {
+ if (timeOut.manager == this) {
+ queue.remove(timeOut);
+ } else {
+ timeOut.manager.rmQ.add(timeOut);
+ }
+ }
+ }
+
+ /**
+ * Dispatch timeout events and return the timeout deadline for next
+ * first timeout task
+ *
+ * @return -1: there's no timeout task, > 0 deadline nanos
+ */
+ long processTimeoutEventsAndGetWaitDeadline(final long now) {
+ TimeOut timeOut;
+ while ((timeOut = rmQ.poll()) != null) {
+ assert timeOut.manager == this;
+ queue.remove(timeOut);
+ }
+
+ long deadline = -1;
+ if (queue.size != 0) {
+ while ((timeOut = queue.peek()) != null) {
+ if (timeOut.canceled) {
+ queue.poll();
+ } else if (timeOut.deadlineNano <= now) {
+ queue.poll();
+ timeOut.doUnpark();
+ } else {
+ deadline = timeOut.deadlineNano;
+ break;
+ }
+ }
+ }
+ return deadline;
+ }
+
+ static class Queue {
+ private static final int INITIAL_CAPACITY = 16;
+ private TimeOut[] queue = new TimeOut[INITIAL_CAPACITY];
+ private int size = 0;
+
+ /**
+ * Inserts TimeOut x at position k, maintaining heap invariant by
+ * promoting x up the tree until it is greater than or equal to
+ * its parent, or is the root.
+ *
+ * @param k the position to fill
+ * @param timeOut the TimeOut to insert
+ */
+ private void siftUp(int k, TimeOut timeOut) {
+ while (k > 0) {
+ int parent = (k - 1) >>> 1;
+ TimeOut e = queue[parent];
+ if (timeOut.deadlineNano >= e.deadlineNano) {
+ break;
+ }
+ queue[k] = e;
+ e.queueIdx = k;
+ k = parent;
+ }
+ queue[k] = timeOut;
+ timeOut.queueIdx = k;
+ }
+
+ /**
+ * Inserts item x at position k, maintaining heap invariant by
+ * demoting x down the tree repeatedly until it is less than or
+ * equal to its children or is a leaf.
+ *
+ * @param k the position to fill
+ * @param timeOut the item to insert
+ */
+ private void siftDown(int k, TimeOut timeOut) {
+ int half = size >>> 1;
+ while (k < half) {
+ int child = (k << 1) + 1;
+ TimeOut c = queue[child];
+ int right = child + 1;
+ if (right < size && c.deadlineNano > queue[right].deadlineNano) {
+ c = queue[child = right];
+ }
+ if (timeOut.deadlineNano <= c.deadlineNano) {
+ break;
+ }
+ queue[k] = c;
+ c.queueIdx = k;
+ k = child;
+ }
+ queue[k] = timeOut;
+ timeOut.queueIdx = k;
+ }
+
+
+ public boolean remove(TimeOut timeOut) {
+ int i = timeOut.queueIdx;
+ if (i == -1) {
+ //this timeOut has been deleted.
+ return false;
+ }
+
+ queue[i].queueIdx = -1;
+ int s = --size;
+ TimeOut replacement = queue[s];
+ queue[s] = null;
+ if (s != i) {
+ siftDown(i, replacement);
+ if (queue[i] == replacement) {
+ siftUp(i, replacement);
+ }
+ }
+ return true;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ public boolean offer(TimeOut timeOut) {
+ int i = size++;
+ if (i >= queue.length) {
+ queue = Arrays.copyOf(queue, queue.length * 2);
+ }
+ if (i == 0) {
+ queue[0] = timeOut;
+ timeOut.queueIdx = 0;
+ } else {
+ siftUp(i, timeOut);
+ }
+ return true;
+ }
+
+ public TimeOut poll() {
+ if (size == 0) {
+ return null;
+ }
+ TimeOut f = queue[0];
+ int s = --size;
+ TimeOut x = queue[s];
+ queue[s] = null;
+ if (s != 0) {
+ siftDown(0, x);
+ }
+ f.queueIdx = -1;
+ return f;
+ }
+
+ public TimeOut peek() {
+ return queue[0];
+ }
+ }
+ }
+
+ private static long overflowFree(long deadlineNano, TimeOut head) {
+ if (deadlineNano < Long.MIN_VALUE / 2) { // deadlineNano regarded as negative overflow
+ deadlineNano = Long.MAX_VALUE;
+ }
+ if (head != null && head.deadlineNano < 0 && deadlineNano > 0 && deadlineNano - head.deadlineNano < 0) {
+ deadlineNano = Long.MAX_VALUE + head.deadlineNano;
+ // then deadlineNano - head.deadlineNano = Long.MAX_VALUE > 0
+ // i.e. deadlineNano > head.deadlineNano
+ }
+ return deadlineNano;
+ }
+
+ static long nanos2Millis(long nanos) {
+ long ms = TimeUnit.NANOSECONDS.toMillis(nanos + TimeUnit.MILLISECONDS.toNanos(1) / 2);
+ if (ms < 0) {
+ ms = 0;
+ }
+ if (WispConfiguration.PARK_ONE_MS_AT_LEAST && ms == 0) {
+ ms = 1;
+ }
+ return ms;
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispCarrier.java b/src/linux/classes/com/alibaba/wisp/engine/WispCarrier.java
new file mode 100644
index 0000000000000000000000000000000000000000..5feecf8bc3aa1e084f5f17edd4089e3116934fb2
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispCarrier.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import java.dyn.Coroutine;
+import java.dyn.CoroutineSupport;
+import java.io.IOException;
+import java.nio.channels.SelectableChannel;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+
+/**
+ * {@link WispCarrier} schedules all {@link WispTask} on according worker and control their life cycle
+ * {@link WispCarrier} exposed its scheduling function for wisp inner usage and maintained all thread local
+ * schedule info, such as current active {@link WispTask} and thread local task cache, etc.
+ *
+ * A {@link WispCarrier} instance is expected to run in a specific worker. Get per-thread instance by calling
+ * {@link WispCarrier#current()}.
+ */
+final class WispCarrier implements Comparable {
+
+ private static final AtomicIntegerFieldUpdater TASK_COUNT_UPDATER =
+ AtomicIntegerFieldUpdater.newUpdater(WispEngine.class, "runningTaskCount");
+
+ /**
+ * The user can only can only get thread-specific carrier by calling this method.
+ *
+ * We can not use ThreadLocal any more, because if transparentAsync, it behaves as a coroutine local.
+ *
+ * @return thread-specific carrier
+ */
+ static WispCarrier current() {
+ Thread thread = WispEngine.JLA.currentThread0();
+ WispTask current = WispEngine.JLA.getWispTask(thread);
+ if (current == null) {
+ WispCarrier carrier = new WispCarrier(WispEngine.WISP_ROOT_ENGINE);
+ if (carrier.threadTask.ctx != null) {
+ WispEngine.JLA.setWispTask(thread, carrier.getCurrentTask());
+ carrier.init();
+ } // else: fake carrier used in jni attach
+ return carrier;
+ } else {
+ return current.carrier;
+ }
+ }
+
+ // thread, threadTask and worker are 1:1:1 related
+ WispScheduler.Worker worker;
+ final Thread thread;
+ private final WispTask threadTask;
+ WispEngine engine;
+ // current running task
+ WispTask current;
+ private final List taskCache = new ArrayList<>();
+ boolean isInCritical;
+ WispCounter counter;
+ int schedTick;
+ int lastSchedTick; // access by Sysmon
+ boolean terminated;
+ private long switchTimestamp = 0;
+ private WispTask yieldingTask;
+ private TimeOut pendingTimer;
+
+ private WispCarrier(WispEngine engine) {
+ thread = WispEngine.JLA.currentThread0();
+ this.engine = engine;
+ CoroutineSupport cs = thread.getCoroutineSupport();
+ current = threadTask = new WispTask(this,
+ cs == null ? null : cs.threadCoroutine(),
+ cs != null, true);
+ if (cs == null) { // fake carrier used in jni attach
+ threadTask.setThreadWrapper(thread);
+ } else {
+ threadTask.reset(null, "THREAD: " + thread.getName(), thread, thread.getContextClassLoader());
+ }
+ }
+
+ /**
+ * Use 2nd-phase init after constructor. Because if constructor calls Thread.currentThread(),
+ * and recursive calls constructor, then stackOverflow.
+ */
+ private void init() {
+ WispTask.trackTask(threadTask);
+ counter = WispCounter.create(this);
+ }
+
+ /**
+ * @return Currently running WispTask. Ensured by {@link #yieldTo(WispTask)}
+ * If calling in a non-coroutine environment, return a thread-emulated WispTask.
+ */
+ WispTask getCurrentTask() {
+ return current;
+ }
+
+ /**
+ * Each WispCarrier has a corresponding worker. Thread can't be changed for WispCarrier.
+ * Use thread id as WispCarrier id.
+ *
+ * @return WispCarrier id
+ */
+ long getId() {
+ assert thread != null;
+ return thread.getId();
+ }
+
+ // ----------------------------------------------- lifecycle
+
+ final WispTask runTaskInternal(Runnable target, String name, Thread thread, ClassLoader ctxLoader) {
+ if (engine.hasBeenShutdown && !WispTask.SHUTDOWN_TASK_NAME.equals(name)) {
+ throw new RejectedExecutionException("Wisp carrier has been shutdown");
+ }
+ assert current == threadTask;
+ boolean isInCritical0 = isInCritical;
+ isInCritical = true;
+ WispTask wispTask;
+ try {
+ counter.incrementCreateTaskCount();
+ if ((wispTask = getTaskFromCache()) == null) {
+ wispTask = new WispTask(this, null, true, false);
+ WispTask.trackTask(wispTask);
+ }
+ wispTask.reset(target, name, thread, ctxLoader);
+ TASK_COUNT_UPDATER.incrementAndGet(engine);
+ } finally {
+ isInCritical = isInCritical0;
+ }
+ yieldTo(wispTask);
+ runWispTaskEpilog();
+
+ return wispTask;
+ }
+
+ /**
+ * The only exit path of a task.
+ * WispTask must call {@code taskExit()} to exit safely.
+ */
+ void taskExit() { // and exit
+ current.status = WispTask.Status.ZOMBIE;
+ TASK_COUNT_UPDATER.decrementAndGet(engine);
+
+ current.countExecutionTime(switchTimestamp);
+ switchTimestamp = 0;
+
+ unregisterEvent();
+ returnTaskToCache(current);
+
+ // reset threadWrapper after call returnTaskToCache,
+ // since the threadWrapper will be used in Thread.currentThread()
+ current.resetThreadWrapper();
+ counter.incrementCompleteTaskCount();
+
+ // In Tenant killing process, we have an pending exception,
+ // WispTask.Coroutine's loop will be breaked
+ // invoke an explicit reschedule instead of return
+ schedule();
+ }
+
+ /**
+ * @return task from global cached theScheduler
+ */
+ private WispTask getTaskFromCache() {
+ assert WispCarrier.current() == this;
+ if (!taskCache.isEmpty()) {
+ return taskCache.remove(taskCache.size() - 1);
+ }
+ if (engine.hasBeenShutdown) {
+ return null;
+ }
+ WispTask task = engine.groupTaskCache.poll();
+ if (task == null) {
+ return null;
+ }
+ if (task.carrier != this) {
+ if (steal(task) != Coroutine.StealResult.SUCCESS) {
+ engine.groupTaskCache.add(task);
+ return null;
+ }
+ }
+ assert task.carrier == this;
+ return task;
+ }
+
+ /**
+ * return task back to global cache
+ */
+ private void returnTaskToCache(WispTask task) {
+ // reuse exited wispTasks from shutdown wispEngine is very tricky, so we'd better not return
+ // these tasks to global cache
+ if (taskCache.size() > WispConfiguration.WISP_ENGINE_TASK_CACHE_SIZE && !engine.hasBeenShutdown) {
+ engine.groupTaskCache.add(task);
+ } else {
+ taskCache.add(task);
+ }
+ }
+
+ /**
+ * hook for yield wispTask
+ */
+ private void runWispTaskEpilog() {
+ processPendingTimer();
+ processYield();
+ }
+
+ void destroy() {
+ WispTask.cleanExitedTasks(taskCache);
+ WispTask.cleanExitedTask(threadTask);
+ terminated = true;
+ }
+
+ // ------------------------------------------ scheduling
+
+ /**
+ * Block current coroutine and do scheduling.
+ * Typically called when resource is not ready.
+ */
+ final void schedule() {
+ assert WispCarrier.current() == this;
+ WispTask current = this.current;
+ current.countExecutionTime(switchTimestamp);
+ assert current != threadTask;
+ assert current.resumeEntry != null : "call `schedule()` in scheduler";
+ current.resumeEntry.setStealEnable(true);
+ yieldTo(threadTask); // letting the scheduler choose runnable task
+ if (engine.hasBeenShutdown && current != threadTask
+ && !WispTask.SHUTDOWN_TASK_NAME.equals(current.getName())) {
+ CoroutineSupport.checkAndThrowException(current.ctx);
+ }
+ }
+
+ /**
+ * Wake up a {@link WispTask} that belongs to this carrier
+ *
+ * @param task target task
+ */
+ void wakeupTask(WispTask task) {
+ assert !task.isThreadTask();
+ assert task.resumeEntry != null;
+ assert task.carrier == this;
+ task.updateEnqueueTime();
+ engine.scheduler.executeWithWorkerThread(task.resumeEntry, thread);
+ }
+
+ /**
+ * create a Entry runnable for wisp task,
+ * used for bridge coroutine and Executor interface.
+ */
+ StealAwareRunnable createResumeEntry(WispTask task) {
+ assert !task.isThreadTask();
+ return new StealAwareRunnable() {
+ boolean stealEnable = true;
+
+ @Override
+ public void run() {
+ WispCarrier current = WispCarrier.current();
+ /*
+ * Please be extremely cautious:
+ * task.carrier can not be changed here by other thread
+ * is based on our implementation of using park instead of
+ * direct schedule, so only one thread could receive
+ * this closure.
+ */
+ WispCarrier source = task.carrier;
+ if (source != current) {
+ Coroutine.StealResult res = current.steal(task);
+ if (res != Coroutine.StealResult.SUCCESS) {
+ if (res != Coroutine.StealResult.FAIL_BY_CONTENTION) {
+ stealEnable = false;
+ }
+ source.wakeupTask(task);
+ return;
+ }
+ // notify detached empty worker to exit
+ if (source.worker.hasBeenHandoff && TASK_COUNT_UPDATER.get(source.engine) == 0) {
+ source.worker.signal();
+ }
+ }
+ current.countEnqueueTime(task.getEnqueueTime());
+ task.resetEnqueueTime();
+ if (current.yieldTo(task)) {
+ current.runWispTaskEpilog();
+ } else { // switch failure
+ // this is unexpected, record in counter to help troubleshooting.
+ // The actual behavior of switch failure is similar to unpark lost,
+ // so we re-enqueue the entry for compensation.
+ resumeFailure++;
+ current.wakeupTask(task);
+ }
+ }
+
+ @Override
+ public void setStealEnable(boolean b) {
+ stealEnable = b;
+ }
+
+ @Override
+ public boolean isStealEnable() {
+ return stealEnable;
+ }
+ };
+ }
+
+ private static int resumeFailure = 0;
+
+ /**
+ * Steal task from it's current bond carrier to this carrier
+ *
+ * @return steal result
+ */
+ private Coroutine.StealResult steal(WispTask task) {
+ /* shutdown is an async operation in wisp2, SHUTDOWN task relies on runningTaskCount to
+ determine whether it's okay to exit the worker, hence we need to make sure no more new
+ wispTasks are created or stolen for hasBeenShutdown engines
+ for example:
+ 1. SHUTDOWN task found runningTaskCount equals 0 and exit
+ 2. worker's task queue may still has some remaining tasks, when tried to steal these tasks
+ we may encounter jvm crash.
+ */
+ if (engine.hasBeenShutdown) {
+ return Coroutine.StealResult.FAIL_BY_STATUS;
+ }
+
+ assert WispCarrier.current() == this;
+ assert !task.isThreadTask();
+ if (task.carrier != this) {
+ while (task.stealLock != 0) {/* wait until steal enabled */}
+ Coroutine.StealResult res = task.ctx.steal(true);
+ if (res != Coroutine.StealResult.SUCCESS) {
+ task.stealFailureCount++;
+ return res;
+ }
+ task.stealCount++;
+ task.setCarrier(this);
+ }
+ return Coroutine.StealResult.SUCCESS;
+ }
+
+ /**
+ * The ONLY entry point to a task,
+ * {@link #current} will be set correctly
+ *
+ * @param task coroutine to run
+ */
+ private boolean yieldTo(WispTask task) {
+ assert task != null;
+ assert WispCarrier.current() == this;
+ assert task.carrier == this;
+ assert task != current;
+
+ schedTick++;
+
+ if (task.status == WispTask.Status.ZOMBIE) {
+ unregisterEvent(task);
+ return false;
+ }
+
+ WispTask from = current;
+ current = task;
+ counter.incrementSwitchCount();
+ switchTimestamp = WispEngine.getNanoTime();
+ assert !isInCritical;
+ boolean res = WispTask.switchTo(from, task);
+ assert res : "coroutine switch failure";
+ // Since carrier is changed with stealing,
+ // we shouldn't directly access carrier's member any more.
+ assert WispCarrier.current().current == from;
+ assert !from.carrier.isInCritical;
+ return res;
+ }
+
+ /**
+ * Telling to the scheduler that the current carrier is willing to yield
+ * its current use of a processor.
+ *
+ * Called by {@link Thread#yield()}
+ */
+ void yield() {
+ if (!WispConfiguration.WISP_HIGH_PRECISION_TIMER && worker != null) {
+ worker.processTimer();
+ }
+ if (WispEngine.runningAsCoroutine(current.getThreadWrapper())) {
+ if (getTaskQueueLength() > 0) {
+ assert yieldingTask == null;
+ yieldingTask = current;
+ // delay it, make sure wakeupTask is called after yield out
+ schedule();
+ }
+ } else {
+ WispEngine.JLA.yield0();
+ }
+ }
+
+ private void processYield() {
+ assert current.isThreadTask();
+ if (yieldingTask != null) {
+ wakeupTask(yieldingTask);
+ yieldingTask = null;
+ }
+ }
+
+ // ------------------------------------------------ IO
+
+ /**
+ * Modify current {@link WispTask}'s interest channel and event.
+ * {@see registerEvent(...)}
+ *
+ * Used for implementing socket io
+ *
+ * while (!ch.read(buf) == 0) { // 0 indicate IO not ready, not EOF..
+ * registerEvent(ch, OP_READ);
+ * schedule();
+ * }
+ * // read is done here
+ *
+ */
+ void registerEvent(SelectableChannel ch, int events) throws IOException {
+ registerEvent(current, ch, events);
+ }
+
+
+ /**
+ * register target {@link WispTask}'s interest channel and event.
+ *
+ * @param ch the channel that is related to the current WispTask
+ * @param events interest event
+ */
+ private void registerEvent(WispTask target, SelectableChannel ch, int events) throws IOException {
+ if (ch != null && ch.isOpen() && events != 0) {
+ WispEventPump.Pool.INSTANCE.registerEvent(target, ch, events);
+ }
+ }
+
+ /**
+ * Clean current task's interest event before an non-IO blocking operation
+ * or task exit to prevent unexpected wake up.
+ */
+ void unregisterEvent() {
+ unregisterEvent(current);
+ }
+
+ private void unregisterEvent(WispTask target) {
+ if (target.ch != null) {
+ target.resetRegisterEventTime();
+ target.ch = null;
+ }
+ }
+
+ // ------------------------------------------------ timer support
+
+ /**
+ * Add a timer for current {@link WispTask},
+ * used for implementing timed IO operation / sleep etc...
+ *
+ * @param deadlineNano deadline of the timer
+ * @param fromJvm synchronized or obj.wait()
+ */
+ void addTimer(long deadlineNano, boolean fromJvm) {
+ WispTask task = current;
+ TimeOut timeOut = new TimeOut(task, deadlineNano, fromJvm);
+ task.timeOut = timeOut;
+
+ if (WispConfiguration.WISP_HIGH_PRECISION_TIMER) {
+ if (task.isThreadTask()) {
+ scheduleInTimer(timeOut);
+ } else {
+ /*
+ * timer.schedule may enter park() again
+ * we delegate this operation to thread coroutine
+ * (which always use native park)
+ */
+ pendingTimer = timeOut;
+ }
+ } else {
+ engine.scheduler.addTimer(timeOut, thread);
+ }
+ }
+
+ /**
+ * Cancel the timer added by {@link #addTimer(long, boolean)}.
+ */
+ void cancelTimer() {
+ if (current.timeOut != null) {
+ current.timeOut.canceled = true;
+ if (!WispConfiguration.WISP_HIGH_PRECISION_TIMER) {
+ engine.scheduler.cancelTimer(current.timeOut, thread);
+ }
+ current.timeOut = null;
+ }
+ pendingTimer = null;
+ }
+
+ private void processPendingTimer() {
+ assert current.isThreadTask();
+ if (WispConfiguration.WISP_HIGH_PRECISION_TIMER && pendingTimer != null) {
+ scheduleInTimer(pendingTimer);
+ pendingTimer = null;
+ }
+ }
+
+ private void scheduleInTimer(TimeOut timeOut) {
+ boolean isInCritical0 = isInCritical;
+ final long timeout = timeOut.deadlineNano - System.nanoTime();
+ isInCritical = true;
+ if (timeout > 0) {
+ WispEngine.timer.schedule(new Runnable() {
+ @Override
+ public void run() {
+ if (!timeOut.canceled) {
+ timeOut.doUnpark();
+ }
+ }
+ }, timeout, TimeUnit.NANOSECONDS);
+ } else if (!timeOut.canceled) {
+ timeOut.task.jdkUnpark();
+ }
+ isInCritical = isInCritical0;
+ }
+
+ // ----------------------------------------------- status fetch
+
+ /**
+ * @return if current carrier is busy
+ */
+ boolean isRunning() {
+ return current != threadTask;
+ }
+
+ /**
+ * @return queue length. used for mxBean report
+ */
+ int getTaskQueueLength() {
+ if (worker == null) {
+ return 0;
+ }
+ int ql = worker.queueLength;
+ // use a local copy to avoid queueLength change to negative.
+ return Math.max(ql, 0);
+ }
+
+ /**
+ * @return running task number, used for mxBean report
+ */
+ int getRunningTaskCount() {
+ return engine.runningTaskCount;
+ }
+
+ // ----------------------------------------------- retake
+
+ /**
+ * hand off wispEngine for blocking system calls.
+ */
+ void handOff() {
+ engine.scheduler.handOffWorkerThread(thread);
+ }
+
+ // ----------------------------------------------- Monitoring
+
+ WispCounter getCounter() {
+ return counter;
+ }
+
+ void countEnqueueTime(long enqueueTime) {
+ if (enqueueTime != 0) {
+ counter.incrementTotalEnqueueTime(System.nanoTime() - enqueueTime);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "WispCarrier on " + thread.getName();
+ }
+
+ @Override
+ public int compareTo(WispCarrier o) {
+ return Long.compare(getId(), o.getId());
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispConfiguration.java b/src/linux/classes/com/alibaba/wisp/engine/WispConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..dede8fe3909d7cba6d5fb1962663eea4ae2e8782
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispConfiguration.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.security.action.GetPropertyAction;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+class WispConfiguration {
+ private static final String DELIMITER = ";";
+
+ static final boolean TRANSPARENT_WISP_SWITCH;
+ static final boolean ENABLE_THREAD_AS_WISP;
+ static final boolean ALL_THREAD_AS_WISP;
+
+ static final int STACK_SIZE;
+ static final boolean PARK_ONE_MS_AT_LEAST;
+ static final int WORKER_COUNT;
+ static final boolean ENABLE_HANDOFF;
+ static final WispSysmon.Policy HANDOFF_POLICY;
+ static final int SYSMON_TICK_US;
+ static final int MIN_PARK_NANOS;
+ static final int POLLER_SHARDING_SIZE;
+
+ static final int SYSMON_CARRIER_GROW_TICK_US;
+ // monitor
+ static final boolean WISP_PROFILE;
+ static final boolean WISP_PROFILE_LOG_ENABLED;
+ static final int WISP_PROFILE_LOG_INTERVAL_MS;
+ static final String WISP_PROFILE_LOG_PATH;
+
+ static final boolean WISP_HIGH_PRECISION_TIMER;
+ static final int WISP_ENGINE_TASK_CACHE_SIZE;
+ static final int WISP_SCHEDULE_STEAL_RETRY;
+ static final int WISP_SCHEDULE_PUSH_RETRY;
+ static final int WISP_SCHEDULE_HELP_STEAL_RETRY;
+ static final WispScheduler.SchedulingPolicy SCHEDULING_POLICY;
+ static final boolean USE_DIRECT_SELECTOR_WAKEUP;
+ static final boolean CARRIER_AS_POLLER;
+ static final boolean MONOLITHIC_POLL;
+ static final boolean CARRIER_GROW;
+
+ // io
+ static final boolean WISP_ENABLE_SOCKET_LOCK;
+
+ private static List THREAD_AS_WISP_BLACKLIST;
+
+
+ static {
+ Properties p = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+ );
+
+ TRANSPARENT_WISP_SWITCH = p.containsKey("com.alibaba.wisp.transparentWispSwitch") ?
+ parseBooleanParameter(p, "com.alibaba.wisp.transparentWispSwitch", false) :
+ parseBooleanParameter(p, "com.alibaba.transparentAsync", false);
+ ENABLE_THREAD_AS_WISP = p.containsKey("com.alibaba.wisp.enableThreadAsWisp") ?
+ parseBooleanParameter(p, "com.alibaba.wisp.enableThreadAsWisp", false) :
+ parseBooleanParameter(p, "com.alibaba.shiftThreadModel", false);
+ ALL_THREAD_AS_WISP = parseBooleanParameter(p, "com.alibaba.wisp.allThreadAsWisp", false);
+ STACK_SIZE = parsePositiveIntegerParameter(p, "com.alibaba.wisp.stacksize", 512 * 1024);
+ PARK_ONE_MS_AT_LEAST = parseBooleanParameter(p, "com.alibaba.wisp.parkOneMs", true);
+ WORKER_COUNT = parsePositiveIntegerParameter(p, "com.alibaba.wisp.carrierEngines",
+ Runtime.getRuntime().availableProcessors());
+ POLLER_SHARDING_SIZE = parsePositiveIntegerParameter(p, "com.alibaba.pollerShardingSize", 8);
+ ENABLE_HANDOFF = parseBooleanParameter(p, "com.alibaba.wisp.enableHandOff",
+ TRANSPARENT_WISP_SWITCH);
+ // handoff worker thread implementation is not stable enough,
+ // use preempt by default, and we'll move to ADAPTIVE in the future
+ HANDOFF_POLICY = WispSysmon.Policy.valueOf(
+ p.getProperty("com.alibaba.wisp.handoffPolicy", WispSysmon.Policy.PREEMPT.name()));
+ SYSMON_TICK_US = parsePositiveIntegerParameter(p, "com.alibaba.wisp.sysmonTickUs",
+ (int) TimeUnit.MILLISECONDS.toMicros(100));
+ MIN_PARK_NANOS = parsePositiveIntegerParameter(p, "com.alibaba.wisp.minParkNanos", 100);
+ WISP_PROFILE_LOG_ENABLED = parseBooleanParameter(p, "com.alibaba.wisp.enableProfileLog", false);
+ WISP_PROFILE_LOG_INTERVAL_MS = parsePositiveIntegerParameter(p, "com.alibaba.wisp.logTimeInternalMillis", 15000);
+ if (WISP_PROFILE_LOG_ENABLED) {
+ WISP_PROFILE = true;
+ WISP_PROFILE_LOG_PATH = p.getProperty("com.alibaba.wisp.logPath");
+ } else {
+ WISP_PROFILE = parseBooleanParameter(p, "com.alibaba.wisp.profile", false);
+ WISP_PROFILE_LOG_PATH = "";
+ }
+
+ CARRIER_AS_POLLER = parseBooleanParameter(p, "com.alibaba.wisp.useCarrierAsPoller", ALL_THREAD_AS_WISP);
+ MONOLITHIC_POLL = parseBooleanParameter(p, "com.alibaba.wisp.monolithicPoll", true);
+ WISP_HIGH_PRECISION_TIMER = parseBooleanParameter(p, "com.alibaba.wisp.highPrecisionTimer", false);
+ WISP_ENGINE_TASK_CACHE_SIZE = parsePositiveIntegerParameter(p, "com.alibaba.wisp.engineTaskCache", 20);
+ WISP_SCHEDULE_STEAL_RETRY = parsePositiveIntegerParameter(p, "com.alibaba.wisp.schedule.stealRetry", Math.max(1, WORKER_COUNT / 2));
+ WISP_SCHEDULE_PUSH_RETRY = parsePositiveIntegerParameter(p, "com.alibaba.wisp.schedule.pushRetry", WORKER_COUNT);
+ WISP_SCHEDULE_HELP_STEAL_RETRY = parsePositiveIntegerParameter(p, "com.alibaba.wisp.schedule.helpStealRetry", Math.max(1, WORKER_COUNT / 4));
+ SCHEDULING_POLICY = WispScheduler.SchedulingPolicy.valueOf(p.getProperty("com.alibaba.wisp.schedule.policy",
+ WORKER_COUNT > 16 ? WispScheduler.SchedulingPolicy.PUSH.name() : WispScheduler.SchedulingPolicy.PULL.name()));
+ USE_DIRECT_SELECTOR_WAKEUP = parseBooleanParameter(p, "com.alibaba.wisp.directSelectorWakeup", true);
+ WISP_ENABLE_SOCKET_LOCK = parseBooleanParameter(p, "com.alibaba.wisp.useSocketLock", true);
+ CARRIER_GROW = parseBooleanParameter(p, "com.alibaba.wisp.growCarrier", false);
+ SYSMON_CARRIER_GROW_TICK_US = parsePositiveIntegerParameter(p, "com.alibaba.wisp.growCarrierTickUs", (int) TimeUnit.SECONDS.toMicros(5));
+ checkCompatibility();
+ }
+
+ private static void checkCompatibility() {
+ checkDependency(ENABLE_THREAD_AS_WISP, "-Dcom.alibaba.wisp.enableThreadAsWisp=true",
+ TRANSPARENT_WISP_SWITCH, "-Dcom.alibaba.wisp.transparentWispSwitch=true");
+ checkDependency(ENABLE_HANDOFF, "-Dcom.alibaba.wisp.enableHandOff=true",
+ TRANSPARENT_WISP_SWITCH, "-Dcom.alibaba.wisp.enableThreadAsWisp=true");
+ checkDependency(ALL_THREAD_AS_WISP, "-Dcom.alibaba.wisp.allThreadAsWisp=true",
+ ENABLE_THREAD_AS_WISP, "-Dcom.alibaba.wisp.enableThreadAsWisp=true");
+ checkDependency(CARRIER_AS_POLLER, "-Dcom.alibaba.wisp.useCarrierAsPoller=true",
+ ALL_THREAD_AS_WISP, "-Dcom.alibaba.wisp.allThreadAsWisp=true");
+ if (ENABLE_THREAD_AS_WISP && !ALL_THREAD_AS_WISP) {
+ throw new IllegalArgumentException("shift thread model by stack configuration is no longer supported," +
+ " use -XX:+UseWisp2 instead");
+ }
+ }
+
+ private static void checkDependency(boolean cond, String condStr, boolean preRequire, String preRequireStr) {
+ if (cond && !preRequire) {
+ throw new IllegalArgumentException("\"" + condStr + "\" depends on \"" + preRequireStr + "\"");
+ }
+ }
+
+ private static int parsePositiveIntegerParameter(Properties p, String key, int defaultVal) {
+ String value;
+ if (p == null || (value = p.getProperty(key)) == null) {
+ return defaultVal;
+ }
+ int res = defaultVal;
+ try {
+ res = Integer.valueOf(value);
+ } catch (NumberFormatException e) {
+ return defaultVal;
+ }
+ return res <= 0 ? defaultVal : res;
+ }
+
+ private static boolean parseBooleanParameter(Properties p, String key, boolean defaultVal) {
+ String value;
+ if (p == null || (value = p.getProperty(key)) == null) {
+ return defaultVal;
+ }
+ return Boolean.valueOf(value);
+ }
+
+ private static List parseListParameter(Properties p, Properties confProp, String key) {
+ String value = p.getProperty(key);
+ if (value == null) {
+ value = confProp.getProperty(key);
+ }
+ return value == null ? Collections.emptyList() :
+ Arrays.asList(value.trim().split(DELIMITER));
+ }
+
+ /**
+ * Loading config from system property "com.alibaba.wisp.config" specified
+ * file or jre/lib/wisp.properties.
+ */
+ private static void loadBizConfig() {
+ Properties p = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+ );
+ String path = p.getProperty("com.alibaba.wisp.config");
+
+ Properties confProp = new Properties();
+ if (path != null) {
+ File f = new File(path);
+ if (f.exists()) {
+ try (InputStream is = new BufferedInputStream(new FileInputStream(f.getPath()))) {
+ confProp.load(is);
+ } catch (IOException e) {
+ // ignore, all STACK_LIST are empty
+ }
+ }
+ }
+ THREAD_AS_WISP_BLACKLIST = parseListParameter(p, confProp, "com.alibaba.wisp.threadAsWisp.black");
+
+ }
+
+ private static final int UNLOADED = 0, LOADING = 1, LOADED = 2;
+ private static final AtomicInteger bizLoadStatus = new AtomicInteger(UNLOADED);
+
+ private static void ensureBizConfigLoaded() {
+ if (bizLoadStatus.get() == LOADED) {
+ return;
+ }
+ if (bizLoadStatus.get() == UNLOADED && bizLoadStatus.compareAndSet(UNLOADED, LOADING)) {
+ try {
+ loadBizConfig();
+ } finally {
+ bizLoadStatus.set(LOADED);
+ }
+ }
+ while (bizLoadStatus.get() != LOADED) {/* wait */}
+ }
+
+ static List getThreadAsWispBlacklist() {
+ ensureBizConfigLoaded();
+ assert THREAD_AS_WISP_BLACKLIST != null;
+ return THREAD_AS_WISP_BLACKLIST;
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispCounter.java b/src/linux/classes/com/alibaba/wisp/engine/WispCounter.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d37f92e0e4acf18cab1d3a06edda353b6953536
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispCounter.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import java.beans.ConstructorProperties;
+
+final public class WispCounter {
+
+ private long switchCount = 0;
+
+ private long waitTimeTotal = 0;
+
+ private long runningTimeTotal = 0;
+
+ private long completedTaskCount = 0;
+
+ private long createTaskCount = 0;
+
+ private long parkCount = 0;
+
+ private long unparkCount = 0;
+
+ private long unparkInterruptSelectorCount = 0;
+
+ private long selectableIOCount = 0;
+
+ private long timeOutCount = 0;
+
+ private long eventLoopCount = 0;
+
+ private long totalEnqueueTime = 0;
+
+ private long maxEnqueueTime = 0;
+
+ private long enqueueCount = 0;
+
+ private long totalExecutionTime = 0;
+
+ private long maxExecutionTime = 0;
+
+ private long executionCount = 0;
+
+ private long totalWaitSocketIOTime = 0;
+
+ private long maxWaitSocketIOTime = 0;
+
+ private long waitSocketIOCount = 0;
+
+ private long totalBlockingTime = 0;
+
+ private long maxBlockingTime = 0;
+
+ private long unparkFromJvmCount = 0;
+
+ private long runningTaskCount = 0;
+
+ private long taskQueueLength = 0;
+
+ WispCarrier carrier;
+
+ private WispCounter(WispCarrier carrier) {
+ this.carrier = carrier;
+ }
+
+ boolean getRunningState() {
+ WispCarrier e = carrier;
+ return e != null && e.isRunning();
+ }
+
+ void incrementSwitchCount() {
+ switchCount++;
+ }
+
+ long getSwitchCount() {
+ return switchCount;
+ }
+
+ void incrementCompleteTaskCount() {
+ completedTaskCount++;
+ }
+
+ void incrementRunningTimeTotal(long value) {
+ runningTimeTotal += value;
+ }
+
+ long getRunningTimeTotal() {
+ return runningTimeTotal;
+ }
+
+ void incrementWaitTime(long value) {
+ waitTimeTotal += value;
+ }
+
+ long getWaitTimeTotal() {
+ return waitTimeTotal;
+ }
+
+ public long getCompletedTaskCount() {
+ return completedTaskCount;
+ }
+
+ void incrementCreateTaskCount() {
+ createTaskCount++;
+ }
+
+ long getCreateTaskCount() {
+ return createTaskCount;
+ }
+
+ void incrementParkCount() {
+ parkCount++;
+ }
+
+ long getParkCount() {
+ return parkCount;
+ }
+
+
+ void incrementUnparkInterruptSelectorCount() {
+ unparkInterruptSelectorCount++;
+ }
+
+ long getUnparkInterruptSelectorCount() {
+ return unparkInterruptSelectorCount;
+ }
+
+ void incrementSelectableIOCount() {
+ selectableIOCount++;
+ }
+
+ long getSelectableIOCount() {
+ return selectableIOCount;
+ }
+
+ void incrementTimeOutCount() {
+ timeOutCount++;
+ }
+
+ long getTimeOutCount() {
+ return timeOutCount;
+ }
+
+ void incrementEventLoopCount() {
+ eventLoopCount++;
+ }
+
+ long getEventLoopCount() {
+ return eventLoopCount;
+ }
+
+ void incrementTotalEnqueueTime(long value) {
+ totalEnqueueTime += value;
+ enqueueCount++;
+ if (value > maxEnqueueTime) {
+ maxEnqueueTime = value;
+ }
+ }
+
+ public long getTotalEnqueueTime() {
+ return totalEnqueueTime;
+ }
+
+ public long getEnqueueCount() {
+ return enqueueCount;
+ }
+
+ void incrementTotalExecutionTime(long value) {
+ totalExecutionTime += value;
+ executionCount++;
+ if (value > maxExecutionTime) {
+ maxExecutionTime = value;
+ }
+ }
+
+ public long getTotalExecutionTime() {
+ return totalExecutionTime;
+ }
+
+ public long getExecutionCount() {
+ return executionCount;
+ }
+
+ void incrementTotalWaitSocketIOTime(long value) {
+ totalWaitSocketIOTime += value;
+ waitSocketIOCount++;
+ if (value > maxWaitSocketIOTime) {
+ maxWaitSocketIOTime = value;
+ }
+ }
+
+ public long getTotalWaitSocketIOTime() {
+ return totalWaitSocketIOTime;
+ }
+
+ public long getWaitSocketIOCount() {
+ return waitSocketIOCount;
+ }
+
+ void incrementTotalBlockingTime(long value) {
+ totalBlockingTime += value;
+ unparkCount++;
+ if (value > maxBlockingTime) {
+ maxBlockingTime = value;
+ }
+ }
+
+ public long getTotalBlockingTime() {
+ return totalBlockingTime;
+ }
+
+ public long getUnparkCount() {
+ return unparkCount;
+ }
+
+ long getCurrentTaskQueueLength() {
+ WispCarrier e = carrier;
+ return e != null ? e.getTaskQueueLength() : 0;
+ }
+
+ long getCurrentRunningTaskCount() {
+ WispCarrier e = carrier;
+ return e != null ? e.getRunningTaskCount() : 0;
+ }
+
+ void incrementUnparkFromJvmCount() {
+ unparkFromJvmCount++;
+ }
+
+ long getUnparkFromJvmCount() {
+ return unparkFromJvmCount;
+ }
+
+ public long getMaxEnqueueTime() {
+ return maxEnqueueTime;
+ }
+
+ public long getMaxExecutionTime() {
+ return maxExecutionTime;
+ }
+
+ public long getMaxWaitSocketIOTime() {
+ return maxWaitSocketIOTime;
+ }
+
+ public long getMaxBlockingTime() {
+ return maxBlockingTime;
+ }
+
+ public long getTaskQueueLength() {
+ return taskQueueLength;
+ }
+
+ public long getRunningTaskCount() {
+ return runningTaskCount;
+ }
+
+ WispCounter() {
+ }
+
+ @ConstructorProperties({"completedTaskCount", "totalEnqueueTime", "maxEnqueueTime", "enqueueCount",
+ "totalExecutionTime", "maxExecutionTime", "executionCount",
+ "totalWaitSocketIOTime", "maxWaitSocketIOTime", "waitSocketIOCount",
+ "totalBlockingTime", "maxBlockingTime", "unparkCount",
+ "runningTaskCount", "taskQueueLength"})
+ public WispCounter(long completedTaskCount, long totalEnqueueTime, long maxEnqueueTime, long enqueueCount,
+ long totalExecutionTime, long maxExecutionTime, long executionCount,
+ long totalWaitSocketIOTime, long maxWaitSocketIOTime, long waitSocketIOCount,
+ long totalBlockingTime, long maxBlockingTime, long unparkCount,
+ long runningTaskCount, long taskQueueLength) {
+ this.completedTaskCount = completedTaskCount;
+ this.totalEnqueueTime = totalEnqueueTime;
+ this.maxEnqueueTime = maxEnqueueTime;
+ this.enqueueCount = enqueueCount;
+ this.totalExecutionTime = totalExecutionTime;
+ this.maxExecutionTime = maxExecutionTime;
+ this.executionCount = executionCount;
+ this.totalWaitSocketIOTime = totalWaitSocketIOTime;
+ this.maxWaitSocketIOTime = maxWaitSocketIOTime;
+ this.waitSocketIOCount = waitSocketIOCount;
+ this.totalBlockingTime = totalBlockingTime;
+ this.maxBlockingTime = maxBlockingTime;
+ this.unparkCount = unparkCount;
+ this.runningTaskCount = runningTaskCount;
+ this.taskQueueLength = taskQueueLength;
+ }
+
+
+ void assign(WispCounter counter) {
+ createTaskCount = counter.createTaskCount;
+ completedTaskCount = counter.completedTaskCount;
+ totalEnqueueTime = counter.totalEnqueueTime;
+ enqueueCount = counter.enqueueCount;
+ maxEnqueueTime = counter.maxEnqueueTime;
+ totalExecutionTime = counter.totalExecutionTime;
+ executionCount = counter.executionCount;
+ maxExecutionTime = counter.maxExecutionTime;
+ totalBlockingTime = counter.totalBlockingTime;
+ unparkCount = counter.unparkCount;
+ maxBlockingTime = counter.maxBlockingTime;
+ totalWaitSocketIOTime = counter.totalWaitSocketIOTime;
+ waitSocketIOCount = counter.waitSocketIOCount;
+ maxWaitSocketIOTime = counter.maxWaitSocketIOTime;
+ switchCount = counter.switchCount;
+ unparkFromJvmCount = counter.unparkFromJvmCount;
+ runningTaskCount = counter.getCurrentRunningTaskCount();
+ taskQueueLength = counter.getCurrentTaskQueueLength();
+ }
+
+ void resetMaxValue() {
+ maxEnqueueTime = 0;
+ maxExecutionTime = 0;
+ maxWaitSocketIOTime = 0;
+ maxBlockingTime = 0;
+ }
+
+ void cleanup() {
+ carrier = null;
+ }
+
+ static WispCounter create(WispCarrier carrier) {
+ return new WispCounter(carrier);
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java b/src/linux/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..97529dca31a2a2b0a1346539da55d84decb42e35
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import com.alibaba.management.WispCounterMXBean;
+
+import sun.management.Util;
+
+import javax.management.ObjectName;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+/**
+ * Implementation class for WispCounterMXBean.
+ */
+public class WispCounterMXBeanImpl implements WispCounterMXBean {
+
+ private final static String WISP_COUNTER_MXBEAN_NAME = "com.alibaba.management:type=WispCounter";
+
+ private final static Map managedEngineCounters;
+
+ static {
+ if (!WispEngine.transparentWispSwitch()) {
+ managedEngineCounters = new HashMap<>();
+ } else {
+ managedEngineCounters = new ConcurrentHashMap<>(100);
+ }
+ }
+
+ @Override
+ public List getRunningStates() {
+ return aggregate(WispCounter::getRunningState);
+ }
+
+ @Override
+ public List getSwitchCount() {
+ return aggregate(WispCounter::getSwitchCount);
+ }
+
+ @Override
+ public List getWaitTimeTotal() {
+ return aggregate(WispCounter::getWaitTimeTotal);
+ }
+
+ @Override
+ public List getRunningTimeTotal() {
+ return aggregate(WispCounter::getRunningTimeTotal);
+ }
+
+ @Override
+ public List getCompleteTaskCount() {
+ return aggregate(WispCounter::getCompletedTaskCount);
+ }
+
+ @Override
+ public List getCreateTaskCount() {
+ return aggregate(WispCounter::getCreateTaskCount);
+ }
+
+ @Override
+ public List getParkCount() {
+ return aggregate(WispCounter::getParkCount);
+ }
+
+ @Override
+ public List getUnparkCount() {
+ return aggregate(WispCounter::getUnparkCount);
+ }
+
+ @Override
+ public List getLazyUnparkCount() {
+ return aggregate(w -> 0L);
+ }
+
+ @Override
+ public List getUnparkInterruptSelectorCount() {
+ return aggregate(WispCounter::getUnparkInterruptSelectorCount);
+ }
+
+ @Override
+ public List getSelectableIOCount() {
+ return aggregate(WispCounter::getSelectableIOCount);
+ }
+
+ @Override
+ public List getTimeOutCount() {
+ return aggregate(WispCounter::getTimeOutCount);
+ }
+
+ @Override
+ public List getEventLoopCount() {
+ return aggregate(WispCounter::getEventLoopCount);
+ }
+
+ @Override
+ public List getQueueLength() {
+ return aggregate(WispCounter::getCurrentTaskQueueLength);
+ }
+
+ @Override
+ public List getNumberOfRunningTasks() {
+ return aggregate(WispCounter::getCurrentRunningTaskCount);
+ }
+
+ @Override
+ public List getTotalEnqueueTime() {
+ return aggregate(WispCounter::getTotalEnqueueTime);
+ }
+
+ @Override
+ public List getEnqueueCount() {
+ return aggregate(WispCounter::getEnqueueCount);
+ }
+
+ @Override
+ public List getTotalExecutionTime() {
+ return aggregate(WispCounter::getTotalExecutionTime);
+ }
+
+ @Override
+ public List getExecutionCount() {
+ return aggregate(WispCounter::getExecutionCount);
+ }
+
+ @Override
+ public List getTotalWaitSocketIOTime() {
+ return aggregate(WispCounter::getTotalWaitSocketIOTime);
+ }
+
+ @Override
+ public List getWaitSocketIOCount() {
+ return aggregate(WispCounter::getWaitSocketIOCount);
+ }
+
+ @Override
+ public List getTotalBlockingTime() {
+ return aggregate(WispCounter::getTotalBlockingTime);
+ }
+
+ /**
+ * @param id WispCarrier id
+ * @return WispCounter
+ */
+ @Override
+ public WispCounter getWispCounter(long id) {
+ return WispEngine.getWispCounter(id);
+ }
+
+ private List aggregate(Function getter) {
+ List result = new ArrayList<>(managedEngineCounters.size());
+ for (Entry entry : managedEngineCounters.entrySet()) {
+ result.add(getter.apply(entry.getValue()));
+ }
+ return result;
+ }
+
+ @Override
+ public ObjectName getObjectName() {
+ return Util.newObjectName(WISP_COUNTER_MXBEAN_NAME);
+ }
+
+ static void register(WispCounter counter) {
+ managedEngineCounters.put(counter.carrier.getId(), counter);
+ }
+
+ static void deRegister(WispCounter counter) {
+ managedEngineCounters.remove(counter.carrier.getId());
+ counter.cleanup();
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispEngine.java b/src/linux/classes/com/alibaba/wisp/engine/WispEngine.java
new file mode 100644
index 0000000000000000000000000000000000000000..59e476f27652a0cc4a20fbea53f01a1d4f753a98
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispEngine.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.JavaLangAccess;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.dyn.Coroutine;
+import java.dyn.CoroutineExitException;
+import java.dyn.CoroutineSupport;
+import java.io.IOException;
+import java.nio.channels.SelectableChannel;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import java.util.function.Supplier;
+
+/**
+ * Coroutine Runtime Engine. It's a "wisp" thing, as we want our asynchronization transformation to be transparent
+ * without any modification to user code.
+ *
+ * WispEngine represents a group of {@link WispCarrier}, which can steal
+ * tasks from each other to achieve work-stealing.
+ *
+ * {@code WispEngine#WISP_ROOT_ENGINE} is created by system.
+ * {@link WispEngine#current().execute(Runnable)} in non-worker thread and WISP_ROOT_ENGINE's
+ * worker thread will dispatch task in this carrier.
+ *
+ * User code could also create {@link WispEngine} by calling
+ * {@link WispEngine#createEngine(int, ThreadFactory)},
+ * Calling {@link WispEngine#execute(Runnable)} will dispatch
+ * WispTask inner created carrier.
+ * {@link WispEngine#current().execute(Runnable)} in a user created carrier will also
+ * dispatch task in current carrier.
+ */
+public class WispEngine extends AbstractExecutorService {
+
+ static {
+ registerNatives();
+ setWispEngineAccess();
+ timer = createTimerScheduler();
+ }
+
+ public static boolean transparentWispSwitch() {
+ return WispConfiguration.TRANSPARENT_WISP_SWITCH;
+ }
+
+ public static boolean enableThreadAsWisp() {
+ return shiftThreadModel;
+ }
+
+ @Deprecated
+ public static boolean isTransparentAsync() {
+ return transparentWispSwitch();
+ }
+
+ private static final String WISP_ROOT_ENGINE_NAME = "Root";
+ private static final AtomicReferenceFieldUpdater SHUTDOWN_UPDATER
+ = AtomicReferenceFieldUpdater.newUpdater(WispEngine.class, Boolean.class, "hasBeenShutdown");
+ /*
+ some of our users change this field by reflection
+ in the runtime to disable wisp temporarily.
+ We should move shiftThreadModel to WispConfiguration
+ after we provide api to control this behavior and
+ notify the users to modify their code.
+ TODO refactor to com.alibaba.wisp.enableThreadAsWisp later
+ */
+ static boolean shiftThreadModel = WispConfiguration.ENABLE_THREAD_AS_WISP;
+ static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+ /*
+ * Wisp specified Thread Group
+ * all the daemon threads in wisp should be created with the Thread Group.
+ * In Thread.start(), if the thread should not convert to WispTask,
+ * check whether the thread's carrier is daemonThreadGroup
+ */
+ final static ThreadGroup DAEMON_THREAD_GROUP =
+ new ThreadGroup(JLA.currentThread0().getThreadGroup(), "Daemon Thread Group");
+ static ScheduledExecutorService timer;
+ static Set carrierThreads;
+ static Thread unparkDispatcher;
+
+ static WispEngine WISP_ROOT_ENGINE;
+
+ private static ScheduledExecutorService createTimerScheduler() {
+ return !WispConfiguration.WISP_HIGH_PRECISION_TIMER ? null :
+ Executors.newScheduledThreadPool(1, new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(WispEngine.DAEMON_THREAD_GROUP, r);
+ thread.setDaemon(true);
+ thread.setName("Wisp-Timer");
+ return thread;
+ }
+ });
+ }
+
+ private static void initializeWispClass() {
+ assert JLA != null : "WispCarrier should be initialized after System";
+ assert JLA.currentThread0().getName().equals("main") : "Wisp need to be loaded by main thread";
+ shiftThreadModel = WispConfiguration.ENABLE_THREAD_AS_WISP;
+ carrierThreads = new ConcurrentSkipListSet<>(new Comparator() {
+ @Override
+ public int compare(Thread o1, Thread o2) {
+ return Long.compare(o1.getId(), o2.getId());
+ }
+ });
+ WISP_ROOT_ENGINE = new WispEngine(WISP_ROOT_ENGINE_NAME);
+ if (transparentWispSwitch()) {
+ WispEngine.initializeClasses();
+ JLA.wispBooted();
+ }
+ }
+
+ private static void initializeClasses() {
+ try {
+ Class.forName(CoroutineExitException.class.getName());
+ Class.forName(WispThreadWrapper.class.getName());
+ Class.forName(TaskDispatcher.class.getName());
+ Class.forName(StartShutdown.class.getName());
+ Class.forName(NotifyAndWaitTasksForShutdown.class.getName());
+ Class.forName(Coroutine.StealResult.class.getName());
+ Class.forName(WispCounterMXBeanImpl.class.getName());
+ Class.forName(ThreadAsWisp.class.getName());
+ Class.forName(WispEventPump.class.getName());
+ if (WispConfiguration.WISP_PROFILE) {
+ Class.forName(WispPerfCounterMonitor.class.getName());
+ }
+ if (WispConfiguration.WISP_HIGH_PRECISION_TIMER) {
+ timer.submit(new Runnable() {
+ @Override
+ public void run() {
+ }
+ });
+ }
+ new ConcurrentLinkedQueue<>().iterator();
+ new ConcurrentSkipListMap<>().keySet().iterator();
+ WispCarrier carrier = WispCarrier.current();
+ carrier.addTimer(System.nanoTime() + Integer.MAX_VALUE, false);
+ carrier.cancelTimer();
+ carrier.createResumeEntry(new WispTask(carrier, null, false, false));
+ registerPerfCounter(carrier);
+ deRegisterPerfCounter(carrier);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private static void startWispDaemons() {
+ if (transparentWispSwitch()) {
+ unparkDispatcher = new Thread(DAEMON_THREAD_GROUP, new Runnable() {
+ @Override
+ public void run() {
+ int[] proxyUnparks = new int[12];
+ CoroutineSupport.setWispBooted();
+ while (true) {
+ int n = WispEngine.getProxyUnpark(proxyUnparks);
+ for (int i = 0; i < n; i++) {
+ WispTask.unparkById(proxyUnparks[i]);
+ }
+ }
+ }
+ }, "Wisp-Unpark-Dispatcher");
+ unparkDispatcher.setDaemon(true);
+ unparkDispatcher.start();
+ WispSysmon.INSTANCE.startDaemon();
+ WISP_ROOT_ENGINE.scheduler.startWorkerThreads();
+
+ if (!WispConfiguration.CARRIER_AS_POLLER) {
+ WispEventPump.Pool.INSTANCE.startPollerThreads();
+ }
+ if (WispConfiguration.WISP_PROFILE_LOG_ENABLED) {
+ WispPerfCounterMonitor.INSTANCE.startDaemon();
+ }
+ }
+ }
+
+ private static void setWispEngineAccess() {
+ SharedSecrets.setWispEngineAccess(new WispEngineAccess() {
+
+ @Override
+ public WispTask getCurrentTask() {
+ return WispCarrier.current().getCurrentTask();
+ }
+
+ @Override
+ public void registerEvent(SelectableChannel ch, int events) throws IOException {
+ WispCarrier.current().registerEvent(ch, events);
+ }
+
+ @Override
+ public void unregisterEvent() {
+ WispCarrier.current().unregisterEvent();
+ }
+
+ @Override
+ public int epollWait(int epfd, long pollArray, int arraySize, long timeout,
+ AtomicReference status, Object INTERRUPTED) throws IOException {
+ return WispEventPump.Pool.INSTANCE.epollWaitForWisp(epfd, pollArray, arraySize, timeout, status, INTERRUPTED);
+ }
+
+ @Override
+ public void interruptEpoll(AtomicReference status, Object INTERRUPTED, int interruptFd) {
+ WispEventPump.Pool.INSTANCE.interruptEpoll(status, INTERRUPTED, interruptFd);
+ }
+
+ @Override
+ public void addTimer(long deadlineNano) {
+ WispCarrier.current().addTimer(deadlineNano, false);
+ }
+
+ @Override
+ public void cancelTimer() {
+ WispCarrier.current().cancelTimer();
+ }
+
+ @Override
+ public void sleep(long ms) {
+ WispTask.sleep(ms);
+ }
+
+ @Override
+ public void yield() {
+ WispCarrier.current().yield();
+ }
+
+ @Override
+ public boolean isThreadTask(WispTask task) {
+ return task.isThreadTask();
+ }
+
+ @Override
+ public boolean isTimeout() {
+ WispTask task = WispCarrier.current().current;
+ return task.timeOut != null && task.timeOut.expired();
+ }
+
+ @Override
+ public void park(long timeoutNano) {
+ WispTask.jdkPark(timeoutNano);
+ }
+
+ @Override
+ public void unpark(WispTask task) {
+ if (task != null) {
+ task.jdkUnpark();
+ }
+ }
+
+ @Override
+ public void destroy() {
+ WispCarrier.current().destroy();
+ }
+
+ @Override
+ public boolean hasMoreTasks() {
+ return WispCarrier.current().getTaskQueueLength() > 0;
+ }
+
+ @Override
+ public boolean runningAsCoroutine(Thread t) {
+ return WispEngine.runningAsCoroutine(t);
+ }
+
+ @Override
+ public boolean usingWispEpoll() {
+ return runningAsCoroutine(null);
+ }
+
+ public boolean isAlive(WispTask task) {
+ return task.isAlive();
+ }
+
+ @Override
+ public void interrupt(WispTask task) {
+ task.interrupt();
+ }
+
+ @Override
+ public boolean testInterruptedAndClear(WispTask task, boolean clear) {
+ return task.testInterruptedAndClear(clear);
+ }
+
+ @Override
+ public boolean tryStartThreadAsWisp(Thread thread, Runnable target) {
+ return ThreadAsWisp.tryStart(thread, target);
+ }
+
+ @Override
+ public boolean isAllThreadAsWisp() {
+ return WispConfiguration.ALL_THREAD_AS_WISP;
+ }
+
+ @Override
+ public boolean useDirectSelectorWakeup() {
+ return WispConfiguration.USE_DIRECT_SELECTOR_WAKEUP;
+ }
+
+ @Override
+ public boolean enableSocketLock() {
+ return WispConfiguration.WISP_ENABLE_SOCKET_LOCK;
+ }
+
+ @Override
+ public StackTraceElement[] getStackTrace(WispTask task) {
+ return task.getStackTrace();
+ }
+ });
+ }
+
+ final WispScheduler scheduler;
+ final Set carrierEngines;
+ final Queue groupTaskCache = new ConcurrentLinkedQueue<>();
+ final CyclicBarrier shutdownBarrier;
+ volatile int runningTaskCount = 0;
+ private CountDownLatch shutdownFuture;
+ volatile Boolean hasBeenShutdown = false;
+ volatile boolean detached;
+
+ /**
+ * Create a new WispEngine for executing tasks.
+ *
+ * @param size worker thread counter
+ * @param tf ThreadFactory used to create worker thread
+ */
+ public static WispEngine createEngine(int size, ThreadFactory tf) {
+ return new WispEngine(size, tf);
+ }
+
+ /**
+ * Create Root Worker.
+ */
+ private WispEngine(String name) {
+ carrierEngines = new ConcurrentSkipListSet<>();
+ // detached carrier won't shut down
+ shutdownBarrier = null;
+ scheduler = new WispScheduler(
+ WispConfiguration.WORKER_COUNT,
+ WispConfiguration.WISP_SCHEDULE_STEAL_RETRY,
+ WispConfiguration.WISP_SCHEDULE_PUSH_RETRY,
+ WispConfiguration.WISP_SCHEDULE_HELP_STEAL_RETRY,
+ new ThreadFactory() {
+ final AtomicInteger seq = new AtomicInteger();
+
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r, "Wisp-" + name + "-Worker-" + seq.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ }
+ }, this, true);
+ }
+
+ private WispEngine(int size, ThreadFactory tf) {
+ carrierEngines = new ConcurrentSkipListSet<>();
+ shutdownBarrier = new CyclicBarrier(size);
+ scheduler = new WispScheduler(size, tf, this);
+ shutdownFuture = new CountDownLatch(1);
+ }
+
+
+ public static WispEngine current() {
+ return WispCarrier.current().engine;
+ }
+
+
+ /**
+ * Create WispTask to run task code
+ *
+ * The real running thread depends on implementation
+ *
+ * @param target target code
+ */
+ public static void dispatch(Runnable target) {
+ WispEngine.current().execute(target);
+ }
+
+ @Deprecated
+ public static boolean isShiftThreadModel() {
+ return shiftThreadModel;
+ }
+
+ static boolean isEngineThread(Thread t) {
+ assert DAEMON_THREAD_GROUP != null;
+ return DAEMON_THREAD_GROUP == t.getThreadGroup() || carrierThreads.contains(t);
+ }
+
+ static long getNanoTime() {
+ return WispConfiguration.WISP_PROFILE ? System.nanoTime() : 0;
+ }
+
+ /**
+ * DO NOT use this helper inside WispCarrier,
+ * because lambda may cause class loading.
+ */
+ static T runInCritical(Supplier supplier) {
+ WispCarrier carrier = WispCarrier.current();
+ boolean critical0 = carrier.isInCritical;
+ carrier.isInCritical = true;
+ try {
+ return supplier.get();
+ } finally {
+ carrier.isInCritical = critical0;
+ }
+ }
+
+ static boolean runningAsCoroutine(Thread t) {
+ WispTask task = t == null ? WispCarrier.current().getCurrentTask() : JLA.getWispTask(t);
+ assert task != null;
+ // Only carrierThread could create WispTask, and
+ // the carrierThread will listen on WispTask's wakeup.
+ // So we can safely letting the non-worker wispTask block the whore Thread.
+ return !task.isThreadTask();
+ }
+
+ static WispCounter getWispCounter(long id) {
+ return WispConfiguration.WISP_PROFILE ? WispPerfCounterMonitor.INSTANCE.getWispCounter(id) : null;
+ }
+
+
+ // ----------------------------------------------- shutdown support
+ @Override
+ public void shutdown() {
+ if (!SHUTDOWN_UPDATER.compareAndSet(this, false, true)) {
+ return;
+ }
+ for (WispCarrier carrier : carrierEngines) {
+ deRegisterPerfCounter(carrier);
+ }
+ scheduler.execute(new StartShutdown());
+ }
+
+ @Override
+ public List shutdownNow() {
+ throw new UnsupportedOperationException();
+ }
+
+ class StartShutdown extends StealDisabledRunnable {
+ @Override
+ public void run() {
+ WispCarrier.current().runTaskInternal(new NotifyAndWaitTasksForShutdown(),
+ WispTask.SHUTDOWN_TASK_NAME, null, null);
+ }
+ }
+
+ class NotifyAndWaitTasksForShutdown implements Runnable {
+ @Override
+ public void run() {
+ try {
+ // wait until current 'shutdown wispTask' is the only
+ // running wispTask on this carrier
+ while (runningTaskCount != 1) {
+ List runningTasks = getRunningTasks();
+ for (WispTask task : runningTasks) {
+ if (task.carrier.engine == WispEngine.this
+ && task.isAlive()
+ && !WispTask.SHUTDOWN_TASK_NAME.equals(task.getName())) {
+ task.interrupt();
+ }
+ }
+ WispCarrier.current().yield();
+ }
+ assert WispTask.SHUTDOWN_TASK_NAME.equals(WispCarrier.current().current.getName());
+ detached = true;
+ //notify all worker to exit
+ for (WispCarrier carrier : carrierEngines) {
+ carrier.worker.signal();
+ }
+ shutdownFuture.countDown();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 1. In Wisp2, each WispCarrier's runningTask is modified when WispTask is stolen, we can't guarantee
+ * the accuracy of the task set.
+ * 2. this function is only called in shutdown, so it's not performance sensitive
+ * 3. this function should only be called by current WispTask
+ */
+ private List getRunningTasks() {
+ assert WispTask.SHUTDOWN_TASK_NAME.equals(WispCarrier.current().current.getName());
+ WispCarrier carrier = WispCarrier.current();
+ ArrayList runningTasks = new ArrayList<>();
+ boolean isInCritical0 = carrier.isInCritical;
+ carrier.isInCritical = true;
+ try {
+ for (WispTask task : WispTask.id2Task.values()) {
+ if (task.isAlive()
+ && task.carrier.engine == WispEngine.this
+ && !task.isThreadTask()) {
+ runningTasks.add(task);
+ }
+ }
+ return runningTasks;
+ } finally {
+ carrier.isInCritical = isInCritical0;
+ }
+ }
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return hasBeenShutdown;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return detached;
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ return shutdownFuture.await(timeout, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ startAsThread(command, "execute task", null);
+ }
+
+ public List getWispCarrierIds() {
+ List carriers = new ArrayList<>();
+ for (WispCarrier carrier : carrierEngines) {
+ carriers.add(carrier.getId());
+ }
+ return carriers;
+ }
+
+ static void registerPerfCounter(WispCarrier carrier) {
+ WispEngine.runInCritical(() -> {
+ if (WispConfiguration.WISP_PROFILE) {
+ WispPerfCounterMonitor.INSTANCE.register(carrier.counter);
+ }
+ WispCounterMXBeanImpl.register(carrier.counter);
+ return null;
+ });
+ }
+
+ static void deRegisterPerfCounter(WispCarrier carrier) {
+ WispEngine.runInCritical(() -> {
+ if (WispConfiguration.WISP_PROFILE) {
+ WispPerfCounterMonitor.INSTANCE.deRegister(carrier.counter);
+ }
+ WispCounterMXBeanImpl.deRegister(carrier.counter);
+ return null;
+ });
+ }
+
+ void startAsThread(Runnable target, String name, Thread thread) {
+ scheduler.execute(new TaskDispatcher(WispCarrier.current().current.ctxClassLoader,
+ target, name, thread));
+ }
+
+ abstract static class StealDisabledRunnable implements StealAwareRunnable {
+ @Override
+ public final boolean isStealEnable() {
+ return false;
+ }
+ }
+
+ private static native void registerNatives();
+
+ private static native int getProxyUnpark(int[] res);
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispEventPump.java b/src/linux/classes/com/alibaba/wisp/engine/WispEventPump.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fb78511f2f143a416b3c70d5939cf62bd8c2d8a
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispEventPump.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.SharedSecrets;
+import sun.nio.ch.IOEventAccess;
+import sun.nio.ch.Net;
+import sun.nio.ch.SelChImpl;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+
+class WispEventPump {
+ private static final int LOW_FD_BOUND = 1024 * 10;
+ private static final int MAX_EVENTS_TO_POLL = 512;
+ private static final IOEventAccess IOEA;
+
+ private final int epfd;
+ private final int pipe0;
+ private final int pipe1;
+ private final long epollArray;
+
+ static {
+ sun.nio.ch.IOUtil.load();
+ IOEA = SharedSecrets.getIOEventAccess();
+ }
+
+ private WispEventPump() {
+ try {
+ epfd = IOEA.eventCreate();
+ int[] a = new int[2];
+ IOEA.socketpair(a);
+ pipe0 = a[0];
+ pipe1 = a[1];
+ if (IOEA.eventCtl(epfd, IOEA.eventCtlAdd(), pipe0, Net.POLLIN) != 0) {
+ throw new IOException("epoll_ctl fail");
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ epollArray = IOEA.allocatePollArray(MAX_EVENTS_TO_POLL);
+ }
+
+ enum Pool {
+ INSTANCE;
+ private final int mask;
+ private final WispEventPump[] pumps;
+
+ Pool() {
+ int n = Math.max(1, WispConfiguration.WORKER_COUNT / WispConfiguration.POLLER_SHARDING_SIZE);
+ n = (n & (n - 1)) == 0 ? n : Integer.highestOneBit(n) * 2; // next power of 2
+ mask = n - 1;
+ pumps = new WispEventPump[n];
+ for (int i = 0; i < pumps.length; i++) {
+ pumps[i] = new WispEventPump();
+ }
+ }
+
+ void startPollerThreads() {
+ int i = 0;
+ for (WispEventPump pump : pumps) {
+ Thread t = new Thread(WispEngine.DAEMON_THREAD_GROUP, new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ pump.pollAndDispatchEvents(-1);
+ }
+ }
+ }, "Wisp-Poller-" + i++);
+ t.setDaemon(true);
+ t.start();
+ }
+ }
+
+ private static int hash(int x) {
+ // implementation of Knuth multiplicative algorithm.
+ return x * (int) 2654435761L;
+ }
+
+ void registerEvent(WispTask task, SelectableChannel ch, int event) throws IOException {
+ if (ch != null && ch.isOpen()) {
+ int fd = ((SelChImpl) ch).getFDVal();
+ pumps[hash(fd) & mask].registerEvent(task, fd, event);
+ }
+ }
+
+ int epollWaitForWisp(int epfd, long pollArray, int arraySize, long timeout, AtomicReference status,
+ final Object INTERRUPTED) throws IOException {
+ return pumps[hash(epfd) & mask].epollWaitForWisp(epfd, pollArray, arraySize, timeout, status, INTERRUPTED);
+ }
+
+ void interruptEpoll(AtomicReference status, Object INTERRUPTED, int interruptFd) {
+ WispEventPump.interruptEpoll(status, INTERRUPTED, interruptFd);
+ }
+
+ WispEventPump getPump(int ord) {
+ return pumps[ord & mask];
+ }
+ }
+
+ /**
+ * fd2ReadTask handles all incoming io events like reading and accepting
+ */
+ private final WispTask[] fd2ReadTaskLow = new WispTask[LOW_FD_BOUND];
+ private final ConcurrentHashMap fd2ReadTaskHigh = new ConcurrentHashMap<>();
+
+ /**
+ * fd2WriteTask handles all outing io events like connecting and writing
+ */
+ private final WispTask[] fd2WriteTaskLow = new WispTask[LOW_FD_BOUND];
+ private final ConcurrentHashMap fd2WriteTaskHigh = new ConcurrentHashMap<>();
+
+ /**
+ * whether event is a reading event or an accepting event
+ */
+ private boolean isReadEvent(int events) throws IllegalArgumentException {
+ int event = (events & (Net.POLLCONN | Net.POLLIN | Net.POLLOUT));
+ assert Integer.bitCount(event) == 1;
+ return (events & Net.POLLIN) != 0;
+ }
+
+ private WispTask[] getFd2TaskLow(int events) {
+ return isReadEvent(events) ? fd2ReadTaskLow : fd2WriteTaskLow;
+ }
+
+ private ConcurrentHashMap getFd2TaskHigh(int events) {
+ return isReadEvent(events) ? fd2ReadTaskHigh : fd2WriteTaskHigh;
+ }
+
+ private boolean sanityCheck(int fd, WispTask newTask, int events) {
+ WispTask oldTask = fd < LOW_FD_BOUND ? getFd2TaskLow(events)[fd] : getFd2TaskHigh(events).get(fd);
+ // If timeout happened, when oldTask finished,
+ // the oldTask.ch would be nullified(we didn't get chance to remove it)
+ return (oldTask == null || oldTask == newTask || oldTask.ch == null
+ || ((SelChImpl) oldTask.ch).getFDVal() != fd);
+ }
+
+ /**
+ * All events are guaranteed to be interested in only one direction since
+ * all registrations are from WispSocket
+ */
+ private void recordTaskByFD(int fd, WispTask task, int events) {
+ assert sanityCheck(fd, task, events);
+ if (fd < LOW_FD_BOUND) {
+ getFd2TaskLow(events)[fd] = task;
+ } else {
+ getFd2TaskHigh(events).put(fd, task);
+ }
+ }
+
+ private WispTask removeTaskByFD(int fd, int events) {
+ WispTask task;
+ if (fd < LOW_FD_BOUND) {
+ WispTask[] fd2TaskLow = getFd2TaskLow(events);
+ task = fd2TaskLow[fd];
+ fd2TaskLow[fd] = null;
+ } else {
+ task = getFd2TaskHigh(events).remove(fd);
+ }
+ return task;
+ }
+
+ private void registerEvent(WispTask task, int fd, int event) throws IOException {
+ int ev = 0;
+ // Translates an interest operation set into a native poll event set
+ if ((event & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0) ev |= Net.POLLIN;
+ if ((event & SelectionKey.OP_WRITE) != 0) ev |= Net.POLLOUT;
+ if ((event & SelectionKey.OP_CONNECT) != 0) ev |= Net.POLLCONN;
+ // When the socket is closed, the poll event will be triggered
+ ev |= Net.POLLHUP;
+ // specify the EPOLLONESHOT flag, to tell epoll to disable the associated
+ // file descriptor after the receipt of an event with epoll_wait
+ ev |= IOEA.eventOneShot();
+
+ recordTaskByFD(fd, task, ev);
+ task.setRegisterEventTime();
+ // we can do it multi-thread, because epoll is protected by spin lock in kernel
+ // When the EPOLLONESHOT flag is specified, it is the caller's responsibility to
+ // rearm the file descriptor using epoll_ctl with EPOLL_CTL_MOD
+ int res = IOEA.eventCtl(epfd, IOEA.eventCtlMod(), fd, ev); // rearm
+ if (res != 0 && !(res == IOEA.noEvent() && (res = IOEA.eventCtl(epfd, IOEA.eventCtlAdd(), fd, ev)) == 0)) {
+ removeTaskByFD(fd, ev);
+ task.resetRegisterEventTime();
+ throw new IOException("epoll_ctl " + res);
+ }
+ }
+
+ /**
+ * API for coroutine do epoll_wait
+ *
+ * @param epfd epoll fd
+ * @param pollArray epoll array address
+ * @param arraySize epoll array size
+ * @param timeout timeout ms
+ * @param status interrupt status;
+ * @param INTERRUPTED const indicate for interrupted
+ * @return selected event num
+ */
+ private int epollWaitForWisp(int epfd, long pollArray, int arraySize, long timeout,
+ AtomicReference status, final Object INTERRUPTED) throws IOException {
+ assert pollArray != 0;
+ WispTask me = WispCarrier.current().current;
+ if (!WispEngine.runningAsCoroutine(me.getThreadWrapper())) {
+ return IOEA.eventWait(epfd, pollArray, arraySize, (int) timeout);
+ }
+ if (WispConfiguration.MONOLITHIC_POLL) {
+ if (timeout == 0) {
+ // return 0 for selectNow(), prevent calling epoll_wait in non-poller thread
+ // and the application will retry with timeout
+ return 0;
+ }
+ } else {
+ int updated = IOEA.eventWait(epfd, pollArray, arraySize, 0);
+ if (timeout == 0 || updated > 0) {
+ return updated;
+ }
+ }
+ if (WispConfiguration.USE_DIRECT_SELECTOR_WAKEUP &&
+ (status.get() == INTERRUPTED || !(status.get() == null && status.compareAndSet(null, me)))) {
+ assert status.get() == INTERRUPTED;
+ return 0; // already epoll_wait(0), no retry needed.
+ }
+
+ if (WispConfiguration.MONOLITHIC_POLL) {
+ assert timeout != 0;
+ me.epollArraySize = arraySize;
+ me.setEpollEventNum(0);
+ me.setEpollArray(pollArray);
+ }
+
+ if (timeout != 0) {
+ registerEvent(me, epfd, SelectionKey.OP_READ);
+ WispTask.jdkPark(TimeUnit.MILLISECONDS.toNanos(timeout));
+ }
+
+ if (WispConfiguration.USE_DIRECT_SELECTOR_WAKEUP &&
+ !(status.get() == me && status.compareAndSet(me, null))) {
+ assert status.get() == INTERRUPTED;
+ }
+
+ if (WispConfiguration.MONOLITHIC_POLL) {
+ // already polled by poller, see doMonolithicPoll()
+ me.setEpollArray(0);
+ return me.getEpollEventNum();
+ } else {
+ return IOEA.eventWait(epfd, pollArray, arraySize, 0);
+ }
+ }
+
+ private void doMonolithicPoll(int fd, WispTask task, long epollArray) throws IOException {
+ assert WispConfiguration.MONOLITHIC_POLL;
+ task.setEpollEventNum(IOEA.eventWait(fd, epollArray, task.epollArraySize, 0));
+ }
+
+ private static void interruptEpoll(AtomicReference status, Object INTERRUPTED, int interruptFd) {
+ assert WispConfiguration.USE_DIRECT_SELECTOR_WAKEUP;
+ while (true) {
+ final Object st = status.get();
+ if (st == INTERRUPTED || st == null && status.compareAndSet(null, INTERRUPTED)) {
+ if (!WispConfiguration.ALL_THREAD_AS_WISP) {
+ try {
+ IOEA.interrupt(interruptFd);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ break;
+ } else if (st != null) { // waiting
+ assert st instanceof WispTask;
+ if (status.compareAndSet(st, INTERRUPTED)) {
+ ((WispTask) st).jdkUnpark();
+ break;
+ }
+ }
+ }
+ }
+
+ private volatile int wakeupCount;
+
+ boolean pollAndDispatchEvents(long timeout) {
+ boolean wakened = false;
+ try {
+ int n = IOEA.eventWait(epfd, epollArray, MAX_EVENTS_TO_POLL, (int) timeout);
+ while (n-- > 0) {
+ long eventAddress = IOEA.getEvent(epollArray, n);
+ int fd = IOEA.getDescriptor(eventAddress);
+ if (fd == pipe0) {
+ wakened = true;
+ // Conservative strategy, wakeup() can never lost
+ if (WAKEUP_UPDATER.decrementAndGet(this) == 0) {
+ IOEA.drain(pipe0);
+ }
+ continue;
+ }
+ int events = IOEA.getEvents(eventAddress);
+ if ((events & Net.POLLIN) != 0) {
+ processEvent(fd, true);
+ }
+ if ((events & Net.POLLCONN) != 0 || (events & Net.POLLOUT) != 0) {
+ processEvent(fd, false);
+ }
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return wakened;
+ }
+
+
+ private void processEvent(int fd, boolean isRead) throws IOException {
+ WispTask task = removeTaskByFD(fd, isRead ? Net.POLLIN : Net.POLLOUT);
+ if (task != null) {
+ long epollArray = task.getEpollArray();
+ if (isRead && epollArray != 0) {
+ doMonolithicPoll(fd, task, epollArray);
+ } else {
+ task.countWaitSocketIOTime();
+ }
+ task.jdkUnpark();
+ }
+ }
+
+ void wakeup() {
+ if (WAKEUP_UPDATER.getAndIncrement(this) == 0) {
+ try {
+ IOEA.interrupt(pipe1);
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ }
+ }
+
+ volatile WispScheduler.Worker owner;
+
+ boolean tryAcquire(WispScheduler.Worker worker) {
+ assert WispConfiguration.CARRIER_AS_POLLER;
+ return owner == null && OWNER_UPDATER.compareAndSet(this, null, worker);
+ }
+
+ void release(WispScheduler.Worker worker) {
+ assert owner == worker;
+ OWNER_UPDATER.lazySet(this, null);
+ }
+
+ private final static AtomicReferenceFieldUpdater OWNER_UPDATER =
+ AtomicReferenceFieldUpdater.newUpdater(WispEventPump.class, WispScheduler.Worker.class, "owner");
+ private final static AtomicIntegerFieldUpdater WAKEUP_UPDATER =
+ AtomicIntegerFieldUpdater.newUpdater(WispEventPump.class, "wakeupCount");
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispPerfCounterMonitor.java b/src/linux/classes/com/alibaba/wisp/engine/WispPerfCounterMonitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa5cbf8a5aeb0158111b08b583f6891f470af7e0
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispPerfCounterMonitor.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.logging.*;
+
+enum WispPerfCounterMonitor {
+ INSTANCE;
+
+ private boolean fileHandleEnable = false;
+ private Map managedEngineCounters;
+ private Logger wispLog;
+
+ private final SimpleDateFormat localDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ WispPerfCounterMonitor() {
+ if (WispConfiguration.WISP_PROFILE) {
+ managedEngineCounters = new ConcurrentHashMap<>(100);
+ }
+ if (WispConfiguration.WISP_PROFILE_LOG_ENABLED) {
+ String logPath = WispConfiguration.WISP_PROFILE_LOG_PATH;
+ wispLog = Logger.getLogger(WispPerfCounterMonitor.class.getName());
+ FileHandler fileHandler;
+ try {
+ // In a log file, record about 24 hours of data
+ fileHandler = new FileHandler(
+ logPath == null ? "wisplog%g.log" : logPath + File.separator + "wisplog%g.log",
+ 12800000, 4, true);
+ fileHandler.setLevel(Level.INFO);
+ fileHandler.setFormatter(new java.util.logging.Formatter() {
+ @Override
+ public String format(LogRecord record) {
+ return record.getMessage() + "\n";
+ }
+ });
+ wispLog.setUseParentHandlers(false);
+ wispLog.addHandler(fileHandler);
+ fileHandleEnable = true;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ void startDaemon() {
+ Thread thread = new Thread(WispEngine.DAEMON_THREAD_GROUP, this::perfCounterLoop, "Wisp-Monitor");
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ void register(WispCounter counter) {
+ if (WispConfiguration.WISP_PROFILE && sun.misc.VM.isBooted()) {
+ WispPerfCounter wispPerfCounter = new WispPerfCounter(counter);
+ managedEngineCounters.put(counter.carrier.getId(), wispPerfCounter);
+ }
+ }
+
+ void deRegister(WispCounter counter) {
+ if (WispConfiguration.WISP_PROFILE) {
+ managedEngineCounters.remove(counter.carrier.getId());
+ }
+ }
+
+ WispCounter getWispCounter(long id) {
+ WispPerfCounter perfCounter = WispEngine.runInCritical(
+ () -> managedEngineCounters.get(id));
+ if (perfCounter == null) {
+ return null;
+ }
+ perfCounter.storeCurrentWispCounter();
+ return perfCounter.prevCounterValue;
+ }
+
+ private void perfCounterLoop() {
+ while (true) {
+ try {
+ Thread.sleep((long) WispConfiguration.WISP_PROFILE_LOG_INTERVAL_MS);
+ } catch (InterruptedException e) {
+ // pass
+ }
+ dumpCounter();
+ }
+ }
+
+ private void appendLogString(StringBuilder strb, String dateTime, String item, int workerID, long data) {
+ strb.append(dateTime)
+ .append("\t").append(item).append("\t\t")
+ .append("worker").append(workerID).append("\t\t")
+ .append(data).append("\n");
+ }
+
+ private void dumpCounter() {
+ if (!fileHandleEnable) {
+ return;
+ }
+
+ StringBuilder strb = new StringBuilder();
+ long currentTime = System.currentTimeMillis();
+ String dateTime = localDateFormat.format(new Date(currentTime));
+ int worker = 0;
+ /* dump Wisp monitor information */
+ WispPerfCounter perfCounter;
+ for (Entry entry : managedEngineCounters.entrySet()) {
+ perfCounter = entry.getValue();
+ appendLogString(strb, dateTime, "completedTaskCount", worker, perfCounter.getCompletedTaskCount());
+ appendLogString(strb, dateTime, "unparkFromJvmCount", worker, perfCounter.getUnparkFromJvmCount());
+ appendLogString(strb, dateTime, "averageEnqueueTime", worker, perfCounter.getAverageEnqueueTime());
+ appendLogString(strb, dateTime, "averageExecutionTime", worker, perfCounter.getAverageExecutionTime());
+ appendLogString(strb, dateTime, "averageWaitSocketIOTime", worker, perfCounter.getAverageWaitSocketIOTime());
+ appendLogString(strb, dateTime, "averageBlockingTime", worker, perfCounter.getAverageBlockingTime());
+ perfCounter.storeCurrentWispCounter();
+ worker++;
+ }
+ wispLog.info(strb.toString());
+ }
+
+ private class WispPerfCounter {
+ WispCounter counter;
+
+ WispCounter prevCounterValue;
+
+ long getCompletedTaskCount() {
+ return counter.getCompletedTaskCount() - prevCounterValue.getCompletedTaskCount();
+ }
+
+ long getUnparkFromJvmCount() {
+ return counter.getUnparkFromJvmCount() - prevCounterValue.getUnparkFromJvmCount();
+ }
+
+ long getAverageTime(Function timeFunc, Function countFunc) {
+ long count = countFunc.apply(counter) - countFunc.apply(prevCounterValue);
+ if (count == 0) {
+ return 0;
+ }
+ long totalNanos = timeFunc.apply(counter) - timeFunc.apply(prevCounterValue);
+ return totalNanos / count;
+ }
+
+ long getAverageEnqueueTime() {
+ return getAverageTime(WispCounter::getTotalEnqueueTime, WispCounter::getEnqueueCount);
+ }
+
+ long getAverageExecutionTime() {
+ return getAverageTime(WispCounter::getTotalExecutionTime, WispCounter::getExecutionCount);
+ }
+
+ long getAverageWaitSocketIOTime() {
+ return getAverageTime(WispCounter::getTotalWaitSocketIOTime, WispCounter::getWaitSocketIOCount);
+ }
+
+ long getAverageBlockingTime() {
+ return getAverageTime(WispCounter::getTotalBlockingTime, WispCounter::getUnparkCount);
+ }
+
+ void storeCurrentWispCounter() {
+ if (counter == null) {
+ return;
+ }
+ prevCounterValue.assign(counter);
+ counter.resetMaxValue();
+ }
+
+ WispPerfCounter(WispCounter counter) {
+ this.counter = counter;
+ this.prevCounterValue = new WispCounter();
+ this.prevCounterValue.assign(counter);
+ }
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispScheduler.java b/src/linux/classes/com/alibaba/wisp/engine/WispScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..141c8ab39dd2587b5540fd1fedb8882b52410c5c
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispScheduler.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.JavaLangAccess;
+import sun.misc.SharedSecrets;
+import sun.misc.UnsafeAccess;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+
+/**
+ * Wisp work-stealing scheduler.
+ * Every worker thread has a {@link ConcurrentLinkedQueue} to
+ * receive tasks.
+ * Once local queue is empty, worker will scan
+ * others' queue, execute stolen task, then check local queue.
+ * Again and again, until all the queue is empty.
+ */
+class WispScheduler {
+
+ private static final SchedulingPolicy SCHEDULING_POLICY = WispConfiguration.SCHEDULING_POLICY;
+
+ private final static int IDX_MASK = 0xffff; // ensure positive
+ private final static int STEAL_HIGH_WATER_LEVEL = 4;
+
+ // instance const
+ private int PARALLEL;
+ private int STEAL_RETRY;
+ private int PUSH_RETRY;
+ private int HELP_STEAL_RETRY;
+ private final boolean IS_ROOT_CARRIER;
+
+ // workers could be changed by handOff(),
+ // add volatile to avoiding workers's elements
+ // to be allocated in register.
+ // we could not add volatile volatile modifier
+ // to array elements, so make the array volatile.
+ private volatile Worker[] workers;
+ private final ThreadFactory threadFactory;
+ private final WispEngine engine;
+ private int sharedSeed = randomSeed();
+
+ WispScheduler(int parallelism, ThreadFactory threadFactory, WispEngine group) {
+ this(parallelism, Math.max(1, parallelism / 2), parallelism,
+ Math.max(1, parallelism / 4), threadFactory, group, false);
+ }
+
+ WispScheduler(int parallelism, int stealRetry, int pushRetry, int helpStealRetry,
+ ThreadFactory threadFactory, WispEngine engine, boolean isRootCarrier) {
+ assert parallelism > 0;
+ PARALLEL = parallelism;
+ STEAL_RETRY = stealRetry;
+ PUSH_RETRY = pushRetry;
+ HELP_STEAL_RETRY = helpStealRetry;
+ IS_ROOT_CARRIER = isRootCarrier;
+ this.engine = engine;
+ this.threadFactory = threadFactory;
+ workers = new Worker[PARALLEL];
+ for (int i = parallelism - 1; i >= 0; i--) {
+ workers[i] = new Worker(i);
+ workers[i].next = i == PARALLEL - 1 ? null : workers[i + 1];
+ }
+ workers[PARALLEL - 1].next = workers[0];
+ if (!isRootCarrier) {
+ // root worker threads are started in startWispDaemons()
+ startWorkerThreads();
+ }
+ }
+
+ void startWorkerThreads() {
+ for (Worker worker : workers) {
+ worker.thread.start();
+ }
+ }
+
+ private int generateRandom() {
+ return sharedSeed = nextRandom(sharedSeed);
+ }
+
+ class Worker implements Runnable {
+ ConcurrentLinkedQueue taskQueue;
+ private final TimeOut.TimerManager timerManager;
+ private final Thread thread;
+ private final WispEventPump pump; // ONE pump verse N worker relationship
+ volatile boolean hasBeenHandoff = false;
+ private Worker next;
+
+ private final static int QL_PROCESSING_TIMER = -1; // idle than ql=0, but not really idle
+ private final static int QL_POLLING = -1000002;
+ private final static int QL_IDLE = -2000002;
+
+ volatile int queueLength;
+
+ Worker(int index) {
+ thread = threadFactory.newThread(this);
+ WispEngine.carrierThreads.add(thread);
+ taskQueue = new ConcurrentLinkedQueue<>();
+ timerManager = new TimeOut.TimerManager();
+ queueLength = 0;
+ pump = WispConfiguration.CARRIER_AS_POLLER && IS_ROOT_CARRIER ?
+ WispEventPump.Pool.INSTANCE.getPump(index) : null;
+ }
+
+ void processTimer() {
+ timerManager.processTimeoutEventsAndGetWaitDeadline(System.nanoTime());
+ }
+
+ @Override
+ public void run() {
+ try {
+ WispCarrier carrier = WispCarrier.current();
+ carrier.engine = WispScheduler.this.engine;
+ carrier.worker = this;
+ WispScheduler.this.engine.carrierEngines.add(carrier);
+ WispEngine.registerPerfCounter(carrier);
+ WispSysmon.INSTANCE.register(carrier);
+ runCarrier(carrier);
+ } finally {
+ WispEngine.carrierThreads.remove(thread);
+ try {
+ engine.shutdownBarrier.await();
+ } catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ System.out.println("[Wisp-ERROR] unexpected error "
+ + "on current" + Thread.currentThread() + "has exception"
+ + sw.toString());
+ }
+ }
+ }
+
+ private void runCarrier(final WispCarrier carrier) {
+ int r = randomSeed();
+ Runnable task;
+ while (true) {
+ while ((task = pollTask(false)) != null) {
+ doExec(task);
+ }
+
+ if (carrier.engine.detached) {
+ return;
+ } else if ((task = SCHEDULING_POLICY.steal(this, r = nextRandom(r))) != null) {
+ doExec(task);
+ continue; // process local queue
+ }
+ doParkOrPolling();
+ }
+ }
+
+ private void doParkOrPolling() {
+ int st = QL_PROCESSING_TIMER;
+ if (queueLength != 0 || !LENGTH_UPDATER.compareAndSet(this, 0, st)) {
+ return;
+ }
+ final long now = System.nanoTime();
+ final long deadline = timerManager.processTimeoutEventsAndGetWaitDeadline(now);
+ assert deadline != 0;
+ if (queueLength == st) {
+ int update = pump != null && pump.tryAcquire(this) ? QL_POLLING : QL_IDLE;
+ if (LENGTH_UPDATER.compareAndSet(this, st, update)) {
+ st = update;
+ if (taskQueue.peek() == null) {
+ if (st == QL_IDLE) {
+ UA.park0(false, deadline < 0 ? 0 : deadline - now);
+ } else { // st == QL_POLLING
+ doPolling(deadline, now);
+ }
+ }
+ }
+ if (update == QL_POLLING) {
+ pump.release(this);
+ }
+ }
+ LENGTH_UPDATER.addAndGet(this, -st);
+ }
+
+ private void doPolling(final long deadline, long now) {
+ while ((deadline < 0 || deadline > now) &&
+ !pump.pollAndDispatchEvents(
+ deadline < 0 ? -1 : TimeOut.nanos2Millis(deadline - now)) &&
+ queueLength == QL_POLLING) { // if wakened by event, we can still waiting..
+ now = deadline < 0 ? now : System.nanoTime();
+ }
+ }
+
+ /**
+ * @return if it is idle
+ */
+ private boolean doSignalIfNecessary(int len) {
+ Thread current = JLA.currentThread0();
+ if (thread != current) {
+ if (len == QL_IDLE) {
+ UA.unpark0(this.thread);
+ } else if (len == QL_POLLING) {
+ pump.wakeup();
+ }
+ }
+ return len < 0;
+ }
+
+ boolean idleOrPolling() {
+ return queueLength == QL_IDLE || queueLength == QL_POLLING;
+ }
+
+ boolean isProcessingTimer() {
+ return queueLength == QL_PROCESSING_TIMER;
+ }
+
+ Runnable pollTask(boolean isSteal) {
+ StealAwareRunnable task = taskQueue.poll();
+ if (task != null) {
+ LENGTH_UPDATER.decrementAndGet(this);
+ if (isSteal && !task.isStealEnable()) {
+ // disable steal is a very uncommon case,
+ // The overhead of re-enqueue is acceptable
+ // use pushAndSignal rather than offer,
+ // let the worker execute the task as soon as possible.
+ pushAndSignal(task);
+ return null;
+ }
+ }
+ return task;
+ }
+
+ /**
+ * @return if it is idle
+ */
+ boolean pushAndSignal(StealAwareRunnable task) {
+ taskQueue.offer(task);
+ return doSignalIfNecessary(LENGTH_UPDATER.getAndIncrement(this));
+ }
+
+ void signal() {
+ doSignalIfNecessary(queueLength);
+ }
+
+ void copyContextFromDetachedCarrier(Worker detachedWorker) {
+ // copy timers
+ timerManager.copyTimer(detachedWorker.timerManager.queue);
+ // drain wispTasks
+ StealAwareRunnable task;
+ while ((task = detachedWorker.taskQueue.poll()) != null) {
+ pushAndSignal(task);
+ }
+ }
+
+ WispScheduler theScheduler() {
+ return WispScheduler.this;
+ }
+ }
+
+ /**
+ * try steal one task from the most busy worker's queue
+ *
+ * @param r random seed
+ */
+ private Runnable trySteal(int r) {
+ Worker busyWorker = null;
+ for (int i = 0; i < STEAL_RETRY; i++) {
+ final Worker w = getWorker(r + i);
+ int ql = w.queueLength;
+ if (ql >= STEAL_HIGH_WATER_LEVEL) {
+ Runnable task = w.pollTask(true);
+ if (task != null) {
+ return task;
+ }
+ }
+ if (busyWorker == null || ql > busyWorker.queueLength) {
+ busyWorker = w;
+ }
+ }
+ // If busyCarrier's head is disable steal, we also miss the
+ // chance of steal from second busy worker..
+ // For disable steal is uncommon path, current implementation is good enough..
+ return busyWorker == null ? null : busyWorker.pollTask(true);
+ }
+
+ /**
+ * Find an idle worker, and push task to it's work queue
+ *
+ * @param n retry times
+ * @param command the task
+ * @param force push even all workers are busy
+ * @return success push to a idle worker
+ */
+ private boolean tryPush(int n, StealAwareRunnable command, boolean force) {
+ assert n > 0;
+ int r = generateRandom();
+ Worker idleWorker = null;
+ int idleQl = Integer.MAX_VALUE;
+
+ Worker w = getWorker(r);
+ for (int i = 0; i < n; i++, w = w.next) {
+ if (w.idleOrPolling()) {
+ if (command != null) {
+ w.pushAndSignal(command);
+ } else {
+ w.signal();
+ }
+ return true;
+ }
+ int ql = w.queueLength;
+ if (ql < idleQl) {
+ idleWorker = w;
+ idleQl = ql;
+ }
+ }
+ if (force) {
+ assert idleWorker != null && command != null;
+ idleWorker.pushAndSignal(command);
+ return true;
+ }
+ return false;
+ }
+
+ private Worker getWorker(int r) {
+ return workers[(r & IDX_MASK) % PARALLEL];
+ }
+
+ /**
+ * cast thread to worker
+ *
+ * @param detachedAsNull treat detached worker as not worker thread if detachedAsNull is true.
+ * @return null means thread is not considered as a worker
+ */
+ private Worker castToWorker(Thread thread, boolean detachedAsNull) {
+ if (thread == null) {
+ return null;
+ }
+ Worker worker = JLA.getWispTask(thread).carrier.worker;
+ if (worker == null || worker.theScheduler() != this) {
+ return null;
+ } else {
+ return detachedAsNull && worker.hasBeenHandoff ? null : worker;
+ }
+ }
+
+ void addTimer(TimeOut timeOut, Thread current) {
+ Worker worker = castToWorker(current, true);
+ if (worker != null) {
+ worker.timerManager.addTimer(timeOut);
+ } else {
+ tryPush(1, new StealAwareRunnable() {
+ @Override
+ public void run() {
+ //Adding timer to detached worker is ok since we rely on
+ //interrupt to wakeup all wispTasks in shutdown
+ Worker worker = castToWorker(JLA.currentThread0(), false);
+ assert worker != null;
+ worker.timerManager.addTimer(timeOut);
+ }
+ }, true);
+ }
+ }
+
+ void cancelTimer(TimeOut timeOut, Thread current) {
+ Worker worker = castToWorker(current, true);
+ if (worker != null) {
+ worker.timerManager.cancelTimer(timeOut);
+ }
+ }
+
+ /**
+ * Run the command on the specified thread.
+ * Used to implement Thread affinity for scheduler.
+ * When execute with detached worker thread, we try to execute this task by
+ * other workers, if this step failed command would be marked as can't be stolen,
+ * then we push this command to detached worker.
+ *
+ * @param command the code
+ * @param thread target thread
+ */
+ void executeWithWorkerThread(StealAwareRunnable command, Thread thread) {
+ final Worker worker = castToWorker(thread, false);
+ boolean stealEnable = command.isStealEnable();
+ if (worker == null || worker.hasBeenHandoff && stealEnable) {
+ // detached worker try to execute from global scheduler at first
+ execute(command);
+ } else {
+ SCHEDULING_POLICY.enqueue(worker, stealEnable, command);
+ }
+ }
+
+ enum SchedulingPolicy {
+ PULL {
+ // always enqueue to the bounded worker, but workers will steal tasks from each other.
+ @Override
+ void enqueue(Worker worker, boolean stealEnable, StealAwareRunnable command) {
+ WispScheduler scheduler = worker.theScheduler();
+ if (!worker.pushAndSignal(command) && stealEnable && scheduler.HELP_STEAL_RETRY > 0) {
+ scheduler.signalIdleWorkerToHelpSteal();
+ }
+ }
+
+ @Override
+ Runnable steal(Worker worker, int r) {
+ return worker.theScheduler().trySteal(r);
+ }
+ },
+ PUSH {
+ // never try to pull other worker's queues, but choose an idle worker when we're enqueueing
+ @Override
+ void enqueue(Worker worker, boolean stealEnable, StealAwareRunnable command) {
+ WispScheduler scheduler = worker.theScheduler();
+ if (stealEnable
+ && !(worker.idleOrPolling() || worker.isProcessingTimer())
+ && scheduler.STEAL_RETRY > 0
+ && scheduler.tryPush(scheduler.STEAL_RETRY, command, false)) {
+ return;
+ }
+ worker.pushAndSignal(command);
+ }
+
+ @Override
+ Runnable steal(Worker worker, int r) {
+ return null;
+ }
+ };
+
+ abstract void enqueue(Worker worker, boolean stealEnable, StealAwareRunnable command);
+
+ abstract Runnable steal(Worker worker, int r);
+ }
+
+ private void signalIdleWorkerToHelpSteal() {
+ tryPush(HELP_STEAL_RETRY, null, false);
+ }
+
+ /**
+ * Executes the given command at some time in the future.
+ *
+ * @param command the runnable task
+ * @throws NullPointerException if command is null
+ */
+ public void execute(StealAwareRunnable command) {
+ tryPush(PUSH_RETRY, command, true);
+ }
+
+ /**
+ * Detach worker and create a new worker to replace it.
+ * This function should only be called by Wisp-Sysmon
+ */
+ void handOffWorkerThread(Thread thread) {
+ assert WispSysmon.WISP_SYSMON_NAME.equals(Thread.currentThread().getName());
+ Worker worker = castToWorker(thread, true);
+ if (worker != null && !worker.hasBeenHandoff) {
+ worker.hasBeenHandoff = true;
+ worker.pushAndSignal(new StealAwareRunnable() {
+ @Override
+ public void run() {
+ }
+ }); // ensure `detached` visibility
+ worker.thread.setName(worker.thread.getName() + " (HandOff)");
+ Worker[] cs = Arrays.copyOf(this.workers, workers.length);
+ Worker last = cs[PARALLEL - 1];
+ for (int i = 0; i < PARALLEL; i++) {
+ if (cs[i] == worker) {
+ cs[i] = new Worker(i);
+ // tasks blocked on detached worker may not be scheduled in time
+ // because it's in long-time syscall, so we try our best to delegate
+ // all context to the new worker
+ cs[i].copyContextFromDetachedCarrier(worker);
+ cs[i].next = worker.next;
+ last.next = cs[i];
+ cs[i].thread.start();
+ break;
+ }
+ last = cs[i];
+ }
+ workers = cs;
+ WispEngine.deRegisterPerfCounter(JLA.getWispTask(thread).carrier);
+ }
+ }
+
+ /**
+ * Check if current processor number exceeds workers.length, if so we add new workers
+ * to this scheduler.
+ * This function should only be called by Wisp-Sysmon
+ */
+ void checkAndGrowWorkers(int availableProcessors) {
+ assert WispSysmon.WISP_SYSMON_NAME.equals(Thread.currentThread().getName());
+ if (availableProcessors <= workers.length) {
+ return;
+ }
+ double growFactor = (double) availableProcessors / (double) workers.length;
+ Worker[] cs = Arrays.copyOf(this.workers, availableProcessors);
+ for (int i = availableProcessors - 1; i >= workers.length; i--) {
+ if (cs[i] == null) {
+ cs[i] = new Worker(i);
+ cs[i].next = i == availableProcessors - 1 ? cs[0] : cs[i + 1];
+ }
+ }
+ cs[workers.length - 1].next = cs[workers.length];
+ for (int i = workers.length; i < availableProcessors; i++) {
+ cs[i].thread.start();
+ }
+ int originLength = workers.length;
+ workers = cs;
+ adjustParameters(originLength, growFactor);
+ }
+
+ private void adjustParameters(int originLength, double growFactor) {
+ PARALLEL = Integer.min((int) Math.round((double) originLength * growFactor),
+ workers.length);
+ PUSH_RETRY = ((int) (PARALLEL * growFactor));
+ STEAL_RETRY = ((int) (STEAL_RETRY * growFactor));
+ HELP_STEAL_RETRY = ((int) (HELP_STEAL_RETRY * growFactor));
+ }
+
+ private static void doExec(Runnable task) {
+ try {
+ task.run();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ private static int nextRandom(int r) {
+ r ^= r << 13;
+ r ^= r >>> 17;
+ return r ^ (r << 5);
+ }
+
+ private static int randomSeed() {
+ int r = 0;
+ while (r == 0) {
+ r = (int) System.nanoTime();
+ }
+ return r;
+ }
+
+ private static final AtomicIntegerFieldUpdater LENGTH_UPDATER =
+ AtomicIntegerFieldUpdater.newUpdater(Worker.class, "queueLength");
+ private static final UnsafeAccess UA = SharedSecrets.getUnsafeAccess();
+ private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispSysmon.java b/src/linux/classes/com/alibaba/wisp/engine/WispSysmon.java
new file mode 100644
index 0000000000000000000000000000000000000000..c182aca6779a2ac816bd1fa7e677618635db5205
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispSysmon.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.JavaLangAccess;
+import sun.misc.SharedSecrets;
+import sun.misc.UnsafeAccess;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.TimeUnit;
+
+enum WispSysmon {
+ INSTANCE;
+
+ static {
+ registerNatives();
+ }
+
+ private final Set carriers = new ConcurrentSkipListSet<>();
+ final static String WISP_SYSMON_NAME = "Wisp-Sysmon";
+
+ void startDaemon() {
+ if (WispConfiguration.ENABLE_HANDOFF) {
+ assert WispConfiguration.HANDOFF_POLICY != null;
+ Thread thread = new Thread(WispEngine.DAEMON_THREAD_GROUP,
+ WispSysmon.INSTANCE::sysmonLoop, WISP_SYSMON_NAME);
+ thread.setDaemon(true);
+ thread.start();
+ }
+ }
+
+ void register(WispCarrier carrier) {
+ if (WispConfiguration.ENABLE_HANDOFF) {
+ carriers.add(carrier);
+ }
+ }
+
+ private void sysmonLoop() {
+ final long interval = TimeUnit.MICROSECONDS.toNanos(WispConfiguration.SYSMON_TICK_US);
+ final long carrierCheckRate = TimeUnit.MICROSECONDS.toNanos(WispConfiguration.SYSMON_CARRIER_GROW_TICK_US);
+ final long checkCarrierOnNthTick = carrierCheckRate / interval;
+ final boolean checkCarrier = WispConfiguration.CARRIER_GROW && checkCarrierOnNthTick > 0
+ // Detach carrier's worker cnt is not specified by configuration
+ && WispConfiguration.WORKER_COUNT == Runtime.getRuntime().availableProcessors();
+ long nextTick = System.nanoTime() + interval;
+ int tick = 0;
+
+ while (true) {
+ long timeout = nextTick - System.nanoTime();
+ if (timeout > 0) {
+ do {
+ UA.park0(false, timeout);
+ } while ((timeout = nextTick - System.nanoTime()) > 0);
+ handleLongOccupation();
+ if (checkCarrier && tick++ == checkCarrierOnNthTick) {
+ WispEngine.WISP_ROOT_ENGINE.scheduler.checkAndGrowWorkers(Runtime.getRuntime().availableProcessors());
+ tick = 0;
+ }
+ } // else: we're too slow, skip a tick
+ nextTick += interval;
+ }
+ }
+
+ private final List longOccupationEngines = new ArrayList<>();
+
+ /**
+ * Handle a WispTask occupied a worker thread for long time.
+ */
+ private void handleLongOccupation() {
+ for (WispCarrier carrier : carriers) {
+ if (carrier.terminated) {
+ // remove in iteration is OK for ConcurrentSkipListSet
+ carriers.remove(carrier);
+ continue;
+ }
+ if (carrier.isRunning() && carrier.schedTick == carrier.lastSchedTick) {
+ longOccupationEngines.add(carrier);
+ }
+ carrier.lastSchedTick = carrier.schedTick;
+ }
+
+ if (!longOccupationEngines.isEmpty()) {
+ Iterator itr = longOccupationEngines.iterator();
+ while (itr.hasNext()) {
+ WispCarrier carrier = itr.next();
+ WispConfiguration.HANDOFF_POLICY.handle(carrier, !itr.hasNext());
+ itr.remove();
+ }
+ }
+ assert longOccupationEngines.isEmpty();
+ }
+
+ enum Policy {
+ HAND_OFF { // handOff the worker
+ @Override
+ void handle(WispCarrier carrier, boolean isLast) {
+ if (JLA.isInSameNative(carrier.thread)) {
+ carrier.handOff();
+ INSTANCE.carriers.remove(carrier);
+ }
+ }
+ },
+ PREEMPT { // insert a yield() after next safepoint
+ @Override
+ void handle(WispCarrier carrier, boolean isLast) {
+ markPreempted(carrier.thread, isLast);
+ }
+ },
+ ADAPTIVE { // depends on thread status
+ @Override
+ void handle(WispCarrier carrier, boolean isLast) {
+ if (JLA.isInSameNative(carrier.thread)) {
+ carrier.handOff();
+ INSTANCE.carriers.remove(carrier);
+ } else {
+ markPreempted(carrier.thread, isLast);
+ }
+ }
+ };
+
+ abstract void handle(WispCarrier carrier, boolean isLast);
+
+ }
+
+ private static native void registerNatives();
+
+
+ /**
+ * Mark the thread as running single wispTask in java too much time.
+ * And the Thread.yield() invocation will be emitted after next safepoint.
+ *
+ * @param thread the thread to mark
+ * @param force fire a force_safepoint immediately
+ */
+ private static native void markPreempted(Thread thread, boolean force);
+
+ private static final UnsafeAccess UA = SharedSecrets.getUnsafeAccess();
+ private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispTask.java b/src/linux/classes/com/alibaba/wisp/engine/WispTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ce1c4e8da03b8013044145d4c1abaca7d43f1a5
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispTask.java
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.SharedSecrets;
+import sun.misc.UnsafeAccess;
+
+import java.dyn.Coroutine;
+import java.dyn.CoroutineExitException;
+import java.nio.channels.SelectableChannel;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+
+/**
+ * {@link WispTask} provides high-level semantics of {link @Coroutine}
+ *
+ * Create {@link WispTask} via {@link WispEngine#dispatch(Runnable)} (Callable, String)} to make
+ * blocking IO operation in {@link WispTask}s to become concurrent.
+ *
+ * The creator and a newly created {@link WispTask} will automatically have parent-children relationship.
+ * When the child gets blocked on something, the {@link WispCarrier} will try to execute parent first.
+ *
+ * A {@link WispTask}'s exit will wake up the waiting parent.
+ */
+public class WispTask implements Comparable {
+ private final static AtomicInteger idGenerator = new AtomicInteger();
+
+ static final Map id2Task = new ConcurrentHashMap<>(360);
+ // global table used for all WispCarriers
+
+ static WispTask fromId(int id) {
+ WispCarrier carrier = WispCarrier.current();
+ boolean isInCritical0 = carrier.isInCritical;
+ carrier.isInCritical = true;
+ try {
+ return id2Task.get(id);
+ } finally {
+ carrier.isInCritical = isInCritical0;
+ }
+ }
+
+ static void cleanExitedTasks(List tasks) {
+ if (!tasks.isEmpty()) {
+ WispCarrier carrier = tasks.get(0).carrier;
+ boolean isInCritical0 = carrier.isInCritical;
+ carrier.isInCritical = true;
+ try {
+ for (WispTask t : tasks) {
+ id2Task.remove(t.id);
+ t.cleanup();
+ }
+ } finally {
+ carrier.isInCritical = isInCritical0;
+ }
+ }
+ }
+
+ static void cleanExitedTask(WispTask task) {
+ WispCarrier carrier = WispCarrier.current();
+ boolean isInCritical0 = carrier.isInCritical;
+ carrier.isInCritical = true;
+ try {
+ // cleanup shouldn't be executed for thread task
+ id2Task.remove(task.id);
+ } finally {
+ carrier.isInCritical = isInCritical0;
+ }
+ }
+
+ static void trackTask(WispTask task) {
+ WispCarrier carrier = WispCarrier.current();
+ boolean isInCritical0 = carrier.isInCritical;
+ carrier.isInCritical = true;
+ try {
+ id2Task.put(task.id, task);
+ } finally {
+ carrier.isInCritical = isInCritical0;
+ }
+ }
+
+ private final int id;
+
+ enum Status {
+ ALIVE, // ALIVE
+ ZOMBIE // exited
+ }
+
+ private Runnable runnable; // runnable for created task
+
+ /**
+ * Task is running in that carrier.
+ */
+ volatile WispCarrier carrier;
+
+ private String name;
+ final Coroutine ctx; // the low-level coroutine implement
+ Status status = Status.ALIVE;
+ SelectableChannel ch; // the interesting channel
+ TimeOut timeOut; // related timer
+ ClassLoader ctxClassLoader;
+
+ private final boolean isThreadTask;
+ private boolean isThreadAsWisp;
+
+ private Thread threadWrapper; // thread returned by Thread::currentThread()
+ private volatile int interrupted; // 0 means not interrupted
+ private volatile int alreadyCheckNativeInterrupt;
+
+ private volatile int jdkParkStatus;
+ private volatile int jvmParkStatus;
+ volatile int stealLock;
+ private WispTask from;
+ /**
+ * WispTask execution wrapper for schduler should only be used in wakupTask
+ */
+ final StealAwareRunnable resumeEntry;
+ // counter printed by jstack
+ private int activeCount;
+ int stealCount;
+ int stealFailureCount;
+ private int preemptCount;
+ // perf monitor
+ private long enqueueTime;
+ private long parkTime;
+ private long blockingTime;
+ private long registerEventTime;
+
+ // monolithic epoll support
+ private volatile long epollArray;
+ private volatile int epollEventNum;
+ int epollArraySize;
+
+ WispTask(WispCarrier carrier, Coroutine ctx, boolean isRealTask, boolean isThreadTask) {
+ this.isThreadTask = isThreadTask;
+ this.id = isRealTask ? idGenerator.addAndGet(1) : -1;
+ setCarrier(carrier);
+ if (isRealTask) {
+ this.ctx = ctx != null ? ctx : new CacheableCoroutine(WispConfiguration.STACK_SIZE);
+ this.ctx.setWispTask(id, this, carrier);
+ } else {
+ this.ctx = null;
+ }
+ resumeEntry = isThreadTask ? null : carrier.createResumeEntry(this);
+ }
+
+ void reset(Runnable runnable, String name, Thread thread, ClassLoader ctxLoader) {
+ assert ctx != null;
+ this.status = Status.ALIVE;
+ this.runnable = runnable;
+ this.name = name;
+ interrupted = 0;
+ ctxClassLoader = ctxLoader;
+ ch = null;
+ enqueueTime = 0;
+ parkTime = 0;
+ blockingTime = 0;
+ registerEventTime = 0;
+
+ activeCount = 0;
+ stealCount = 0;
+ stealFailureCount = 0;
+ preemptCount = 0;
+
+ // thread status
+ if (thread != null) { // calling from Thread.start()
+ NATIVE_INTERRUPTED_UPDATER.lazySet(this, 1);
+ isThreadAsWisp = true;
+ WispEngine.JLA.setWispTask(thread, this);
+ threadWrapper = thread;
+ } else {
+ // for WispThreadWrapper, skip native interrupt check
+ NATIVE_INTERRUPTED_UPDATER.lazySet(this, 0);
+ isThreadAsWisp = false;
+ if (threadWrapper == null) {
+ threadWrapper = new WispThreadWrapper(this);
+ }
+ WispEngine.JLA.setWispAlive(threadWrapper, true);
+ }
+ assert WispEngine.JLA.getWispTask(threadWrapper) == this;
+
+ if (!isThreadTask() && name != null && !threadWrapper.getName().equals(name)) {
+ threadWrapper.setName(name);
+ }
+ }
+
+ void setCarrier(WispCarrier carrier) {
+ CARRIER_UPDATER.lazySet(this, carrier);
+ }
+
+ private void cleanup() {
+ setCarrier(null);
+ threadWrapper = null;
+ ctxClassLoader = null;
+ }
+
+ class CacheableCoroutine extends Coroutine {
+ CacheableCoroutine(long stacksize) {
+ super(stacksize);
+ }
+
+ @Override
+ protected void run() {
+ while (true) {
+ assert WispCarrier.current() == carrier;
+ assert carrier.current == WispTask.this;
+ if (runnable != null) {
+ Throwable throwable = null;
+ try {
+ runOutsideWisp(runnable);
+ } catch (Throwable t) {
+ throwable = t;
+ } finally {
+ assert timeOut == null;
+ runnable = null;
+ WispEngine.JLA.setWispAlive(threadWrapper, false);
+ if (isThreadAsWisp) {
+ ThreadAsWisp.exit(threadWrapper);
+ }
+ if (throwable instanceof CoroutineExitException) {
+ throw (CoroutineExitException) throwable;
+ }
+ carrier.taskExit();
+ }
+ } else {
+ carrier.schedule();
+ }
+ }
+ }
+ }
+
+ /**
+ * Mark if wisp is running internal scheduling code or user code, this would
+ * be used in preempt to identify if it's okay to preempt
+ * Modify Coroutine::is_usermark_frame accordingly if you need to change this
+ * method, because it's name and sig are used
+ */
+ private static void runOutsideWisp(Runnable runnable) {
+ runnable.run();
+ }
+
+ /**
+ * Switch task. we need the information of {@code from} task param
+ * to do classloader switch etc..
+ *
+ * {@link #stealLock} is used in {@link WispCarrier#steal(WispTask)} .
+ */
+ static boolean switchTo(WispTask current, WispTask next) {
+ assert next.ctx != null;
+ assert WispCarrier.current() == current.carrier;
+ assert current.carrier == next.carrier;
+ next.activeCount++;
+ assert current.isThreadTask() || next.isThreadTask();
+ next.from = current;
+ STEAL_LOCK_UPDATER.lazySet(next, 1);
+ // store load barrier is not necessary
+ boolean res = current.carrier.thread.getCoroutineSupport().unsafeSymmetricYieldTo(next.ctx);
+ assert current.stealLock != 0;
+ STEAL_LOCK_UPDATER.lazySet(current.from, 0);
+ assert WispCarrier.current() == current.carrier;
+ assert current.carrier.current == current;
+ return res;
+ }
+
+ /**
+ * @return {@code false} if current {@link WispTask} is thread-emulated.
+ */
+ boolean isThreadTask() {
+ return isThreadTask;
+ }
+
+ /**
+ * Let currently executing task sleep for specified number of milliseconds.
+ *
+ * May be wakened up early by an available IO.
+ */
+ static void sleep(long ms) {
+ if (ms < 0) throw new IllegalArgumentException();
+
+ if (ms == 0) {
+ WispCarrier.current().yield();
+ } else {
+ WispCarrier.current().unregisterEvent();
+ jdkPark(TimeUnit.MILLISECONDS.toNanos(ms));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "WispTask" + id + "(" +
+ "name=" + name + ')' +
+ "{status=" + status + "/" +
+ jdkParkStatus + ", " +
+ '}';
+ }
+
+ public String getName() {
+ return name;
+ }
+
+
+ private static final int
+ WAITING = -1, // was blocked
+ FREE = 0, // the Initial Park status
+ PERMITTED = 1; // another task give a permit to make the task not block at next park()
+
+ static final String SHUTDOWN_TASK_NAME = "SHUTDOWN_TASK";
+
+ boolean isAlive() {
+ return status != Status.ZOMBIE;
+ }
+
+ /**
+ * If a permit is available, it will be consumed and this function returns
+ * immediately; otherwise
+ * current task will become blocked until {@link #unpark()} ()} happens.
+ *
+ * @param timeoutNano <= 0 park forever
+ * else park with given timeout
+ */
+ private void parkInternal(long timeoutNano, boolean fromJvm) {
+ if (timeoutNano > 0 && timeoutNano < WispConfiguration.MIN_PARK_NANOS) {
+ carrier.yield();
+ return;
+ }
+ final AtomicIntegerFieldUpdater statusUpdater = fromJvm ? JVM_PARK_UPDATER : JDK_PARK_UPDATER;
+ final boolean isInCritical0 = carrier.isInCritical;
+ carrier.isInCritical = true;
+ try {
+ carrier.getCounter().incrementParkCount();
+ for (;;) {
+ int s = statusUpdater.get(this);
+ assert s != WAITING; // if parkStatus == WAITING, should already blocked
+
+ if (s == FREE && statusUpdater.compareAndSet(this, FREE, WAITING)) {
+ // may become PERMITTED here; need retry.
+ // another thread unpark here is ok:
+ // current task is put to unpark queue,
+ // and will wake up eventually
+ if (WispEngine.runningAsCoroutine(threadWrapper) && timeoutNano > 0) {
+ carrier.addTimer(timeoutNano + System.nanoTime(), fromJvm);
+ }
+ carrier.isInCritical = isInCritical0;
+ try {
+ if (WispEngine.runningAsCoroutine(threadWrapper)) {
+ setParkTime();
+ carrier.schedule();
+ } else {
+ UA.park0(false, timeoutNano < 0 ? 0 : timeoutNano);
+ }
+ } finally {
+ carrier.isInCritical = true;
+ if (timeoutNano > 0) {
+ carrier.cancelTimer();
+ }
+ // we'may direct wakeup by current carrier
+ // the statue may be still WAITING..
+ statusUpdater.lazySet(this, FREE);
+ }
+ break;
+ } else if (s == PERMITTED &&
+ (statusUpdater.compareAndSet(this, PERMITTED, FREE))) {
+ // consume the permit
+ break;
+ }
+ }
+ } finally {
+ carrier.isInCritical = isInCritical0;
+ }
+ }
+
+ /**
+ * If the thread was blocked on {@link #park(long)} then it will unblock.
+ * Otherwise, its next call to {@link #park(long)} is guaranteed not to block.
+ */
+ private void unparkInternal(boolean fromJvm) {
+ AtomicIntegerFieldUpdater statusUpdater = fromJvm ? JVM_PARK_UPDATER : JDK_PARK_UPDATER;
+ for (;;) {
+ int s = statusUpdater.get(this);
+ if (s == WAITING && statusUpdater.compareAndSet(this, WAITING, FREE)) {
+ if (WispEngine.runningAsCoroutine(threadWrapper)) {
+ recordOnUnpark(fromJvm);
+ carrier.wakeupTask(this);
+ } else {
+ UA.unpark0(threadWrapper);
+ }
+ break;
+ } else if (s == PERMITTED ||
+ (s == FREE && statusUpdater.compareAndSet(this, FREE, PERMITTED))) {
+ // add a permit
+ break;
+ }
+ }
+ }
+
+ /**
+ * Park Invoked by jdk, include IO, JUC etc..
+ */
+ static void jdkPark(long timeoutNano) {
+ WispCarrier.current().getCurrentTask().parkInternal(timeoutNano, false);
+ }
+
+ void jdkUnpark() {
+ unparkInternal(false);
+ }
+
+ /**
+ * Invoked by VM to support coroutine switch in object monitor case.
+ */
+ private static void park(long timeoutNano) {
+ WispCarrier.current().getCurrentTask().parkInternal(timeoutNano, true);
+ }
+
+ void unpark() {
+ unparkInternal(true);
+ }
+
+ // direct called by jvm runtime if UseDirectUnpark
+ static void unparkById(int id) {
+ WispTask t = fromId(id);
+ if (t != null) {
+ t.unpark();
+ }
+ }
+
+ void interrupt() {
+ // For JSR166. Unpark even if interrupt status was already set.
+ interrupted = 1;
+ unpark();
+ jdkUnpark();
+ }
+
+ private static void interruptById(int id) {
+ WispTask t = fromId(id);
+ if (t != null) {
+ t.interrupt();
+ }
+ }
+
+ boolean isInterrupted() {
+ return interrupted != 0;
+ }
+
+ boolean testInterruptedAndClear(boolean clear) {
+ boolean nativeInterrupt = false;
+ if (alreadyCheckNativeInterrupt == 0 && // only do it once
+ NATIVE_INTERRUPTED_UPDATER.compareAndSet(this, 0, 1) &&
+ !isInterrupted()) {
+ nativeInterrupt = checkAndClearNativeInterruptForWisp(threadWrapper);
+ }
+ boolean res = interrupted != 0 || nativeInterrupt;
+ if (res && clear) {
+ INTERRUPTED_UPDATER.lazySet(this, 0);
+ }
+ // return old interrupt status.
+ return res;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ WispTask t = (WispTask) o;
+ return Objects.equals(id, t.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ public Thread getThreadWrapper() {
+ return threadWrapper;
+ }
+
+ void setThreadWrapper(Thread thread) {
+ threadWrapper = thread;
+ WispEngine.JLA.setWispTask(thread, this);
+ }
+
+ void resetThreadWrapper() {
+ if (isThreadAsWisp) {
+ threadWrapper = null;
+ }
+ }
+
+ @Override
+ public int compareTo(WispTask o) {
+ return Integer.compare(this.id, o.id);
+ }
+
+ long getEpollArray() {
+ return epollArray;
+ }
+
+ void setEpollArray(long epollArray) {
+ EPOLL_ARRAY_UPDATER.lazySet(this, epollArray);
+ }
+
+ int getEpollEventNum() {
+ return epollEventNum;
+ }
+
+ void setEpollEventNum(int epollEventNum) {
+ EPOLL_EVENT_NUM_UPDATER.lazySet(this, epollEventNum);
+ }
+
+ void updateEnqueueTime() {
+ if (!WispConfiguration.WISP_PROFILE) {
+ return;
+ }
+ // in wisp2, if the task is stealed unsuccessfully, it will be put into queue again
+ if (enqueueTime != 0) {
+ return;
+ }
+ enqueueTime = System.nanoTime();
+ }
+
+ long getEnqueueTime() {
+ return enqueueTime;
+ }
+
+ void resetEnqueueTime() {
+ enqueueTime = 0;
+ }
+
+ void setRegisterEventTime() {
+ // only count the time which is spent on WispTask by service
+ registerEventTime = (!WispConfiguration.WISP_PROFILE || isThreadTask) ? 0 : System.nanoTime();
+ }
+
+ void resetRegisterEventTime() {
+ registerEventTime = 0;
+ }
+
+ void countWaitSocketIOTime() {
+ if (registerEventTime != 0) {
+ carrier.counter.incrementTotalWaitSocketIOTime(System.nanoTime() - registerEventTime);
+ registerEventTime = 0;
+ }
+ }
+
+ private void setParkTime() {
+ parkTime = (!WispConfiguration.WISP_PROFILE || isThreadTask) ? 0 : System.nanoTime();
+ }
+
+ /* When unpark is called, the time is set.
+ * Since the unpark may be called by non-worker thread, the count is delayed.
+ */
+ private void recordOnUnpark(boolean fromJVM) {
+ if (!WispConfiguration.WISP_PROFILE) {
+ return;
+ }
+ if (parkTime != 0) {
+ blockingTime = System.nanoTime() - parkTime;
+ if (blockingTime < 0) {
+ blockingTime = 0;
+ }
+ parkTime = 0;
+ }
+ if (fromJVM) {
+ carrier.counter.incrementUnparkFromJvmCount();
+ }
+ }
+
+ void countExecutionTime(long beginTime) {
+ // TaskExit set beginTime to 0, and calls schedule,
+ // then beginTime is 0. It need to skip it.
+ if (!WispConfiguration.WISP_PROFILE || beginTime == 0) {
+ return;
+ }
+ carrier.counter.incrementTotalExecutionTime(System.nanoTime() - beginTime);
+ if (blockingTime != 0) {
+ carrier.counter.incrementTotalBlockingTime(blockingTime);
+ blockingTime = 0;
+ }
+ }
+
+ StackTraceElement[] getStackTrace() {
+ return this.ctx.getCoroutineStack();
+ }
+
+ private static final AtomicReferenceFieldUpdater CARRIER_UPDATER;
+ private static final AtomicIntegerFieldUpdater JVM_PARK_UPDATER;
+ private static final AtomicIntegerFieldUpdater JDK_PARK_UPDATER;
+ private static final AtomicIntegerFieldUpdater INTERRUPTED_UPDATER;
+ private static final AtomicIntegerFieldUpdater NATIVE_INTERRUPTED_UPDATER;
+ private static final AtomicIntegerFieldUpdater STEAL_LOCK_UPDATER;
+ private static final AtomicLongFieldUpdater EPOLL_ARRAY_UPDATER;
+ private static final AtomicIntegerFieldUpdater EPOLL_EVENT_NUM_UPDATER;
+ private static final UnsafeAccess UA = SharedSecrets.getUnsafeAccess();
+
+ private static native void registerNatives();
+
+ // only for wisp to clear the native interrupt, for parallel interrupt problem.
+ private static native boolean checkAndClearNativeInterruptForWisp(Thread cur);
+
+ static {
+ CARRIER_UPDATER = AtomicReferenceFieldUpdater.newUpdater(WispTask.class, WispCarrier.class, "carrier");
+ JVM_PARK_UPDATER = AtomicIntegerFieldUpdater.newUpdater(WispTask.class, "jvmParkStatus");
+ JDK_PARK_UPDATER = AtomicIntegerFieldUpdater.newUpdater(WispTask.class, "jdkParkStatus");
+ INTERRUPTED_UPDATER = AtomicIntegerFieldUpdater.newUpdater(WispTask.class, "interrupted");
+ NATIVE_INTERRUPTED_UPDATER = AtomicIntegerFieldUpdater.newUpdater(WispTask.class, "alreadyCheckNativeInterrupt");
+ STEAL_LOCK_UPDATER = AtomicIntegerFieldUpdater.newUpdater(WispTask.class, "stealLock");
+ EPOLL_ARRAY_UPDATER = AtomicLongFieldUpdater.newUpdater(WispTask.class, "epollArray");
+ EPOLL_EVENT_NUM_UPDATER = AtomicIntegerFieldUpdater.newUpdater(WispTask.class, "epollEventNum");
+ registerNatives();
+ }
+}
diff --git a/src/linux/classes/com/alibaba/wisp/engine/WispThreadWrapper.java b/src/linux/classes/com/alibaba/wisp/engine/WispThreadWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..5675dad24a96550ffaf5cc13dd661da3ed1baaff
--- /dev/null
+++ b/src/linux/classes/com/alibaba/wisp/engine/WispThreadWrapper.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.JavaLangAccess;
+import sun.misc.SharedSecrets;
+import sun.reflect.CallerSensitive;
+
+import java.dyn.CoroutineSupport;
+
+/**
+ * An wrapper of {@link Thread} let every {@link WispTask} get different thread
+ * object from {@link Thread#currentThread()}.
+ * In this way, we make the listed class (not only but include) behave expected without
+ * changing their code.
+ *
+ * 1. {@link ThreadLocal}
+ * 2. {@link java.util.concurrent.locks.AbstractQueuedSynchronizer} based synchronizer
+ * 3. Netty's judgment of weather we are running in it's worker thread.
+ */
+class WispThreadWrapper extends Thread {
+
+ WispThreadWrapper(WispTask task) {
+ JLA.setWispTask(this, task);
+ setName(task.getName());
+ }
+
+ @Override
+ public CoroutineSupport getCoroutineSupport() {
+ return JLA.getWispTask(this).carrier.thread.getCoroutineSupport();
+ }
+
+ @Override
+ public void start() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ @Deprecated
+ public void destroy() {
+ }
+
+ @Override
+ @Deprecated
+ public int countStackFrames() {
+ return JLA.getWispTask(this).carrier.thread.countStackFrames();
+ }
+
+ @Override
+ @CallerSensitive
+ public ClassLoader getContextClassLoader() {
+ return JLA.getWispTask(this).ctxClassLoader;
+ }
+
+ @Override
+ public void setContextClassLoader(ClassLoader cl) {
+ JLA.getWispTask(this).ctxClassLoader = cl;
+ }
+
+ @Override
+ public StackTraceElement[] getStackTrace() {
+ return super.getStackTrace();
+ }
+
+ @Override
+ public long getId() {
+ return super.getId();
+ }
+
+ @Override
+ public State getState() {
+ return JLA.getWispTask(this).carrier.thread.getState();
+ }
+
+ @Override
+ public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+ return JLA.getWispTask(this).carrier.thread.getUncaughtExceptionHandler();
+ }
+
+ @Override
+ public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
+ JLA.getWispTask(this).carrier.thread.setUncaughtExceptionHandler(eh);
+ }
+
+ @Override
+ public String toString() {
+ return "WispThreadWrapper{" +
+ "wispTask=" + JLA.getWispTask(this) +
+ '}';
+ }
+
+ private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+}
diff --git a/src/linux/classes/sun/nio/ch/IOEvent.java b/src/linux/classes/sun/nio/ch/IOEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..179d307675141deeef19edc2e1f7ab3bdf7500bb
--- /dev/null
+++ b/src/linux/classes/sun/nio/ch/IOEvent.java
@@ -0,0 +1,9 @@
+package sun.nio.ch;
+
+public class IOEvent {
+
+ public static Class> eventClass() {
+ return EPollPort.class;
+ }
+
+}
\ No newline at end of file
diff --git a/src/linux/classes/sun/nio/ch/WispServerSocketImpl.java b/src/linux/classes/sun/nio/ch/WispServerSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a17cf6860301438d92d7bcb6abce104d4876132
--- /dev/null
+++ b/src/linux/classes/sun/nio/ch/WispServerSocketImpl.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.TimeUnit;
+
+
+// Make a server socket channel be like a socket and yield on block
+
+public class WispServerSocketImpl
+{
+ private static WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
+
+ private WispSocketLockSupport wispSocketLockSupport = new WispSocketLockSupport();
+ // The channel being adapted
+ private ServerSocketChannelImpl ssc = null;
+
+ // Timeout "option" value for accepts
+ private volatile int timeout = 0;
+
+ public WispServerSocketImpl() {
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ bind(local, 50);
+ }
+
+ public void bind(SocketAddress local, int backlog) throws IOException {
+ if (local == null)
+ local = new InetSocketAddress(0);
+ try {
+ getChannelImpl().bind(local, backlog);
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public InetAddress getInetAddress() {
+ if (ssc == null || !ssc.isBound())
+ return null;
+ return Net.getRevealedLocalAddress(ssc.localAddress()).getAddress();
+ }
+
+ public int getLocalPort() {
+ if (ssc == null || !ssc.isBound())
+ return -1;
+ return Net.asInetSocketAddress(ssc.localAddress()).getPort();
+ }
+
+ public Socket accept() throws IOException {
+ try {
+ wispSocketLockSupport.beginRead();
+ return accept0();
+ } finally {
+ wispSocketLockSupport.endRead();
+ }
+ }
+
+ private Socket accept0() throws IOException {
+ final ServerSocketChannel ch = getChannelImpl();
+ try {
+ SocketChannel res;
+
+ if (getSoTimeout() > 0) {
+ WEA.addTimer(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(getSoTimeout()));
+ }
+
+ while ((res = ch.accept()) == null) {
+ WEA.registerEvent(ch, SelectionKey.OP_ACCEPT);
+ WEA.park(-1);
+
+ if (getSoTimeout() > 0 && WEA.isTimeout()) {
+ throw new SocketTimeoutException("time out");
+ }
+ }
+ res.configureBlocking(false);
+ return new Socket(res);
+
+ } catch (Exception x) {
+ Net.translateException(x, true);
+ return null;
+ } finally {
+ if (getSoTimeout() > 0) {
+ WEA.cancelTimer();
+ }
+ WEA.unregisterEvent();
+ }
+ }
+
+ public void close() throws IOException {
+ if (ssc != null) {
+ ssc.close();
+ wispSocketLockSupport.unparkBlockedWispTask();
+ }
+ }
+
+ public ServerSocketChannel getChannel() {
+ return ssc;
+ }
+
+ public boolean isBound() {
+ return ssc != null && ssc.isBound();
+ }
+
+ public boolean isClosed() {
+ return ssc != null && !ssc.isOpen();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ this.timeout = timeout;
+ }
+
+ public int getSoTimeout() throws IOException {
+ return timeout;
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ try {
+ getChannelImpl().setOption(StandardSocketOptions.SO_REUSEADDR, on);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ try {
+ return getChannelImpl().getOption(StandardSocketOptions.SO_REUSEADDR);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return false; // Never happens
+ }
+ }
+
+ public String toString() {
+ if (!isBound())
+ return "ServerSocket[unbound]";
+ return "ServerSocket[addr=" + getInetAddress() +
+ ",localport=" + getLocalPort() + "]";
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ if (size <= 0)
+ throw new IllegalArgumentException("size can not be 0 or negative");
+ try {
+ getChannelImpl().setOption(StandardSocketOptions.SO_RCVBUF, size);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ try {
+ return getChannelImpl().getOption(StandardSocketOptions.SO_RCVBUF);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return -1; // Never happens
+ }
+ }
+
+ private ServerSocketChannelImpl getChannelImpl() throws SocketException {
+ if (ssc == null) {
+ try {
+ ssc = (ServerSocketChannelImpl) ServerSocketChannel.open();
+ ssc.configureBlocking(false);
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+ return ssc;
+ }
+}
diff --git a/src/linux/classes/sun/nio/ch/WispSocketImpl.java b/src/linux/classes/sun/nio/ch/WispSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a45331e69e18c8b008868522379e9374a31cbc6
--- /dev/null
+++ b/src/linux/classes/sun/nio/ch/WispSocketImpl.java
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.TimeUnit;
+
+
+// Make a socket channel be like a socket and yield on block
+
+public class WispSocketImpl
+{
+ private static WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
+
+ WispSocketLockSupport wispSocketLockSupport = new WispSocketLockSupport();
+ // The channel being adapted
+ private SocketChannelImpl sc = null;
+ // 1 verse 1 related socket
+ private Socket so;
+ // Timeout "option" value for reads
+ protected int timeout = 0;
+ private InputStream socketInputStream = null;
+
+ public WispSocketImpl(Socket so) {
+ this.so = so;
+ }
+
+ public WispSocketImpl(SocketChannel sc, Socket so) {
+ this.so = so;
+ this.sc = (SocketChannelImpl) sc;
+ }
+
+ public SocketChannel getChannel() {
+ return sc;
+ }
+
+ // Override this method just to protect against changes in the superclass
+ //
+ public void connect(SocketAddress remote) throws IOException {
+ connect(remote, 0);
+ }
+
+ public void connect(SocketAddress remote, int timeout) throws IOException {
+ if (remote == null)
+ throw new IllegalArgumentException("connect: The address can't be null");
+ if (timeout < 0)
+ throw new IllegalArgumentException("connect: timeout can't be negative");
+
+ final SocketChannel ch = getChannelImpl();
+ try {
+ wispSocketLockSupport.beginWrite();
+ if (ch.connect(remote)) return;
+
+ if (timeout > 0)
+ WEA.addTimer(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout));
+
+ do {
+ WEA.registerEvent(ch, SelectionKey.OP_CONNECT);
+ WEA.park(-1);
+
+ if (timeout > 0 && WEA.isTimeout()) {
+ throw new SocketTimeoutException("time out");
+ }
+ } while (!ch.finishConnect());
+
+ } catch (Exception x) {
+ // see AbstractPlainSocketImpl#doConnect
+ try {
+ Net.translateException(x, true);
+ } catch (IOException e) {
+ sc.close();
+ throw e;
+ }
+ } finally {
+ wispSocketLockSupport.endWrite();
+ if (timeout > 0) {
+ WEA.cancelTimer();
+ }
+
+ if (ch.isBlocking())
+ ch.configureBlocking(false);
+
+ WEA.unregisterEvent();
+ }
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ try {
+ getChannelImpl().bind(local);
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public InetAddress getInetAddress() {
+ SocketAddress remote = sc == null ? null : sc.remoteAddress();
+ if (remote == null) {
+ return null;
+ } else {
+ return ((InetSocketAddress)remote).getAddress();
+ }
+ }
+
+ public InetAddress getLocalAddress() {
+ SocketChannelImpl ch = null;
+ try {
+ ch = getChannelImpl();
+ } catch (SocketException e) {
+ // return 0.0.0.0
+ }
+ if (ch != null && ch.isOpen()) {
+ InetSocketAddress local = ch.localAddress();
+ if (local != null) {
+ return Net.getRevealedLocalAddress(local).getAddress();
+ }
+ }
+ return new InetSocketAddress(0).getAddress();
+ }
+
+ public int getPort() {
+ SocketAddress remote = sc == null ? null : sc.remoteAddress();
+ if (remote == null) {
+ return 0;
+ } else {
+ return ((InetSocketAddress)remote).getPort();
+ }
+ }
+
+ public int getLocalPort() {
+ SocketChannelImpl ch = null;
+ try {
+ ch = getChannelImpl();
+ } catch (SocketException e) {
+ // return 0.0.0.0
+ }
+ SocketAddress local = ch == null ? null : ch.localAddress();
+ if (local == null) {
+ return -1;
+ } else {
+ return ((InetSocketAddress)local).getPort();
+ }
+ }
+
+ public InputStream getInputStream() throws IOException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ if (!isConnected())
+ throw new SocketException("Socket is not connected");
+ if (isInputShutdown())
+ throw new SocketException("Socket input is shutdown");
+ if (socketInputStream == null) {
+ try {
+ socketInputStream = AccessController.doPrivileged(
+ new PrivilegedExceptionAction() {
+ public InputStream run() throws IOException {
+ return new InputStream() {
+ protected final SocketChannel ch = getChannelImpl();
+ private ByteBuffer bb = null;
+ // Invoker's previous array
+ private byte[] bs = null;
+ private byte[] b1 = null;
+
+ private ByteBuffer readAhead = null;
+
+ @Override
+ public int read() throws IOException {
+ if (b1 == null) {
+ b1 = new byte[1];
+ }
+ int n = this.read(b1);
+ if (n == 1)
+ return b1[0] & 0xff;
+ return -1;
+ }
+
+ @Override
+ public int read(byte[] bs, int off, int len)
+ throws IOException {
+ if (len <= 0 || off < 0 || off + len > bs.length) {
+ if (len == 0) {
+ return 0;
+ }
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ ByteBuffer bb = ((this.bs == bs) ? this.bb : ByteBuffer.wrap(bs));
+
+ bb.limit(Math.min(off + len, bb.capacity()));
+ bb.position(off);
+ this.bb = bb;
+ this.bs = bs;
+ return read(bb);
+ }
+
+
+ private int read(ByteBuffer bb) throws IOException {
+ try {
+ wispSocketLockSupport.beginRead();
+ return read0(bb);
+ } finally {
+ wispSocketLockSupport.endRead();
+ }
+ }
+
+ private int read0(ByteBuffer bb)
+ throws IOException {
+ int n;
+ try {
+ if (readAhead != null && readAhead.hasRemaining()) {
+ if (bb.remaining() >= readAhead.remaining()) {
+ n = readAhead.remaining();
+ bb.put(readAhead);
+ } else {
+ n = bb.remaining();
+ for (int i = 0; i < n; i++) {
+ bb.put(readAhead.get());
+ }
+ }
+ return n;
+ }
+
+ if ((n = ch.read(bb)) != 0) {
+ return n;
+ }
+
+ if (so.getSoTimeout() > 0) {
+ WEA.addTimer(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(so.getSoTimeout()));
+ }
+
+ do {
+ WEA.registerEvent(ch, SelectionKey.OP_READ);
+ WEA.park(-1);
+
+ if (so.getSoTimeout() > 0 && WEA.isTimeout()) {
+ throw new SocketTimeoutException("time out");
+
+ }
+ } while ((n = ch.read(bb)) == 0);
+ } finally {
+ if (so.getSoTimeout() > 0) {
+ WEA.cancelTimer();
+ }
+ WEA.unregisterEvent();
+ }
+
+ return n;
+ }
+
+ @Override
+ public int available() throws IOException {
+ if (readAhead == null) {
+ readAhead = ByteBuffer.allocate(4096);
+ } else if (readAhead.hasRemaining()) {
+ return readAhead.remaining();
+ }
+
+ readAhead.clear();
+ ch.read(readAhead);
+ readAhead.flip();
+
+ return readAhead.remaining();
+ }
+
+ @Override
+ public void close() throws IOException {
+ WispSocketImpl.this.close();
+ }
+ };
+ }
+ });
+ } catch (java.security.PrivilegedActionException e) {
+ throw (IOException)e.getException();
+ }
+ }
+ return socketInputStream;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ if (!isConnected())
+ throw new SocketException("Socket is not connected");
+ if (isOutputShutdown())
+ throw new SocketException("Socket output is shutdown");
+ try {
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction() {
+ public OutputStream run() throws IOException {
+ return new OutputStream() {
+ protected final SocketChannel ch = getChannelImpl();
+ private ByteBuffer bb = null;
+ // Invoker's previous array
+ private byte[] bs = null;
+ private byte[] b1 = null;
+
+
+ @Override
+ public void write(int b) throws IOException {
+ if (b1 == null) {
+ b1 = new byte[1];
+ }
+ b1[0] = (byte) b;
+ this.write(b1);
+ }
+
+ @Override
+ public void write(byte[] bs, int off, int len)
+ throws IOException
+ {
+ if (len <= 0 || off < 0 || off + len > bs.length) {
+ if (len == 0) {
+ return;
+ }
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ ByteBuffer bb = ((this.bs == bs) ? this.bb : ByteBuffer.wrap(bs));
+ bb.limit(Math.min(off + len, bb.capacity()));
+ bb.position(off);
+ this.bb = bb;
+ this.bs = bs;
+
+ write(bb);
+ }
+
+ private void write(ByteBuffer bb) throws IOException {
+ try {
+ wispSocketLockSupport.beginWrite();
+ write0(bb);
+ } finally {
+ wispSocketLockSupport.endWrite();
+ }
+ }
+
+ private void write0(ByteBuffer bb)
+ throws IOException {
+
+ try {
+ int writeLen = bb.remaining();
+ if (ch.write(bb) == writeLen) {
+ return;
+ }
+
+ if (so.getSoTimeout() > 0) {
+ WEA.addTimer(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(so.getSoTimeout()));
+ }
+
+ do {
+ WEA.registerEvent(ch, SelectionKey.OP_WRITE);
+ WEA.park(-1);
+
+ if (so.getSoTimeout() > 0 && WEA.isTimeout()) {
+ throw new SocketTimeoutException("time out");
+ }
+ ch.write(bb);
+ } while (bb.remaining() > 0);
+ } finally {
+ if (so.getSoTimeout() > 0) {
+ WEA.cancelTimer();
+ }
+ WEA.unregisterEvent();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ WispSocketImpl.this.close();
+ }
+ };
+ }
+ });
+ } catch (java.security.PrivilegedActionException e) {
+ throw (IOException)e.getException();
+ }
+ }
+
+ private void setBooleanOption(SocketOption name, boolean value)
+ throws SocketException {
+ try {
+ getChannelImpl().setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private void setIntOption(SocketOption name, int value)
+ throws SocketException {
+ try {
+ getChannelImpl().setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private boolean getBooleanOption(SocketOption name) throws SocketException {
+ try {
+ return getChannelImpl().getOption(name);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return false; // keep compiler happy
+ }
+ }
+
+ private int getIntOption(SocketOption name) throws SocketException {
+ try {
+ return getChannelImpl().getOption(name);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return -1; // keep compiler happy
+ }
+ }
+
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
+ }
+
+ public boolean getTcpNoDelay() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
+ }
+
+ public void setSoLinger(boolean on, int linger) throws SocketException {
+ if (!on)
+ linger = -1;
+ setIntOption(StandardSocketOptions.SO_LINGER, linger);
+ }
+
+ public int getSoLinger() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_LINGER);
+ }
+
+ public void sendUrgentData(int data) throws IOException {
+ int n = getChannelImpl().sendOutOfBandData((byte) data);
+ if (n == 0)
+ throw new IOException("Socket buffer full");
+ }
+
+ public void setOOBInline(boolean on) throws SocketException {
+ setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
+ }
+
+ public boolean getOOBInline() throws SocketException {
+ return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ if (timeout < 0)
+ throw new IllegalArgumentException("timeout can't be negative");
+ this.timeout = timeout;
+ }
+
+ public int getSoTimeout() throws SocketException {
+ return timeout;
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ // size 0 valid for SocketChannel, invalid for Socket
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid send size");
+ setIntOption(StandardSocketOptions.SO_SNDBUF, size);
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_SNDBUF);
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ // size 0 valid for SocketChannel, invalid for Socket
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid receive size");
+ setIntOption(StandardSocketOptions.SO_RCVBUF, size);
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_RCVBUF);
+ }
+
+ public void setKeepAlive(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);
+ }
+
+ public boolean getKeepAlive() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ setIntOption(StandardSocketOptions.IP_TOS, tc);
+ }
+
+ public int getTrafficClass() throws SocketException {
+ return getIntOption(StandardSocketOptions.IP_TOS);
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
+ }
+
+ public void close() throws IOException {
+ if (sc != null) {
+ sc.close();
+ wispSocketLockSupport.unparkBlockedWispTask();
+ }
+ }
+
+ public void shutdownInput() throws IOException {
+ try {
+ getChannelImpl().shutdownInput();
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public void shutdownOutput() throws IOException {
+ try {
+ getChannelImpl().shutdownOutput();
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public String toString() {
+ if (isConnected())
+ return "Socket[addr=" + getInetAddress() +
+ ",port=" + getPort() +
+ ",localport=" + getLocalPort() + "]";
+ return "Socket[unconnected]";
+ }
+
+ public boolean isConnected() {
+ return sc != null && sc.isConnected();
+ }
+
+ public boolean isBound() {
+ return sc != null && sc.localAddress() != null;
+ }
+
+ public boolean isClosed() {
+ return sc != null && !sc.isOpen();
+ }
+
+ public boolean isInputShutdown() {
+ return sc != null && !sc.isInputOpen();
+ }
+
+ public boolean isOutputShutdown() {
+ return sc != null && !sc.isOutputOpen();
+ }
+
+ private SocketChannelImpl getChannelImpl() throws SocketException {
+ if (sc == null) {
+ try {
+ sc = (SocketChannelImpl) SocketChannel.open();
+ sc.configureBlocking(false);
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+ return sc;
+ }
+}
diff --git a/src/linux/classes/sun/nio/ch/WispSocketLockSupport.java b/src/linux/classes/sun/nio/ch/WispSocketLockSupport.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4ec5eefa33b856e4c340b268fa20cad8b24a4e4
--- /dev/null
+++ b/src/linux/classes/sun/nio/ch/WispSocketLockSupport.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * This class supports fd use across {@link WispTask} by adding read/write reentrantLocks for
+ * {@link WispSocketImpl} {@link WispServerSocketImpl} and {@link WispUdpSocketImpl},
+ * {@link WispTask}s will park once they encountered a contended socket.
+ */
+class WispSocketLockSupport {
+ private static WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
+
+ /** Lock held when reading and accepting
+ */
+ private final ReentrantLock readLock = WEA.enableSocketLock()? new ReentrantLock() : null;
+
+ /** Lock held when writing and connecting
+ */
+ private final ReentrantLock writeLock = WEA.enableSocketLock()? new ReentrantLock() : null;
+
+ /** Lock held when tracking current blocked WispTask and closing
+ */
+ private final ReentrantLock stateLock = WEA.enableSocketLock()? new ReentrantLock() : null;
+
+ WispTask blockedReadWispTask = null;
+ WispTask blockedWriteWispTask = null;
+
+ /**
+ * This is not a ReadWriteLock, they are separate locks here, readLock protect
+ * reading to fd while writeLock protect writing to fd.
+ */
+ private void lockRead() {
+ readLock.lock();
+ }
+
+ private void lockWrite() {
+ writeLock.lock();
+ }
+
+ private void unLockRead() {
+ readLock.unlock();
+ }
+
+ private void unLockWrite() {
+ writeLock.unlock();
+ }
+
+ void beginRead() {
+ if (!WEA.enableSocketLock()) {
+ return;
+ }
+ lockRead();
+ stateLock.lock();
+ try {
+ blockedReadWispTask = WEA.getCurrentTask();
+ } finally {
+ stateLock.unlock();
+ }
+ }
+
+ void endRead() {
+ if (!WEA.enableSocketLock()) {
+ return;
+ }
+
+ stateLock.lock();
+ try {
+ blockedReadWispTask = null;
+ } finally {
+ stateLock.unlock();
+ }
+ unLockRead();
+ }
+
+ void beginWrite() {
+ if (!WEA.enableSocketLock()) {
+ return;
+ }
+ lockWrite();
+ stateLock.lock();
+ try {
+ blockedWriteWispTask = WEA.getCurrentTask();
+ } finally {
+ stateLock.unlock();
+ }
+ }
+
+ void endWrite() {
+ if (!WEA.enableSocketLock()) {
+ return;
+ }
+ stateLock.lock();
+ try {
+ blockedWriteWispTask = null;
+ } finally {
+ stateLock.unlock();
+ }
+ unLockWrite();
+ }
+
+ void unparkBlockedWispTask() {
+ stateLock.lock();
+ try {
+ if (blockedReadWispTask != null) {
+ WEA.unpark(blockedReadWispTask);
+ blockedReadWispTask = null;
+ }
+ if (blockedWriteWispTask != null) {
+ WEA.unpark(blockedWriteWispTask);
+ blockedWriteWispTask = null;
+ }
+ } finally {
+ stateLock.unlock();
+ }
+ }
+}
diff --git a/src/linux/classes/sun/nio/ch/WispUdpSocketImpl.java b/src/linux/classes/sun/nio/ch/WispUdpSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4cd5c781b9fd3eddca83706e7246ab320243844f
--- /dev/null
+++ b/src/linux/classes/sun/nio/ch/WispUdpSocketImpl.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeUnit;
+
+
+// Make a udp socket channel look like a datagram socket.
+
+public class WispUdpSocketImpl {
+
+ private static WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
+
+ private WispSocketLockSupport wispSocketLockSupport = new WispSocketLockSupport();
+ // 1 verse 1 related socket
+ private DatagramChannelImpl dc;
+
+ private DatagramSocket so;
+
+ private volatile int timeout = 0;
+
+ public WispUdpSocketImpl(DatagramSocket so) {
+ this.so = so;
+ }
+
+ public WispUdpSocketImpl(DatagramChannel dc, DatagramSocket so) {
+ this.so = so;
+ this.dc = (DatagramChannelImpl) dc;
+ }
+
+ public void bind(SocketAddress local) throws SocketException {
+ try {
+ if (local == null)
+ local = new InetSocketAddress(0);
+ getChannelImpl().bind(local);
+ } catch (Exception x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public void connect(InetAddress address, int port) {
+ try {
+ connect(new InetSocketAddress(address, port));
+ } catch (SocketException x) {
+ }
+ }
+
+ public void connect(SocketAddress remote) throws SocketException {
+ if (remote == null)
+ throw new IllegalArgumentException("Address can't be null");
+
+ InetSocketAddress isa = Net.asInetSocketAddress(remote);
+ int port = isa.getPort();
+ if (port < 0 || port > 0xFFFF)
+ throw new IllegalArgumentException("connect: " + port);
+ if (remote == null)
+ throw new IllegalArgumentException("connect: null address");
+ if (isClosed())
+ return;
+ try {
+ getChannelImpl().connect(remote);
+ } catch (Exception x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public void disconnect() {
+ try {
+ getChannelImpl().disconnect();
+ } catch (IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ public boolean isBound() {
+ return dc != null && dc.localAddress() != null;
+ }
+
+ public boolean isConnected() {
+ return dc != null && dc.remoteAddress() != null;
+ }
+
+ public InetAddress getInetAddress() {
+ return (isConnected()
+ ? Net.asInetSocketAddress(dc.remoteAddress()).getAddress()
+ : null);
+ }
+
+ public int getPort() {
+ return (isConnected()
+ ? Net.asInetSocketAddress(dc.remoteAddress()).getPort()
+ : -1);
+ }
+
+ public void send(DatagramPacket p) throws IOException {
+ try {
+ wispSocketLockSupport.beginWrite();
+ send0(p);
+ } finally {
+ wispSocketLockSupport.endWrite();
+ }
+ }
+
+ private SocketAddress receive(ByteBuffer bb) throws IOException {
+ try {
+ wispSocketLockSupport.beginRead();
+ return receive0(bb);
+ } finally {
+ wispSocketLockSupport.endRead();
+ }
+ }
+
+
+ private void send0(DatagramPacket p) throws IOException {
+ final DatagramChannelImpl ch = getChannelImpl();
+ try {
+ ByteBuffer bb = ByteBuffer.wrap(p.getData(),
+ p.getOffset(),
+ p.getLength());
+
+ boolean useWrite = ch.isConnected() && p.getAddress() == null;
+ if (useWrite) {
+ InetSocketAddress isa = (InetSocketAddress)
+ ch.remoteAddress();
+ p.setPort(isa.getPort());
+ p.setAddress(isa.getAddress());
+ }
+
+ int writeLen = bb.remaining();
+ if ((useWrite ? ch.write(bb) : ch.send(bb, p.getSocketAddress())) == writeLen)
+ return;
+
+ /* Don't call so.getSoTimeout() here as it will try to acquire the lock of datagram socket
+ which might be already held by receiver, hence deadlock happens */
+ if (getSoTimeout() > 0)
+ WEA.addTimer(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(getSoTimeout()));
+
+ do {
+ WEA.registerEvent(ch, SelectionKey.OP_WRITE);
+ WEA.park(-1);
+
+ if (getSoTimeout() > 0 && WEA.isTimeout()) {
+ throw new SocketTimeoutException("time out");
+ }
+ if (useWrite) {
+ ch.write(bb);
+ } else {
+ ch.send(bb, p.getSocketAddress());
+ }
+ } while (bb.remaining() > 0);
+
+ } catch (IOException x) {
+ Net.translateException(x);
+ } finally {
+ if (getSoTimeout() > 0) {
+ WEA.cancelTimer();
+ }
+ WEA.unregisterEvent();
+ }
+ }
+
+
+ private SocketAddress receive0(ByteBuffer bb) throws IOException {
+ final DatagramChannelImpl ch = getChannelImpl();
+ SocketAddress sa;
+
+ try {
+ if ((sa = ch.receive(bb)) != null)
+ return sa;
+
+ if (getSoTimeout() > 0)
+ WEA.addTimer(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(getSoTimeout()));
+
+ do {
+ WEA.registerEvent(ch, SelectionKey.OP_READ);
+ WEA.park(-1);
+
+ if (getSoTimeout() > 0 && WEA.isTimeout()) {
+ throw new SocketTimeoutException("time out");
+ }
+ } while ((sa = ch.receive(bb)) == null);
+ } finally {
+ if (getSoTimeout() > 0) {
+ WEA.cancelTimer();
+ }
+ WEA.unregisterEvent();
+ }
+
+ return sa;
+ }
+
+ public int receive(DatagramPacket p, int bufLen) throws IOException {
+ int dataLen = 0;
+ try {
+ ByteBuffer bb = ByteBuffer.wrap(p.getData(),
+ p.getOffset(),
+ bufLen);
+ SocketAddress sender = receive(bb);
+ p.setSocketAddress(sender);
+ dataLen = bb.position() - p.getOffset();
+ } catch (IOException x) {
+ Net.translateException(x);
+ }
+ return dataLen;
+ }
+
+ public InetAddress getLocalAddress() {
+ if (isClosed())
+ return null;
+ DatagramChannelImpl ch = null;
+ try {
+ ch = getChannelImpl();
+ } catch (SocketException e) {
+ // return 0.0.0.0
+ }
+ SocketAddress local = ch == null ? null : ch.localAddress();
+ if (local == null)
+ local = new InetSocketAddress(0);
+ InetAddress result = ((InetSocketAddress) local).getAddress();
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ try {
+ sm.checkConnect(result.getHostAddress(), -1);
+ } catch (SecurityException x) {
+ return new InetSocketAddress(0).getAddress();
+ }
+ }
+ return result;
+ }
+
+ public int getLocalPort() {
+ if (isClosed())
+ return -1;
+ try {
+ SocketAddress local = getChannelImpl().getLocalAddress();
+ if (local != null) {
+ return ((InetSocketAddress) local).getPort();
+ }
+ } catch (Exception x) {
+ }
+ return 0;
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ this.timeout = timeout;
+ }
+
+ public int getSoTimeout() throws SocketException {
+ return timeout;
+ }
+
+ private void setBooleanOption(SocketOption name, boolean value)
+ throws SocketException {
+ try {
+ getChannelImpl().setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private void setIntOption(SocketOption name, int value)
+ throws SocketException {
+ try {
+ getChannelImpl().setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private boolean getBooleanOption(SocketOption name) throws SocketException {
+ try {
+ return getChannelImpl().getOption(name);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return false; // keep compiler happy
+ }
+ }
+
+ private int getIntOption(SocketOption name) throws SocketException {
+ try {
+ return getChannelImpl().getOption(name);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return -1; // keep compiler happy
+ }
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid send size");
+ setIntOption(StandardSocketOptions.SO_SNDBUF, size);
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_SNDBUF);
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid receive size");
+ setIntOption(StandardSocketOptions.SO_RCVBUF, size);
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_RCVBUF);
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
+
+ }
+
+ public void setBroadcast(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
+ }
+
+ public boolean getBroadcast() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ setIntOption(StandardSocketOptions.IP_TOS, tc);
+ }
+
+ public int getTrafficClass() throws SocketException {
+ return getIntOption(StandardSocketOptions.IP_TOS);
+ }
+
+ public void close() {
+ if (dc != null) {
+ try {
+ dc.close();
+ } catch (IOException x) {
+ throw new Error(x);
+ }
+ wispSocketLockSupport.unparkBlockedWispTask();
+ }
+ }
+
+ public boolean isClosed() {
+ return dc != null && !dc.isOpen();
+ }
+
+ public DatagramChannel getChannel() {
+ return dc;
+ }
+
+ private DatagramChannelImpl getChannelImpl() throws SocketException {
+ if (dc == null) {
+ try {
+ dc = (DatagramChannelImpl) DatagramChannel.open();
+ dc.configureBlocking(false);
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+ return dc;
+ }
+}
diff --git a/src/linux/native/com/alibaba/wisp/engine/WispEngine.c b/src/linux/native/com/alibaba/wisp/engine/WispEngine.c
new file mode 100644
index 0000000000000000000000000000000000000000..9363be4acdee56af03763e6631c3fd4f062e9269
--- /dev/null
+++ b/src/linux/native/com/alibaba/wisp/engine/WispEngine.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "jni.h"
+#include "jvm.h"
+#include "com_alibaba_wisp_engine_WispEngine.h"
+
+#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
+
+static JNINativeMethod methods[] = {
+ {"getProxyUnpark", "([I)I", (void *)&JVM_GetProxyUnpark},
+};
+
+JNIEXPORT void JNICALL
+Java_com_alibaba_wisp_engine_WispEngine_registerNatives(JNIEnv *env, jclass cls)
+{
+ (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
+}
diff --git a/src/linux/native/com/alibaba/wisp/engine/WispSysmon.c b/src/linux/native/com/alibaba/wisp/engine/WispSysmon.c
new file mode 100644
index 0000000000000000000000000000000000000000..22d38780f7bccc68f23c9c5595720592ee57589c
--- /dev/null
+++ b/src/linux/native/com/alibaba/wisp/engine/WispSysmon.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "jni.h"
+#include "jvm.h"
+#include "com_alibaba_wisp_engine_WispSysmon.h"
+
+#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
+
+static JNINativeMethod methods[] = {
+ {"markPreempted","(Ljava/lang/Thread;Z)V", (void *)&JVM_MarkPreempted},
+};
+
+JNIEXPORT void JNICALL
+Java_com_alibaba_wisp_engine_WispSysmon_registerNatives(JNIEnv *env, jclass cls)
+{
+ (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
+}
diff --git a/src/linux/native/com/alibaba/wisp/engine/WispTask.c b/src/linux/native/com/alibaba/wisp/engine/WispTask.c
new file mode 100644
index 0000000000000000000000000000000000000000..c7566b626ee759993d44a94449ba78ff3c618115
--- /dev/null
+++ b/src/linux/native/com/alibaba/wisp/engine/WispTask.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "jni.h"
+#include "jvm.h"
+#include "com_alibaba_wisp_engine_WispTask.h"
+
+#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
+
+#define THD "Ljava/lang/Thread;"
+
+static JNINativeMethod methods[] = {
+ {"checkAndClearNativeInterruptForWisp", "(" THD ")Z", (void *)&JVM_CheckAndClearNativeInterruptForWisp},
+};
+
+JNIEXPORT void JNICALL
+Java_com_alibaba_wisp_engine_WispTask_registerNatives(JNIEnv *env, jclass cls)
+{
+ (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
+}
diff --git a/src/share/classes/java/dyn/AsymRunnable.java b/src/macosx/classes/com/alibaba/wisp/engine/WispCounter.java
similarity index 61%
rename from src/share/classes/java/dyn/AsymRunnable.java
rename to src/macosx/classes/com/alibaba/wisp/engine/WispCounter.java
index e28f3528439937de1e133cebef66e249b80637ac..0975f673773484378f4e1eec88d918d2983a5c9e 100644
--- a/src/share/classes/java/dyn/AsymRunnable.java
+++ b/src/macosx/classes/com/alibaba/wisp/engine/WispCounter.java
@@ -1,30 +1,26 @@
/*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
+ * published by the Free Software Foundation. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
*/
-package java.dyn;
+package com.alibaba.wisp.engine;
+
+final public class WispCounter {
-public interface AsymRunnable {
- public OutT run(AsymCoroutine extends InT, ? super OutT> coroutine, InT value);
}
diff --git a/src/macosx/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java b/src/macosx/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6438cc340fa97601eec5dfe5b8bbb484889b4104
--- /dev/null
+++ b/src/macosx/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import com.alibaba.management.WispCounterMXBean;
+
+import javax.management.ObjectName;
+import java.util.List;
+
+public class WispCounterMXBeanImpl implements WispCounterMXBean {
+
+ @Override
+ public List getRunningStates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getSwitchCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getWaitTimeTotal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getRunningTimeTotal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getCompleteTaskCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getCreateTaskCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getParkCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getUnparkCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getLazyUnparkCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getUnparkInterruptSelectorCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getSelectableIOCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTimeOutCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getEventLoopCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getQueueLength() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getNumberOfRunningTasks() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalEnqueueTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getEnqueueCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalExecutionTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getExecutionCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalWaitSocketIOTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getWaitSocketIOCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalBlockingTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public WispCounter getWispCounter(long id) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName getObjectName() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/macosx/classes/com/alibaba/wisp/engine/WispEngine.java b/src/macosx/classes/com/alibaba/wisp/engine/WispEngine.java
new file mode 100644
index 0000000000000000000000000000000000000000..e822b03630f4c77913898e0a6e00c53faabf67ea
--- /dev/null
+++ b/src/macosx/classes/com/alibaba/wisp/engine/WispEngine.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.JavaLangAccess;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.io.IOException;
+import java.nio.channels.SelectableChannel;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class WispEngine {
+
+ public static boolean transparentWispSwitch() {
+ return false;
+ }
+
+ public static boolean enableThreadAsWisp() {
+ return false;
+ }
+
+ private static void setWispEngineAccess() {
+ SharedSecrets.setWispEngineAccess(new WispEngineAccess() {
+
+ @Override
+ public WispTask getCurrentTask() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void registerEvent(SelectableChannel ch, int events) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unregisterEvent() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int epollWait(int epfd, long pollArray, int arraySize, long timeout,
+ AtomicReference status, Object INTERRUPTED) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void interruptEpoll(AtomicReference status, Object INTERRUPTED, int interruptFd) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addTimer(long deadlineNano) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void cancelTimer() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sleep(long ms) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void yield() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isThreadTask(WispTask task) {
+ return false;
+ }
+
+ @Override
+ public boolean isTimeout() {
+ return false;
+ }
+
+ @Override
+ public void park(long timeoutNano) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unpark(WispTask task) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void destroy() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean hasMoreTasks() {
+ return false;
+ }
+
+ @Override
+ public boolean runningAsCoroutine(Thread t) {
+ return false;
+ }
+
+ @Override
+ public boolean usingWispEpoll() {
+ return false;
+ }
+
+ public boolean isAlive(WispTask task) {
+ return false;
+ }
+
+ @Override
+ public void interrupt(WispTask task) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean testInterruptedAndClear(WispTask task, boolean clear) {
+ return false;
+ }
+
+ @Override
+ public boolean tryStartThreadAsWisp(Thread thread, Runnable target) {
+ return false;
+ }
+
+ @Override
+ public boolean isAllThreadAsWisp() {
+ return false;
+ }
+
+ @Override
+ public boolean useDirectSelectorWakeup() {
+ return false;
+ }
+
+ @Override
+ public boolean enableSocketLock() {
+ return false;
+ }
+
+ @Override
+ public StackTraceElement[] getStackTrace(WispTask task) {
+ throw new UnsupportedOperationException();
+ }
+ });
+ }
+
+}
diff --git a/src/macosx/classes/com/alibaba/wisp/engine/WispTask.java b/src/macosx/classes/com/alibaba/wisp/engine/WispTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..40ef3fc58213f8897097718b48eebe978e613cc1
--- /dev/null
+++ b/src/macosx/classes/com/alibaba/wisp/engine/WispTask.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+
+public class WispTask {
+
+ public Thread getThreadWrapper() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/macosx/classes/com/alibaba/wisp/engine/WispThreadWrapper.java b/src/macosx/classes/com/alibaba/wisp/engine/WispThreadWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..67999b115507afb9e8a02f1ebc7bbee356fc8677
--- /dev/null
+++ b/src/macosx/classes/com/alibaba/wisp/engine/WispThreadWrapper.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+
+import sun.reflect.CallerSensitive;
+
+import java.dyn.CoroutineSupport;
+
+class WispThreadWrapper extends Thread {
+
+ @Override
+ public CoroutineSupport getCoroutineSupport() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void start() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ @Deprecated
+ public void destroy() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ @Deprecated
+ public int countStackFrames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ @CallerSensitive
+ public ClassLoader getContextClassLoader() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setContextClassLoader(ClassLoader cl) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public StackTraceElement[] getStackTrace() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public State getState() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/macosx/classes/sun/nio/ch/IOEvent.java b/src/macosx/classes/sun/nio/ch/IOEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..51db2db85782dbb1f5e11edff72073c70edb7de8
--- /dev/null
+++ b/src/macosx/classes/sun/nio/ch/IOEvent.java
@@ -0,0 +1,8 @@
+package sun.nio.ch;
+
+public class IOEvent {
+
+ public static Class> eventClass() {
+ return IOEventRegister.class;
+ }
+}
\ No newline at end of file
diff --git a/src/macosx/classes/sun/nio/ch/IOEventRegister.java b/src/macosx/classes/sun/nio/ch/IOEventRegister.java
new file mode 100644
index 0000000000000000000000000000000000000000..06f724db98d04d20d991d0d51ad6fe9afebf6b83
--- /dev/null
+++ b/src/macosx/classes/sun/nio/ch/IOEventRegister.java
@@ -0,0 +1,99 @@
+package sun.nio.ch;
+
+import sun.misc.SharedSecrets;
+
+import java.io.IOException;
+
+public class IOEventRegister {
+
+ static {
+ SharedSecrets.setIOEventAccess(new IOEventAccess() {
+
+ @Override
+ public int eventCtlAdd() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCtlDel() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCtlMod() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventOneShot() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int noEvent() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long allocatePollArray(int count) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void freePollArray(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getEvent(long address, int i) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getDescriptor(long eventAddress) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getEvents(long eventAddress) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCreate() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCtl(int epfd, int opcode, int fd, int events) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventWait(int epfd, long pollAddress, int numfds, int timeout) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void socketpair(int[] sv) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void interrupt(int fd) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drain(int fd) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close(int fd) {
+ throw new UnsupportedOperationException();
+ }
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/src/macosx/classes/sun/nio/ch/WispServerSocketImpl.java b/src/macosx/classes/sun/nio/ch/WispServerSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6fdd26984c6197a8bcc47b30f0ba5423e88b47a
--- /dev/null
+++ b/src/macosx/classes/sun/nio/ch/WispServerSocketImpl.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.ServerSocketChannel;
+
+
+public class WispServerSocketImpl
+{
+
+ public WispServerSocketImpl() {
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void bind(SocketAddress local, int backlog) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getInetAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getLocalPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Socket accept() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void close() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ServerSocketChannel getChannel() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isBound() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isClosed() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoTimeout() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/macosx/classes/sun/nio/ch/WispSocketImpl.java b/src/macosx/classes/sun/nio/ch/WispSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..318ad6436fe376a472c9c2dc4283a41e60c72f56
--- /dev/null
+++ b/src/macosx/classes/sun/nio/ch/WispSocketImpl.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+
+
+public class WispSocketImpl
+{
+
+ public WispSocketImpl(Socket so) {
+ throw new UnsupportedOperationException();
+ }
+
+ public WispSocketImpl(SocketChannel sc, Socket so) {
+ throw new UnsupportedOperationException();
+ }
+
+ public SocketChannel getChannel() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(SocketAddress remote) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(SocketAddress remote, int timeout) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getInetAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getLocalAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getLocalPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getTcpNoDelay() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoLinger(boolean on, int linger) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoLinger() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void sendUrgentData(int data) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setOOBInline(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getOOBInline() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoTimeout() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setKeepAlive(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getKeepAlive() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getTrafficClass() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void close() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void shutdownInput() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void shutdownOutput() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isConnected() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isBound() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isClosed() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isInputShutdown() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isOutputShutdown() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/macosx/classes/sun/nio/ch/WispSocketLockSupport.java b/src/macosx/classes/sun/nio/ch/WispSocketLockSupport.java
new file mode 100644
index 0000000000000000000000000000000000000000..62373f0c88135b99343803d7189288fc920bb27e
--- /dev/null
+++ b/src/macosx/classes/sun/nio/ch/WispSocketLockSupport.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+class WispSocketLockSupport {
+
+}
diff --git a/src/macosx/classes/sun/nio/ch/WispUdpSocketImpl.java b/src/macosx/classes/sun/nio/ch/WispUdpSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3d5f79fd9d5b1ba4f7b460eab9729fb2c2b0f5e
--- /dev/null
+++ b/src/macosx/classes/sun/nio/ch/WispUdpSocketImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.DatagramChannel;
+
+
+// Make a udp socket channel look like a datagram socket.
+
+public class WispUdpSocketImpl {
+
+ public WispUdpSocketImpl(DatagramSocket so) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void bind(SocketAddress local) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(InetAddress address, int port) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(SocketAddress remote) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void disconnect() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isBound() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isConnected() {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getInetAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void send(DatagramPacket p) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ private SocketAddress receive(ByteBuffer bb) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int receive(DatagramPacket p, int bufLen) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getLocalAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getLocalPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoTimeout() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setBroadcast(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getBroadcast() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getTrafficClass() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void close() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isClosed() {
+ throw new UnsupportedOperationException();
+ }
+
+ public DatagramChannel getChannel() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/share/classes/com/alibaba/management/WispCounterMXBean.java b/src/share/classes/com/alibaba/management/WispCounterMXBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..2771100241bb82de9b75f13f2e5857d00a1f099e
--- /dev/null
+++ b/src/share/classes/com/alibaba/management/WispCounterMXBean.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.management;
+
+import com.alibaba.wisp.engine.WispCounter;
+
+import java.lang.management.PlatformManagedObject;
+import java.util.List;
+
+public interface WispCounterMXBean extends PlatformManagedObject {
+
+ /**
+ * @return list of managed wisp worker running state
+ */
+ List getRunningStates();
+
+ /**
+ * @return list of managed wisp worker switch count
+ */
+ List getSwitchCount();
+
+ /**
+ * @return list of managed wisp worker wait time total, unit ns
+ */
+ List getWaitTimeTotal();
+
+ /**
+ * @return list of managed wisp worker running time total, unit ns
+ */
+ List getRunningTimeTotal();
+
+ /**
+ * @return list of managed wisp worker complete task count
+ */
+ List getCompleteTaskCount();
+
+ /**
+ * @return list of managed wisp worker create task count
+ */
+ List getCreateTaskCount();
+
+ /**
+ * @return list of managed wisp worker park count
+ */
+ List getParkCount();
+
+ /**
+ * @return list of managed wisp worker unpark count
+ */
+ List getUnparkCount();
+
+ /**
+ * @return list of managed wisp worker lazy unpark count
+ * @deprecated the lazy unpark mechanism has been removed since ajdk 8.6.11
+ */
+ @Deprecated
+ List getLazyUnparkCount();
+
+ /**
+ * @return list of managed wisp worker unpark interrupt selector count
+ */
+ List getUnparkInterruptSelectorCount();
+
+ /**
+ * @return list of managed wisp worker do IO count
+ */
+ List getSelectableIOCount();
+
+ /**
+ * @return list of managed wisp worker timeout count
+ */
+ List getTimeOutCount();
+
+ /**
+ * @return list of managed wisp worker do event loop count
+ */
+ List getEventLoopCount();
+
+ /**
+ * @return list of managed wisp worker task queue length
+ */
+ List getQueueLength();
+
+ /**
+ * @return list of number of running tasks from managed wisp workers
+ */
+ List getNumberOfRunningTasks();
+
+ /**
+ * @return list of total blocking time in nanos from managed wisp workers
+ */
+ List getTotalBlockingTime();
+
+ /**
+ * @return list of total execution time in nanos from managed wisp workers
+ */
+ List getTotalExecutionTime();
+
+ /**
+ * @return list of execution count from managed wisp workers
+ */
+ List getExecutionCount();
+
+ /**
+ * @return list of total enqueue time in nanos from managed wisp workers
+ */
+ List getTotalEnqueueTime();
+
+ /**
+ * @return list of enqueue count from managed wisp workers
+ */
+ List getEnqueueCount();
+
+ /**
+ * @return list of total wait socket io time in nanos from managed wisp workers
+ */
+ List getTotalWaitSocketIOTime();
+
+ /**
+ * @return list of wait socket io event count from managed wisp workers
+ */
+ List getWaitSocketIOCount();
+
+ /**
+ * @param id WispEngine id
+ * @return WispCounter data
+ */
+ WispCounter getWispCounter(long id);
+}
diff --git a/src/share/classes/com/sun/demo/jvmti/hprof/Tracker.java b/src/share/classes/com/sun/demo/jvmti/hprof/Tracker.java
index dc3d61b5eb962a43ca0864696d7fbfeb10a8e386..00deff667304f2b42203d24fa87bb2fc309ef305 100644
--- a/src/share/classes/com/sun/demo/jvmti/hprof/Tracker.java
+++ b/src/share/classes/com/sun/demo/jvmti/hprof/Tracker.java
@@ -37,6 +37,9 @@ package com.sun.demo.jvmti.hprof;
* for more details.
*/
+import sun.misc.JavaLangAccess;
+import sun.misc.SharedSecrets;
+
public class Tracker {
/* Master switch that activates calls to native functions. */
@@ -57,7 +60,7 @@ public class Tracker {
if (obj == null) {
throw new IllegalArgumentException("Null object.");
}
- nativeObjectInit(Thread.currentThread(), obj);
+ nativeObjectInit(SharedSecrets.getJavaLangAccess().currentThread0(), obj);
}
}
@@ -73,7 +76,7 @@ public class Tracker {
if (obj == null) {
throw new IllegalArgumentException("Null object.");
}
- nativeNewArray(Thread.currentThread(), obj);
+ nativeNewArray(SharedSecrets.getJavaLangAccess().currentThread0(), obj);
}
}
@@ -96,7 +99,11 @@ public class Tracker {
throw new IllegalArgumentException("Negative method index");
}
- nativeCallSite(Thread.currentThread(), cnum, mnum);
+ /*
+ * calling Thread.currentThread() will bring us here again, which will cause
+ * StackOverflow error. Instead, we use Thread.currentThread0().
+ */
+ nativeCallSite(SharedSecrets.getJavaLangAccess().currentThread0(), cnum, mnum);
}
}
@@ -117,7 +124,7 @@ public class Tracker {
throw new IllegalArgumentException("Negative method index");
}
- nativeReturnSite(Thread.currentThread(), cnum, mnum);
+ nativeReturnSite(SharedSecrets.getJavaLangAccess().currentThread0(), cnum, mnum);
}
}
diff --git a/src/share/classes/java/dyn/AsymCoroutine.java b/src/share/classes/java/dyn/AsymCoroutine.java
deleted file mode 100644
index 3a34d026e764ea01da0c03ceea3c4e9a75c23ac9..0000000000000000000000000000000000000000
--- a/src/share/classes/java/dyn/AsymCoroutine.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.dyn;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * Implementation of asymmetric coroutines. A AsymCoroutine can be called by any coroutine (Coroutine and AsymCoroutine) and will return to
- * its caller upon {@link #ret()}.
- *
- * Similar to {@link Thread} there are two ways to implement a AsymCoroutine: either by implementing a subclass of AsymCoroutine (and
- * overriding {@link #run()}) or by providing a {@link Runnable} to the AsymCoroutine constructor.
- *
- * An implementation of a simple AsymCoroutine that always returns the average of all its previous inputs might look like this:
- *
- *
- *
- *
- *
- * class Average extends AsymCoroutine<Integer, Integer> {
- * public Integer run(Integer value) {
- * int sum = value;
- * int count = 1;
- * while (true) {
- * sum += ret(sum / count++);
- * }
- * }
- * }
- *
- *
- *
- *
- *
- * This AsymCoroutine can be invoked either by reading and writing the {@link #output} and {@link #input} fields and invoking the
- * {@link #call()} method:
- *
- *
- *
- *
- * Average avg = new Average();
- * avg.input = 10;
- * avg.call();
- * System.out.println(avg.output);
- *
- *
- *
- *
- * Another way to invoke this AsymCoroutine is by using the shortcut {@link #call(Object)} methods:
- *
- *
- *
- *
- * Average avg = new Average();
- * System.out.println(avg.call(10));
- *
- *
- *
- *
- *
- * @author Lukas Stadler
- *
- * @param
- * input type of this AsymCoroutine, Void if no input value is expected
- * @param
- * output type of this AsymCoroutine, Void if no output is produced
- */
-public class AsymCoroutine extends CoroutineBase implements Iterable {
- CoroutineBase caller;
-
- private final AsymRunnable super InT, ? extends OutT> target;
-
- private InT input;
- private OutT output;
-
- public AsymCoroutine() {
- target = null;
- threadSupport.addCoroutine(this, -1);
- }
-
- public AsymCoroutine(long stacksize) {
- target = null;
- threadSupport.addCoroutine(this, stacksize);
- }
-
- public AsymCoroutine(AsymRunnable super InT, ? extends OutT> target) {
- this.target = target;
- threadSupport.addCoroutine(this, -1);
- }
-
- public AsymCoroutine(AsymRunnable super InT, ? extends OutT> target, long stacksize) {
- this.target = target;
- threadSupport.addCoroutine(this, stacksize);
- }
-
- public final OutT call(final InT input) {
- this.input = input;
- Thread.currentThread().getCoroutineSupport().asymmetricCall(this);
- return output;
- }
-
- public final OutT call() {
- Thread.currentThread().getCoroutineSupport().asymmetricCall(this);
- return output;
- }
-
- public final InT ret(final OutT value) {
- output = value;
- Thread.currentThread().getCoroutineSupport().asymmetricReturn(this);
- return input;
- }
-
- public final InT ret() {
- Thread.currentThread().getCoroutineSupport().asymmetricReturn(this);
- return input;
- }
-
- protected OutT run(InT value) {
- return target.run(this, value);
- }
-
- private static class Iter implements Iterator {
- private final AsymCoroutine, OutT> fiber;
-
- public Iter(final AsymCoroutine, OutT> fiber) {
- this.fiber = fiber;
- }
-
- @Override
- public boolean hasNext() {
- return !fiber.isFinished();
- }
-
- @Override
- public OutT next() {
- if (fiber.isFinished())
- throw new NoSuchElementException();
- return fiber.call();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- }
-
- @Override
- public final Iterator iterator() {
- return new Iter(this);
- }
-
- protected final void run() {
- output = run(input);
- }
-}
diff --git a/src/share/classes/java/dyn/Coroutine.java b/src/share/classes/java/dyn/Coroutine.java
index 479d4335f6974618cc6fcdb292760ee98251816d..9cd81757eb115e5fea4820d6f4448a099f45713b 100644
--- a/src/share/classes/java/dyn/Coroutine.java
+++ b/src/share/classes/java/dyn/Coroutine.java
@@ -25,6 +25,8 @@
package java.dyn;
+import sun.misc.SharedSecrets;
+
/**
* Implementation of symmetric coroutines. A Coroutine will take part in thread-wide scheduling of coroutines. It transfers control to
* the next coroutine whenever yield is called.
@@ -66,56 +68,92 @@ package java.dyn;
* @author Lukas Stadler
*/
public class Coroutine extends CoroutineBase {
- private final Runnable target;
-
- Coroutine next;
- Coroutine last;
-
- public Coroutine() {
- this.target = null;
- threadSupport.addCoroutine(this, -1);
- }
-
- public Coroutine(Runnable target) {
- this.target = target;
- threadSupport.addCoroutine(this, -1);
- }
-
- public Coroutine(long stacksize) {
- this.target = null;
- threadSupport.addCoroutine(this, stacksize);
- }
-
- public Coroutine(Runnable target, long stacksize) {
- this.target = target;
- threadSupport.addCoroutine(this, stacksize);
- }
-
- // creates the initial coroutine for a new thread
- Coroutine(CoroutineSupport threadSupport, long data) {
- super(threadSupport, data);
- this.target = null;
- }
-
- /**
- * Yields execution to the next coroutine in the current threads coroutine queue.
- */
- public static void yield() {
- Thread.currentThread().getCoroutineSupport().symmetricYield();
- }
-
- public static void yieldTo(Coroutine target) {
- Thread.currentThread().getCoroutineSupport().symmetricYieldTo(target);
- }
-
- public void stop() {
- Thread.currentThread().getCoroutineSupport().symmetricStopCoroutine(this);
- }
-
- protected void run() {
- assert Thread.currentThread() == threadSupport.getThread();
- if (target != null) {
- target.run();
- }
- }
+ public enum StealResult {
+ SUCCESS,
+ FAIL_BY_CONTENTION,
+ FAIL_BY_STATUS,
+ FAIL_BY_NATIVE_FRAME
+ }
+
+ private final Runnable target;
+
+ public Coroutine() {
+ this.target = null;
+ threadSupport.addCoroutine(this, -1);
+ }
+
+ public Coroutine(Runnable target) {
+ this.target = target;
+ threadSupport.addCoroutine(this, -1);
+ }
+
+ public Coroutine(long stacksize) {
+ this.target = null;
+ threadSupport.addCoroutine(this, stacksize);
+ }
+
+ public Coroutine(Runnable target, long stacksize) {
+ this.target = target;
+ threadSupport.addCoroutine(this, stacksize);
+ }
+
+ // creates the initial coroutine for a new thread
+ Coroutine(CoroutineSupport threadSupport, long nativeCoroutine) {
+ super(threadSupport, nativeCoroutine);
+ this.target = null;
+ }
+
+
+ public static void yieldTo(Coroutine target) {
+ SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().symmetricYieldTo(target);
+ }
+
+ /**
+ * optimized version of yieldTo function for wisp based on the following assumptions:
+ * 1. we won't simultaneously steal a {@link Coroutine} from other threads
+ * 2. we won't switch to a {@link Coroutine} that's being stolen
+ * 3. we won't steal a running {@link Coroutine}
+ * @param target target coroutine
+ */
+ public static void unsafeYieldTo(Coroutine target) {
+ SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().unsafeSymmetricYieldTo(target);
+ }
+
+ /**
+ * Steal a coroutine from it's carrier thread to current thread.
+ *
+ * @param failOnContention steal fail if there's too much lock contention
+ *
+ * @return result described by Coroutine.STEAL_*. Also return SUCCESS directly if coroutine's carrier thread is current.
+ */
+ public StealResult steal(boolean failOnContention) {
+ return threadSupport.steal(this, failOnContention);
+ }
+
+ public void stop() {
+ SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().symmetricStopCoroutine(this);
+ }
+
+ public void setWispTask(int id, Object task, Object engine) {
+ setWispTask(nativeCoroutine, id, task, engine);
+ }
+
+ protected void run() {
+ assert Thread.currentThread() == threadSupport.getThread();
+ if (target != null) {
+ target.run();
+ }
+ }
+
+ static {
+ registerNatives();
+ }
+
+ private static native void registerNatives();
+
+ private static native void setWispTask(long coroutine, int id, Object task, Object engine);
+
+ public StackTraceElement[] getCoroutineStack() {
+ return CoroutineSupport.getCoroutineStack(this.nativeCoroutine);
+ }
}
\ No newline at end of file
diff --git a/src/share/classes/java/dyn/CoroutineBase.java b/src/share/classes/java/dyn/CoroutineBase.java
index aab2d59141d7d75c8b4da4f4975bd4e4d7ca2913..a8172c8e5555357ae91fd70fd46212d6f68c207b 100644
--- a/src/share/classes/java/dyn/CoroutineBase.java
+++ b/src/share/classes/java/dyn/CoroutineBase.java
@@ -25,70 +25,69 @@
package java.dyn;
+import sun.misc.SharedSecrets;
+
public abstract class CoroutineBase {
- transient long data;
+ transient long nativeCoroutine;
+
+ boolean finished = false;
- transient CoroutineLocal.CoroutineLocalMap coroutineLocals = null;
+ boolean needsUnlock = false;
- boolean finished = false;
+ transient CoroutineSupport threadSupport;
- transient CoroutineSupport threadSupport;
+ CoroutineBase() {
+ Thread thread = SharedSecrets.getJavaLangAccess().currentThread0();
+ assert thread.getCoroutineSupport() != null;
+ this.threadSupport = thread.getCoroutineSupport();
+ }
- CoroutineBase() {
- Thread thread = Thread.currentThread();
- assert thread.getCoroutineSupport() != null;
- this.threadSupport = thread.getCoroutineSupport();
- }
+ // creates the initial coroutine for a new thread
+ CoroutineBase(CoroutineSupport threadSupport, long nativeCoroutine) {
+ this.threadSupport = threadSupport;
+ this.nativeCoroutine = nativeCoroutine;
+ }
- // creates the initial coroutine for a new thread
- CoroutineBase(CoroutineSupport threadSupport, long data) {
- this.threadSupport = threadSupport;
- this.data = data;
- }
+ protected abstract void run();
- protected abstract void run();
+ @SuppressWarnings({"unused"})
+ private final void startInternal() {
+ assert threadSupport.getThread() == SharedSecrets.getJavaLangAccess().currentThread0();
+ try {
+ // When we symmetricYieldTo a newly created coroutine,
+ // we'll expect the new coroutine release lock as soon as possible
+ threadSupport.beforeResume(this);
+ run();
+ } catch (Throwable t) {
+ if (!(t instanceof CoroutineExitException)) {
+ t.printStackTrace();
+ }
+ } finally {
+ finished = true;
+ // threadSupport is fixed by steal()
+ threadSupport.beforeResume(this);
- @SuppressWarnings({ "unused" })
- private final void startInternal() {
- assert threadSupport.getThread() == Thread.currentThread();
- try {
- if (CoroutineSupport.DEBUG) {
- System.out.println("starting coroutine " + this);
- }
- run();
- } catch (Throwable t) {
- if (!(t instanceof CoroutineExitException)) {
- t.printStackTrace();
- }
- } finally {
- finished = true;
- // use Thread.currentThread().getCoroutineSupport() because we might have been migrated to another thread!
- if (this instanceof Coroutine) {
- Thread.currentThread().getCoroutineSupport().terminateCoroutine();
- } else {
- Thread.currentThread().getCoroutineSupport().terminateCallable();
- }
- }
- assert threadSupport.getThread() == Thread.currentThread();
- }
+ threadSupport.terminateCoroutine();
+ }
+ assert threadSupport.getThread() == SharedSecrets.getJavaLangAccess().currentThread0();
+ }
- /**
- * Returns true if this coroutine has reached its end. Under normal circumstances this happens when the {@link #run()} method returns.
- */
- public final boolean isFinished() {
- return finished;
- }
+ /**
+ * Returns true if this coroutine has reached its end. Under normal circumstances this happens when the {@link #run()} method returns.
+ */
+ public final boolean isFinished() {
+ return finished;
+ }
- /**
- * @return the thread that this coroutine is associated with
- * @throws NullPointerException
- * if the coroutine has terminated
- */
- public Thread getThread() {
- return threadSupport.getThread();
- }
+ /**
+ * @return the thread that this coroutine is associated with
+ * @throws NullPointerException if the coroutine has been terminated
+ */
+ public Thread getThread() {
+ return threadSupport.getThread();
+ }
- public static CoroutineBase current() {
- return Thread.currentThread().getCoroutineSupport().getCurrent();
- }
+ public static CoroutineBase current() {
+ return SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().getCurrent();
+ }
}
diff --git a/src/share/classes/java/dyn/CoroutineLocal.java b/src/share/classes/java/dyn/CoroutineLocal.java
deleted file mode 100644
index 60468923762c4eba4b467f42825ec540f8f8a635..0000000000000000000000000000000000000000
--- a/src/share/classes/java/dyn/CoroutineLocal.java
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.dyn;
-
-import java.lang.Object;
-import java.lang.Thread;
-import java.lang.UnsupportedOperationException;
-import java.lang.ref.*;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@SuppressWarnings({ "rawtypes", "unchecked" })
-public class CoroutineLocal {
- private final int coroutineLocalHashCode = nextHashCode();
- private static AtomicInteger nextHashCode = new AtomicInteger();
- private static final int HASH_INCREMENT = 0x61c88647;
-
- private static int nextHashCode() {
- return nextHashCode.getAndAdd(HASH_INCREMENT);
- }
-
- protected T initialValue() {
- return null;
- }
-
- public CoroutineLocal() {
- }
-
- public T get() {
- assert Thread.currentThread().getCoroutineSupport() != null;
- CoroutineBase t = Thread.currentThread().getCoroutineSupport().getCurrent();
- CoroutineLocalMap map = getMap(t);
- if (map != null) {
- CoroutineLocalMap.Entry e = map.getEntry(this);
- if (e != null)
- return (T) e.value;
- }
- return setInitialValue();
- }
-
- /**
- * Variant of set() to establish initialValue. Used instead of set() in case user has overridden the set() method.
- *
- * @return the initial value
- */
- private T setInitialValue() {
- T value = initialValue();
- assert Thread.currentThread().getCoroutineSupport() != null;
- CoroutineBase t = Thread.currentThread().getCoroutineSupport().getCurrent();
- CoroutineLocalMap map = getMap(t);
- if (map != null)
- map.set(this, value);
- else
- createMap(t, value);
- return value;
- }
-
- /**
- * Sets the current thread's copy of this thread-local variable to the specified value. Most subclasses will have no need to override
- * this method, relying solely on the {@link #initialValue} method to set the values of thread-locals.
- *
- * @param value the value to be stored in the current thread's copy of this thread-local.
- */
- public void set(T value) {
- assert Thread.currentThread().getCoroutineSupport() != null;
- CoroutineBase t = Thread.currentThread().getCoroutineSupport().getCurrent();
- CoroutineLocalMap map = getMap(t);
- if (map != null)
- map.set(this, value);
- else
- createMap(t, value);
- }
-
- /**
- * Removes the current thread's value for this thread-local variable. If this thread-local variable is subsequently {@linkplain #get
- * read} by the current thread, its value will be reinitialized by invoking its {@link #initialValue} method, unless its value is
- * {@linkplain #set set} by the current thread in the interim. This may result in multiple invocations of the initialValue
- * method in the current thread.
- *
- * @since 1.5
- */
- public void remove() {
- assert Thread.currentThread().getCoroutineSupport() != null;
- CoroutineLocalMap m = getMap(Thread.currentThread().getCoroutineSupport().getCurrent());
- if (m != null)
- m.remove(this);
- }
-
- CoroutineLocalMap getMap(CoroutineBase t) {
- return t.coroutineLocals;
- }
-
- /**
- * Create the map associated with a ThreadLocal. Overridden in InheritableThreadLocal.
- *
- * @param t the current thread
- * @param firstValue value for the initial entry of the map
- * @param map the map to store.
- */
- void createMap(CoroutineBase t, T firstValue) {
- t.coroutineLocals = new CoroutineLocalMap(this, firstValue);
- }
-
- /**
- * Factory method to create map of inherited thread locals. Designed to be called only from Thread constructor.
- *
- * @param parentMap the map associated with parent thread
- * @return a map containing the parent's inheritable bindings
- */
- static CoroutineLocalMap createInheritedMap(CoroutineLocalMap parentMap) {
- return new CoroutineLocalMap(parentMap);
- }
-
- /**
- * Method childValue is visibly defined in subclass InheritableThreadLocal, but is internally defined here for the sake of providing
- * createInheritedMap factory method without needing to subclass the map class in InheritableThreadLocal. This technique is preferable
- * to the alternative of embedding instanceof tests in methods.
- */
- T childValue(T parentValue) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * ThreadLocalMap is a customized hash map suitable only for maintaining thread local values. No operations are exported outside of the
- * ThreadLocal class. The class is package private to allow declaration of fields in class Thread. To help deal with very large and
- * long-lived usages, the hash table entries use WeakReferences for keys. However, since reference queues are not used, stale entries
- * are guaranteed to be removed only when the table starts running out of space.
- */
- static class CoroutineLocalMap {
-
- /**
- * The entries in this hash map extend WeakReference, using its main ref field as the key (which is always a ThreadLocal object).
- * Note that null keys (i.e. entry.get() == null) mean that the key is no longer referenced, so the entry can be expunged from
- * table. Such entries are referred to as "stale entries" in the code that follows.
- */
- static class Entry extends WeakReference {
- /** The value associated with this ThreadLocal. */
- Object value;
-
- Entry(CoroutineLocal k, Object v) {
- super(k);
- value = v;
- }
- }
-
- /**
- * The initial capacity -- MUST be a power of two.
- */
- private static final int INITIAL_CAPACITY = 16;
-
- /**
- * The table, resized as necessary. table.length MUST always be a power of two.
- */
- private Entry[] table;
-
- /**
- * The number of entries in the table.
- */
- private int size = 0;
-
- /**
- * The next size value at which to resize.
- */
- private int threshold; // Default to 0
-
- /**
- * Set the resize threshold to maintain at worst a 2/3 load factor.
- */
- private void setThreshold(int len) {
- threshold = len * 2 / 3;
- }
-
- /**
- * Increment i modulo len.
- */
- private static int nextIndex(int i, int len) {
- return ((i + 1 < len) ? i + 1 : 0);
- }
-
- /**
- * Decrement i modulo len.
- */
- private static int prevIndex(int i, int len) {
- return ((i - 1 >= 0) ? i - 1 : len - 1);
- }
-
- /**
- * Construct a new map initially containing (firstKey, firstValue). ThreadLocalMaps are constructed lazily, so we only create one
- * when we have at least one entry to put in it.
- */
- CoroutineLocalMap(CoroutineLocal firstKey, Object firstValue) {
- table = new Entry[INITIAL_CAPACITY];
- int i = firstKey.coroutineLocalHashCode & (INITIAL_CAPACITY - 1);
- table[i] = new Entry(firstKey, firstValue);
- size = 1;
- setThreshold(INITIAL_CAPACITY);
- }
-
- /**
- * Construct a new map including all Inheritable ThreadLocals from given parent map. Called only by createInheritedMap.
- *
- * @param parentMap the map associated with parent thread.
- */
- private CoroutineLocalMap(CoroutineLocalMap parentMap) {
- Entry[] parentTable = parentMap.table;
- int len = parentTable.length;
- setThreshold(len);
- table = new Entry[len];
-
- for (int j = 0; j < len; j++) {
- Entry e = parentTable[j];
- if (e != null) {
- CoroutineLocal key = e.get();
- if (key != null) {
- Object value = key.childValue(e.value);
- Entry c = new Entry(key, value);
- int h = key.coroutineLocalHashCode & (len - 1);
- while (table[h] != null)
- h = nextIndex(h, len);
- table[h] = c;
- size++;
- }
- }
- }
- }
-
- /**
- * Get the entry associated with key. This method itself handles only the fast path: a direct hit of existing key. It otherwise
- * relays to getEntryAfterMiss. This is designed to maximize performance for direct hits, in part by making this method readily
- * inlinable.
- *
- * @param key the thread local object
- * @return the entry associated with key, or null if no such
- */
- private Entry getEntry(CoroutineLocal key) {
- int i = key.coroutineLocalHashCode & (table.length - 1);
- Entry e = table[i];
- if (e != null && e.get() == key)
- return e;
- else
- return getEntryAfterMiss(key, i, e);
- }
-
- /**
- * Version of getEntry method for use when key is not found in its direct hash slot.
- *
- * @param key the thread local object
- * @param i the table index for key's hash code
- * @param e the entry at table[i]
- * @return the entry associated with key, or null if no such
- */
- private Entry getEntryAfterMiss(CoroutineLocal key, int i, Entry e) {
- Entry[] tab = table;
- int len = tab.length;
-
- while (e != null) {
- CoroutineLocal k = e.get();
- if (k == key)
- return e;
- if (k == null)
- expungeStaleEntry(i);
- else
- i = nextIndex(i, len);
- e = tab[i];
- }
- return null;
- }
-
- /**
- * Set the value associated with key.
- *
- * @param key the thread local object
- * @param value the value to be set
- */
- private void set(CoroutineLocal key, Object value) {
-
- // We don't use a fast path as with get() because it is at
- // least as common to use set() to create new entries as
- // it is to replace existing ones, in which case, a fast
- // path would fail more often than not.
-
- Entry[] tab = table;
- int len = tab.length;
- int i = key.coroutineLocalHashCode & (len - 1);
-
- for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
- CoroutineLocal k = e.get();
-
- if (k == key) {
- e.value = value;
- return;
- }
-
- if (k == null) {
- replaceStaleEntry(key, value, i);
- return;
- }
- }
-
- tab[i] = new Entry(key, value);
- int sz = ++size;
- if (!cleanSomeSlots(i, sz) && sz >= threshold)
- rehash();
- }
-
- /**
- * Remove the entry for key.
- */
- private void remove(CoroutineLocal key) {
- Entry[] tab = table;
- int len = tab.length;
- int i = key.coroutineLocalHashCode & (len - 1);
- for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
- if (e.get() == key) {
- e.clear();
- expungeStaleEntry(i);
- return;
- }
- }
- }
-
- /**
- * Replace a stale entry encountered during a set operation with an entry for the specified key. The value passed in the value
- * parameter is stored in the entry, whether or not an entry already exists for the specified key.
- *
- * As a side effect, this method expunges all stale entries in the "run" containing the stale entry. (A run is a sequence of entries
- * between two null slots.)
- *
- * @param key the key
- * @param value the value to be associated with key
- * @param staleSlot index of the first stale entry encountered while searching for key.
- */
- private void replaceStaleEntry(CoroutineLocal key, Object value, int staleSlot) {
- Entry[] tab = table;
- int len = tab.length;
- Entry e;
-
- // Back up to check for prior stale entry in current run.
- // We clean out whole runs at a time to avoid continual
- // incremental rehashing due to garbage collector freeing
- // up refs in bunches (i.e., whenever the collector runs).
- int slotToExpunge = staleSlot;
- for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len))
- if (e.get() == null)
- slotToExpunge = i;
-
- // Find either the key or trailing null slot of run, whichever
- // occurs first
- for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
- CoroutineLocal k = e.get();
-
- // If we find key, then we need to swap it
- // with the stale entry to maintain hash table order.
- // The newly stale slot, or any other stale slot
- // encountered above it, can then be sent to expungeStaleEntry
- // to remove or rehash all of the other entries in run.
- if (k == key) {
- e.value = value;
-
- tab[i] = tab[staleSlot];
- tab[staleSlot] = e;
-
- // Start expunge at preceding stale entry if it exists
- if (slotToExpunge == staleSlot)
- slotToExpunge = i;
- cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
- return;
- }
-
- // If we didn't find stale entry on backward scan, the
- // first stale entry seen while scanning for key is the
- // first still present in the run.
- if (k == null && slotToExpunge == staleSlot)
- slotToExpunge = i;
- }
-
- // If key not found, put new entry in stale slot
- tab[staleSlot].value = null;
- tab[staleSlot] = new Entry(key, value);
-
- // If there are any other stale entries in run, expunge them
- if (slotToExpunge != staleSlot)
- cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
- }
-
- /**
- * Expunge a stale entry by rehashing any possibly colliding entries lying between staleSlot and the next null slot. This also
- * expunges any other stale entries encountered before the trailing null. See Knuth, Section 6.4
- *
- * @param staleSlot index of slot known to have null key
- * @return the index of the next null slot after staleSlot (all between staleSlot and this slot will have been checked for
- * expunging).
- */
- private int expungeStaleEntry(int staleSlot) {
- Entry[] tab = table;
- int len = tab.length;
-
- // expunge entry at staleSlot
- tab[staleSlot].value = null;
- tab[staleSlot] = null;
- size--;
-
- // Rehash until we encounter null
- Entry e;
- int i;
- for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
- CoroutineLocal k = e.get();
- if (k == null) {
- e.value = null;
- tab[i] = null;
- size--;
- }
- else {
- int h = k.coroutineLocalHashCode & (len - 1);
- if (h != i) {
- tab[i] = null;
-
- // Unlike Knuth 6.4 Algorithm R, we must scan until
- // null because multiple entries could have been stale.
- while (tab[h] != null)
- h = nextIndex(h, len);
- tab[h] = e;
- }
- }
- }
- return i;
- }
-
- /**
- * Heuristically scan some cells looking for stale entries. This is invoked when either a new element is added, or another stale one
- * has been expunged. It performs a logarithmic number of scans, as a balance between no scanning (fast but retains garbage) and a
- * number of scans proportional to number of elements, that would find all garbage but would cause some insertions to take O(n)
- * time.
- *
- * @param i a position known NOT to hold a stale entry. The scan starts at the element after i.
- *
- * @param n scan control: log2(n) cells are scanned, unless a stale entry is found, in which case
- * log2(table.length)-1 additional cells are scanned. When called from insertions, this parameter is the number
- * of elements, but when from replaceStaleEntry, it is the table length. (Note: all this could be changed to be either
- * more or less aggressive by weighting n instead of just using straight log n. But this version is simple, fast, and
- * seems to work well.)
- *
- * @return true if any stale entries have been removed.
- */
- private boolean cleanSomeSlots(int i, int n) {
- boolean removed = false;
- Entry[] tab = table;
- int len = tab.length;
- do {
- i = nextIndex(i, len);
- Entry e = tab[i];
- if (e != null && e.get() == null) {
- n = len;
- removed = true;
- i = expungeStaleEntry(i);
- }
- }
- while ((n >>>= 1) != 0);
- return removed;
- }
-
- /**
- * Re-pack and/or re-size the table. First scan the entire table removing stale entries. If this doesn't sufficiently shrink the
- * size of the table, double the table size.
- */
- private void rehash() {
- expungeStaleEntries();
-
- // Use lower threshold for doubling to avoid hysteresis
- if (size >= threshold - threshold / 4)
- resize();
- }
-
- /**
- * Double the capacity of the table.
- */
- private void resize() {
- Entry[] oldTab = table;
- int oldLen = oldTab.length;
- int newLen = oldLen * 2;
- Entry[] newTab = new Entry[newLen];
- int count = 0;
-
- for (int j = 0; j < oldLen; ++j) {
- Entry e = oldTab[j];
- if (e != null) {
- CoroutineLocal k = e.get();
- if (k == null) {
- e.value = null; // Help the GC
- }
- else {
- int h = k.coroutineLocalHashCode & (newLen - 1);
- while (newTab[h] != null)
- h = nextIndex(h, newLen);
- newTab[h] = e;
- count++;
- }
- }
- }
-
- setThreshold(newLen);
- size = count;
- table = newTab;
- }
-
- /**
- * Expunge all stale entries in the table.
- */
- private void expungeStaleEntries() {
- Entry[] tab = table;
- int len = tab.length;
- for (int j = 0; j < len; j++) {
- Entry e = tab[j];
- if (e != null && e.get() == null)
- expungeStaleEntry(j);
- }
- }
- }
-}
diff --git a/src/share/classes/java/dyn/CoroutineSupport.java b/src/share/classes/java/dyn/CoroutineSupport.java
index cc245cd4acac29d8e654a6b0a3bea1ffb4dc975e..5b2cfdf1037def0d75bf05bd1542b601d20be8b0 100644
--- a/src/share/classes/java/dyn/CoroutineSupport.java
+++ b/src/share/classes/java/dyn/CoroutineSupport.java
@@ -25,289 +25,356 @@
package java.dyn;
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.Contended;
+import sun.misc.SharedSecrets;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+@Contended
public class CoroutineSupport {
- // Controls debugging and tracing, for maximum performance the actual if(DEBUG/TRACE) code needs to be commented out
- static final boolean DEBUG = false;
- static final boolean TRACE = false;
-
- static final Object TERMINATED = new Object();
-
- // The thread that this CoroutineSupport belongs to. There's only one CoroutineSupport per Thread
- private final Thread thread;
- // The initial coroutine of the Thread
- private final Coroutine threadCoroutine;
-
- // The currently executing, symmetric or asymmetric coroutine
- CoroutineBase currentCoroutine;
- // The anchor of the doubly-linked ring of coroutines
- Coroutine scheduledCoroutines;
-
- static {
- registerNatives();
- }
-
- public CoroutineSupport(Thread thread) {
- if (thread.getCoroutineSupport() != null) {
- throw new IllegalArgumentException("Cannot instantiate CoroutineThreadSupport for existing Thread");
- }
- this.thread = thread;
- threadCoroutine = new Coroutine(this, getThreadCoroutine());
- threadCoroutine.next = threadCoroutine;
- threadCoroutine.last = threadCoroutine;
- currentCoroutine = threadCoroutine;
- scheduledCoroutines = threadCoroutine;
- }
-
- public Coroutine threadCoroutine() {
- return threadCoroutine;
- }
-
- void addCoroutine(Coroutine coroutine, long stacksize) {
- assert scheduledCoroutines != null;
- assert currentCoroutine != null;
-
- coroutine.data = createCoroutine(coroutine, stacksize);
- if (DEBUG) {
- System.out.println("add Coroutine " + coroutine + ", data" + coroutine.data);
- }
-
- // add the coroutine into the doubly linked ring
- coroutine.next = scheduledCoroutines.next;
- coroutine.last = scheduledCoroutines;
- scheduledCoroutines.next = coroutine;
- coroutine.next.last = coroutine;
- }
-
- void addCoroutine(AsymCoroutine, ?> coroutine, long stacksize) {
- coroutine.data = createCoroutine(coroutine, stacksize);
- if (DEBUG) {
- System.out.println("add AsymCoroutine " + coroutine + ", data" + coroutine.data);
- }
-
- coroutine.caller = null;
- }
-
- Thread getThread() {
- return thread;
- }
-
- public void drain() {
- if (Thread.currentThread() != thread) {
- throw new IllegalArgumentException("Cannot drain another threads CoroutineThreadSupport");
- }
-
- if (DEBUG) {
- System.out.println("draining");
- }
- try {
- // drain all scheduled coroutines
- while (scheduledCoroutines.next != scheduledCoroutines) {
- symmetricExitInternal(scheduledCoroutines.next);
- }
-
- CoroutineBase coro;
- while ((coro = cleanupCoroutine()) != null) {
- System.out.println(coro);
- throw new NotImplementedException();
- }
- } catch (Throwable t) {
- t.printStackTrace();
- }
- }
-
- void symmetricYield() {
- if (scheduledCoroutines != currentCoroutine) {
- throw new IllegalThreadStateException("Cannot call yield from within an asymmetric coroutine");
- }
- assert currentCoroutine instanceof Coroutine;
-
- if (TRACE) {
- System.out.println("locking for symmetric yield...");
- }
-
- Coroutine next = scheduledCoroutines.next;
- if (next == scheduledCoroutines) {
- return;
- }
-
- if (TRACE) {
- System.out.println("symmetric yield to " + next);
- }
-
- final Coroutine current = scheduledCoroutines;
- scheduledCoroutines = next;
- currentCoroutine = next;
-
- switchTo(current, next);
- }
-
- public void symmetricYieldTo(Coroutine target) {
- if (scheduledCoroutines != currentCoroutine) {
- throw new IllegalThreadStateException("Cannot call yield from within an asymmetric coroutine");
- }
- assert currentCoroutine instanceof Coroutine;
-
- moveCoroutine(scheduledCoroutines, target);
-
- final Coroutine current = scheduledCoroutines;
- scheduledCoroutines = target;
- currentCoroutine = target;
-
- switchTo(current, target);
- }
-
- private void moveCoroutine(Coroutine a, Coroutine position) {
- // remove a from the ring
- a.last.next = a.next;
- a.next.last = a.last;
-
- // ... and insert at the new position
- a.next = position.next;
- a.last = position;
- a.next.last = a;
- position.next = a;
- }
-
- public void symmetricStopCoroutine(Coroutine target) {
- if (scheduledCoroutines != currentCoroutine) {
- throw new IllegalThreadStateException("Cannot call yield from within an asymmetric coroutine");
- }
- assert currentCoroutine instanceof Coroutine;
-
- moveCoroutine(scheduledCoroutines, target);
-
- final Coroutine current = scheduledCoroutines;
- scheduledCoroutines = target;
- currentCoroutine = target;
-
- switchToAndExit(current, target);
- }
-
- void symmetricExitInternal(Coroutine coroutine) {
- if (scheduledCoroutines != currentCoroutine) {
- throw new IllegalThreadStateException("Cannot call exitNext from within an unscheduled coroutine");
- }
- assert currentCoroutine instanceof Coroutine;
- assert currentCoroutine != coroutine;
-
- // remove the coroutine from the ring
- coroutine.last.next = coroutine.next;
- coroutine.next.last = coroutine.last;
-
- if (!isDisposable(coroutine.data)) {
- // and insert it before the current coroutine
- coroutine.last = scheduledCoroutines.last;
- coroutine.next = scheduledCoroutines;
- coroutine.last.next = coroutine;
- scheduledCoroutines.last = coroutine;
-
- final Coroutine current = scheduledCoroutines;
- scheduledCoroutines = coroutine;
- currentCoroutine = coroutine;
- switchToAndExit(current, coroutine);
- }
- }
-
- void asymmetricCall(AsymCoroutine, ?> target) {
- if (target.threadSupport != this) {
- throw new IllegalArgumentException("Cannot activate a coroutine that belongs to another thread");
- }
- if (target.caller != null) {
- throw new IllegalArgumentException("Coroutine already in use");
- }
- if (target.data == 0) {
- throw new IllegalArgumentException("Target coroutine has already finished");
- }
- if (TRACE) {
- System.out.println("yieldCall " + target + " (" + target.data + ")");
- }
-
- final CoroutineBase current = currentCoroutine;
- target.caller = current;
- currentCoroutine = target;
- switchTo(target.caller, target);
- }
-
- void asymmetricReturn(final AsymCoroutine, ?> current) {
- if (current != currentCoroutine) {
- throw new IllegalThreadStateException("cannot return from non-current fiber");
- }
- final CoroutineBase caller = current.caller;
- if (TRACE) {
- System.out.println("yieldReturn " + caller + " (" + caller.data + ")");
- }
-
- current.caller = null;
- currentCoroutine = caller;
- switchTo(current, currentCoroutine);
- }
-
- void asymmetricReturnAndTerminate(final AsymCoroutine, ?> current) {
- if (current != currentCoroutine) {
- throw new IllegalThreadStateException("cannot return from non-current fiber");
- }
- final CoroutineBase caller = current.caller;
- if (TRACE) {
- System.out.println("yieldReturn " + caller + " (" + caller.data + ")");
- }
-
- current.caller = null;
- currentCoroutine = caller;
- switchToAndTerminate(current, currentCoroutine);
- }
-
- void terminateCoroutine() {
- assert currentCoroutine == scheduledCoroutines;
- assert currentCoroutine != threadCoroutine : "cannot exit thread coroutine";
- assert scheduledCoroutines != scheduledCoroutines.next : "last coroutine shouldn't call coroutineexit";
-
- Coroutine old = scheduledCoroutines;
- Coroutine forward = old.next;
- currentCoroutine = forward;
- scheduledCoroutines = forward;
- old.last.next = old.next;
- old.next.last = old.last;
-
- if (DEBUG) {
- System.out.println("to be terminated: " + old);
- }
- switchToAndTerminate(old, forward);
- }
-
- void terminateCallable() {
- assert currentCoroutine != scheduledCoroutines;
- assert currentCoroutine instanceof AsymCoroutine, ?>;
-
- if (DEBUG) {
- System.out.println("to be terminated: " + currentCoroutine);
- }
- asymmetricReturnAndTerminate((AsymCoroutine, ?>) currentCoroutine);
- }
-
- public boolean isCurrent(CoroutineBase coroutine) {
- return coroutine == currentCoroutine;
- }
-
- public CoroutineBase getCurrent() {
- return currentCoroutine;
- }
-
- private static native void registerNatives();
-
- private static native long getThreadCoroutine();
-
- private static native long createCoroutine(CoroutineBase coroutine, long stacksize);
-
- private static native void switchTo(CoroutineBase current, CoroutineBase target);
-
- private static native void switchToAndTerminate(CoroutineBase current, CoroutineBase target);
-
- private static native void switchToAndExit(CoroutineBase current, CoroutineBase target);
-
- private static native boolean isDisposable(long coroutine);
-
- private static native CoroutineBase cleanupCoroutine();
+ private static final boolean CHECK_LOCK = true;
+ private static final int SPIN_BACKOFF_LIMIT = 2 << 8;
+
+ private static AtomicInteger idGen = new AtomicInteger();
+
+ // The thread that this CoroutineSupport belongs to. There's only one CoroutineSupport per Thread
+ private final Thread thread;
+ // The initial coroutine of the Thread
+ private final Coroutine threadCoroutine;
+
+ // The currently executing coroutine
+ private Coroutine currentCoroutine;
+
+ private volatile Thread lockOwner = null; // also protect double link list of JavaThread->coroutine_list()
+ private int lockRecursive; // volatile is not need
+
+ private final int id;
+ private boolean terminated = false;
+
+ static {
+ registerNatives();
+ }
+
+ public CoroutineSupport(Thread thread) {
+ if (thread.getCoroutineSupport() != null) {
+ throw new IllegalArgumentException("Cannot instantiate CoroutineThreadSupport for existing Thread");
+ }
+ id = idGen.incrementAndGet();
+ this.thread = thread;
+ threadCoroutine = new Coroutine(this, getNativeThreadCoroutine());
+ markThreadCoroutine(threadCoroutine.nativeCoroutine, threadCoroutine);
+ currentCoroutine = threadCoroutine;
+ }
+
+ public Coroutine threadCoroutine() {
+ return threadCoroutine;
+ }
+
+ void addCoroutine(Coroutine coroutine, long stacksize) {
+ assert currentCoroutine != null;
+ lock();
+ try {
+ coroutine.nativeCoroutine = createCoroutine(coroutine, stacksize);
+ } finally {
+ unlock();
+ }
+ }
+
+ Thread getThread() {
+ return thread;
+ }
+
+ public static void checkAndThrowException(Coroutine coroutine) {
+ checkAndThrowException0(coroutine.nativeCoroutine);
+ }
+
+ public void drain() {
+ if (Thread.currentThread() != thread) {
+ throw new IllegalArgumentException("Cannot drain another threads CoroutineThreadSupport");
+ }
+
+ lock();
+ try {
+ // drain all coroutines
+ Coroutine next = null;
+ while ((next = getNextCoroutine(currentCoroutine.nativeCoroutine)) != currentCoroutine) {
+ symmetricExitInternal(next);
+ }
+
+ CoroutineBase coro;
+ while ((coro = cleanupCoroutine()) != null) {
+ System.out.println(coro);
+ throw new NotImplementedException();
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ } finally {
+ assert lockOwner == thread && lockRecursive == 0;
+ terminated = true;
+ unlock();
+ }
+ }
+
+ /**
+ * optimized version of symmetricYieldTo based on assumptions:
+ * 1. we won't simultaneously steal a {@link Coroutine} from other threads
+ * 2. we won't switch to a {@link Coroutine} that's being stolen
+ * 3. we won't steal a running {@link Coroutine}
+ * this function should only be called in
+ * {@link com.alibaba.wisp.engine.WispTask#switchTo(WispTask, WispTask)},
+ * we skipped unnecessary lock to improve performance.
+ * @param target
+ */
+ public boolean unsafeSymmetricYieldTo(Coroutine target) {
+ if (target.threadSupport != this) {
+ return false;
+ }
+ final Coroutine current = currentCoroutine;
+ currentCoroutine = target;
+ switchTo(current, target);
+ //check if locked by exiting coroutine
+ beforeResume(current);
+ return true;
+ }
+
+ public void symmetricYieldTo(Coroutine target) {
+ lock();
+ if (target.threadSupport != this) {
+ unlock();
+ return;
+ }
+ moveCoroutine(currentCoroutine.nativeCoroutine, target.nativeCoroutine);
+ unlockLater(target);
+ unsafeSymmetricYieldTo(target);
+ }
+
+
+ public void symmetricStopCoroutine(Coroutine target) {
+ Coroutine current;
+ lock();
+ try {
+ if (target.threadSupport != this) {
+ unlock();
+ return;
+ }
+ current = currentCoroutine;
+ currentCoroutine = target;
+ moveCoroutine(current.nativeCoroutine, target.nativeCoroutine);
+ } finally {
+ unlock();
+ }
+ switchToAndExit(current, target);
+ }
+
+
+ /**
+ * switch to coroutine and throw Exception in coroutine
+ */
+ void symmetricExitInternal(Coroutine coroutine) {
+ assert currentCoroutine != coroutine;
+ assert coroutine.threadSupport == this;
+
+ if (!testDisposableAndTryReleaseStack(coroutine.nativeCoroutine)) {
+ moveCoroutine(currentCoroutine.nativeCoroutine, coroutine.nativeCoroutine);
+
+ final Coroutine current = currentCoroutine;
+ currentCoroutine = coroutine;
+ switchToAndExit(current, coroutine);
+ beforeResume(current);
+ }
+ }
+
+
+ /**
+ * terminate current coroutine and yield forward
+ */
+ void terminateCoroutine() {
+ assert currentCoroutine != threadCoroutine : "cannot exit thread coroutine";
+ assert currentCoroutine != getNextCoroutine(currentCoroutine.nativeCoroutine) : "last coroutine shouldn't call coroutineexit";
+
+ lock();
+ Coroutine old = currentCoroutine;
+ Coroutine forward = getNextCoroutine(old.nativeCoroutine);
+ currentCoroutine = forward;
+
+ unlockLater(forward);
+ switchToAndTerminate(old, forward);
+ }
+
+ /**
+ * Steal coroutine from it's carrier thread to current thread.
+ *
+ * @param failOnContention steal fail if there's too much lock contention
+ *
+ * @param coroutine to be stolen
+ */
+ Coroutine.StealResult steal(Coroutine coroutine, boolean failOnContention) {
+ assert coroutine.threadSupport.threadCoroutine() != coroutine;
+ CoroutineSupport source = this;
+ CoroutineSupport target = SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport();
+
+ if (source == target) {
+ return Coroutine.StealResult.SUCCESS;
+ }
+
+ if (source.id < target.id) { // prevent dead lock
+ if (!source.lockInternal(failOnContention)) {
+ return Coroutine.StealResult.FAIL_BY_CONTENTION;
+ }
+ target.lock();
+ } else {
+ target.lock();
+ if (!source.lockInternal(failOnContention)) {
+ target.unlock();
+ return Coroutine.StealResult.FAIL_BY_CONTENTION;
+ }
+ }
+
+ try {
+ if (source.terminated || coroutine.finished ||
+ coroutine.threadSupport != source || // already been stolen
+ source.currentCoroutine == coroutine) {
+ return Coroutine.StealResult.FAIL_BY_STATUS;
+ }
+ if (!stealCoroutine(coroutine.nativeCoroutine)) { // native frame
+ return Coroutine.StealResult.FAIL_BY_NATIVE_FRAME;
+ }
+ coroutine.threadSupport = target;
+ } finally {
+ source.unlock();
+ target.unlock();
+ }
+
+ return Coroutine.StealResult.SUCCESS;
+ }
+
+ /**
+ * Can not be stolen while executing this, because lock is held
+ */
+ void beforeResume(CoroutineBase source) {
+ if (source.needsUnlock) {
+ source.needsUnlock = false;
+ source.threadSupport.unlock();
+ }
+ }
+
+ private void unlockLater(CoroutineBase next) {
+ if (CHECK_LOCK && next.needsUnlock) {
+ throw new InternalError("pending unlock");
+ }
+ next.needsUnlock = true;
+ }
+
+ private void lock() {
+ boolean success = lockInternal(false);
+ assert success;
+ }
+
+ private boolean lockInternal(boolean tryingLock) {
+ final Thread th = SharedSecrets.getJavaLangAccess().currentThread0();
+ if (lockOwner == th) {
+ lockRecursive++;
+ return true;
+ }
+ for (int spin = 1; ; ) {
+ if (lockOwner == null && LOCK_UPDATER.compareAndSet(this, null, th)) {
+ return true;
+ }
+ for (int i = 0; i < spin; ) {
+ i++;
+ }
+ if (spin == SPIN_BACKOFF_LIMIT) {
+ if (tryingLock) {
+ return false;
+ }
+ SharedSecrets.getJavaLangAccess().yield0(); // yield safepoint
+ } else { // back off
+ spin *= 2;
+ }
+ }
+ }
+
+ private void unlock() {
+ if (CHECK_LOCK && SharedSecrets.getJavaLangAccess().currentThread0() != lockOwner) {
+ throw new InternalError("unlock from non-owner thread");
+ }
+ if (lockRecursive > 0) {
+ lockRecursive--;
+ } else {
+ LOCK_UPDATER.lazySet(this, null);
+ }
+ }
+
+ private static final AtomicReferenceFieldUpdater LOCK_UPDATER;
+
+ static {
+ LOCK_UPDATER = AtomicReferenceFieldUpdater.newUpdater(CoroutineSupport.class, Thread.class, "lockOwner");
+ }
+
+ public boolean isCurrent(CoroutineBase coroutine) {
+ return coroutine == currentCoroutine;
+ }
+
+ public CoroutineBase getCurrent() {
+ return currentCoroutine;
+ }
+
+
+ private static native void registerNatives();
+
+ private static native long getNativeThreadCoroutine();
+
+ /**
+ * need lock because below methods will operate on thread->coroutine_list()
+ */
+ private static native long createCoroutine(CoroutineBase coroutine, long stacksize);
+
+ private static native void switchToAndTerminate(CoroutineBase current, CoroutineBase target);
+
+ private static native boolean testDisposableAndTryReleaseStack(long coroutine);
+
+ private static native boolean stealCoroutine(long coroPtr);
+ // end of locking
+
+ /**
+ * get next {@link Coroutine} from current thread's doubly linked {@link Coroutine} list
+ * @param coroPtr hotspot coroutine
+ * @return java Coroutine
+ */
+ private static native Coroutine getNextCoroutine(long coroPtr);
+
+ /**
+ * move coroPtr to targetPtr's next field in underlying hotspot coroutine list
+ * @param coroPtr current threadCoroutine
+ * @param targetPtr coroutine that is about to exit
+ */
+ private static native void moveCoroutine(long coroPtr, long targetPtr);
+
+ /**
+ * track hotspot couroutine with java coroutine.
+ * @param coroPtr threadCoroutine in hotspot
+ * @param threadCoroutine threadCoroutine in java
+ */
+ private static native void markThreadCoroutine(long coroPtr, CoroutineBase threadCoroutine);
+
+ private static native void switchTo(CoroutineBase current, CoroutineBase target);
+
+ private static native void switchToAndExit(CoroutineBase current, CoroutineBase target);
+
+ private static native CoroutineBase cleanupCoroutine();
+
+ public static native void setWispBooted();
+
+ /**
+ * this will turn on a safepoint to stop all threads.
+ * @param coroPtr
+ * @return target coroutine's stack
+ */
+ public static native StackTraceElement[] getCoroutineStack(long coroPtr);
+
+ private static native void checkAndThrowException0(long coroPtr);
}
diff --git a/src/share/classes/java/lang/SecurityManager.java b/src/share/classes/java/lang/SecurityManager.java
index 2784ffd5c6c09362724fc968b2bbcb7eb03097ba..676073b20cbee9e0421bc8dd966ea1dff5284db9 100644
--- a/src/share/classes/java/lang/SecurityManager.java
+++ b/src/share/classes/java/lang/SecurityManager.java
@@ -1773,7 +1773,7 @@ class SecurityManager {
* @see java.lang.ThreadGroup
*/
public ThreadGroup getThreadGroup() {
- return Thread.currentThread().getThreadGroup();
+ return Thread.currentThread0().getThreadGroup();
}
}
diff --git a/src/share/classes/java/lang/System.java b/src/share/classes/java/lang/System.java
index fc67d54afa8cca44a41ae33af902ad3b1deb0dd8..1de404d3ab7648c81b7759e4b6f34e771564933f 100644
--- a/src/share/classes/java/lang/System.java
+++ b/src/share/classes/java/lang/System.java
@@ -34,12 +34,14 @@ import java.util.StringTokenizer;
import java.util.Map;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.security.AllPermission;
import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider;
import com.alibaba.rcm.internal.AbstractResourceContainer;
import com.alibaba.tenant.TenantContainer;
import com.alibaba.tenant.TenantGlobals;
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
import sun.misc.VM;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
@@ -1318,6 +1320,44 @@ public final class System {
public AbstractResourceContainer getInheritedResourceContainer(Thread thread) {
return thread.inheritedResourceContainer;
}
+ public Thread currentThread0() {
+ return Thread.currentThread0();
+ }
+
+ @Override
+ public void yield0() {
+ Thread.yield0();
+ }
+
+ @Override
+ public void setWispTask(Thread thread, WispTask task) {
+ thread.wispTask = task;
+ }
+
+ @Override
+ public WispTask getWispTask(Thread thread) {
+ return thread.wispTask;
+ }
+
+ @Override
+ public void setWispAlive(Thread thread, boolean b) {
+ thread.wispIsAlive = b;
+ }
+
+ @Override
+ public boolean isInSameNative(Thread thread) {
+ return thread.isInSameNative();
+ }
+
+ @Override
+ public void threadExit(Thread thread) {
+ thread.exit();
+ }
+
+ @Override
+ public void wispBooted() {
+ Thread.wispBooted();
+ }
});
}
}
diff --git a/src/share/classes/java/lang/Thread.java b/src/share/classes/java/lang/Thread.java
index 005a47e3817226faf3595356b9ebf5420da3cf1a..e69e583da03566dd7a2827721de0c44b8b4a664b 100644
--- a/src/share/classes/java/lang/Thread.java
+++ b/src/share/classes/java/lang/Thread.java
@@ -39,6 +39,9 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.LockSupport;
import com.alibaba.rcm.internal.AbstractResourceContainer;
import sun.misc.VM;
+import com.alibaba.wisp.engine.*;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -277,22 +280,58 @@ class Thread implements Runnable {
private CoroutineSupport coroutineSupport;
+ WispTask wispTask;
+
+ volatile boolean wispIsAlive;
+ // wispTask is set by carrier thread async, so we need additional flag
+
public CoroutineSupport getCoroutineSupport() {
- return coroutineSupport;
+ if (coroutineSupport != null) {
+ return coroutineSupport;
+ }
+
+ Thread t = currentThread0();
+ return t == this ? null : t.getCoroutineSupport();
}
private void initializeCoroutineSupport() {
- if (sun.misc.VM.isEnableCoroutine()) {
+ if (coroutineSupport == null) {
coroutineSupport = new CoroutineSupport(this);
}
}
+ private void destroyCoroutineSupport() {
+ try {
+ if (coroutineSupport != null) {
+ if (WEA != null) {
+ WEA.destroy();
+ }
+ coroutineSupport.drain();
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
/**
* Returns a reference to the currently executing thread object.
*
+ * Returns a thread wrapper of the currently executing wispTask if
+ * WispCarrier.transparentWispSwitch() is on.
+ *
* @return the currently executing thread.
*/
- public static native Thread currentThread();
+ public static Thread currentThread() {
+ if (WEA != null) {
+ return WEA.getCurrentTask().getThreadWrapper();
+ }
+ return currentThread0();
+ }
+
+ /**
+ * Always return the underlying Java thread.
+ */
+ static native Thread currentThread0();
/**
* A hint to the scheduler that the current thread is willing to yield
@@ -310,7 +349,15 @@ class Thread implements Runnable {
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
- public static native void yield();
+ public static void yield() {
+ if (WEA != null) {
+ WEA.yield();
+ } else {
+ yield0();
+ }
+ }
+
+ static native void yield0();
/**
* Causes the currently executing thread to sleep (temporarily cease
@@ -329,7 +376,22 @@ class Thread implements Runnable {
* interrupted status of the current thread is
* cleared when this exception is thrown.
*/
- public static native void sleep(long millis) throws InterruptedException;
+ public static void sleep(long millis) throws InterruptedException {
+ if (WEA != null) {
+ if (Thread.interrupted()) {
+ throw new InterruptedException("sleep interrupted");
+ }
+ WEA.sleep(millis);
+ if (Thread.interrupted()) {
+ throw new InterruptedException("sleep interrupted");
+ }
+ return;
+ } else {
+ sleep0(millis);
+ }
+ }
+
+ public static native void sleep0(long millis) throws InterruptedException;
/**
* Causes the currently executing thread to sleep (temporarily cease
@@ -754,7 +816,10 @@ class Thread implements Runnable {
boolean started = false;
try {
- start0();
+ if (!(WEA != null && WispEngine.enableThreadAsWisp() &&
+ WEA.tryStartThreadAsWisp(this, target))) {
+ start0();
+ }
started = true;
} finally {
try {
@@ -793,11 +858,7 @@ class Thread implements Runnable {
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
*/
- private void exit() {
- if (sun.misc.VM.isEnableCoroutine() && (coroutineSupport != null)) {
- coroutineSupport.drain();
- }
-
+ void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
@@ -959,18 +1020,29 @@ class Thread implements Runnable {
* @spec JSR-51
*/
public void interrupt() {
- if (this != Thread.currentThread())
+
+ if (this != Thread.currentThread()) {
checkAccess();
+ }
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
- interrupt0(); // Just to set the interrupt flag
+ if (WEA != null && wispTask != null) {
+ WEA.interrupt(wispTask);
+ } else {
+ interrupt0(); // Just to set the interrupt flag
+ }
b.interrupt(this);
return;
}
}
- interrupt0();
+
+ if (WEA != null && wispTask != null) {
+ WEA.interrupt(wispTask);
+ } else {
+ interrupt0();
+ }
}
/**
@@ -991,7 +1063,14 @@ class Thread implements Runnable {
* @revised 6.0
*/
public static boolean interrupted() {
- return currentThread().isInterrupted(true);
+ Thread current = currentThread0();
+ if (WEA != null) {
+ WispTask task = WEA.getCurrentTask();
+ if (task != null) {
+ return WEA.testInterruptedAndClear(task, true);
+ }
+ }
+ return current.isInterrupted(true);
}
/**
@@ -1008,6 +1087,9 @@ class Thread implements Runnable {
* @revised 6.0
*/
public boolean isInterrupted() {
+ if (WEA != null && wispTask != null) {
+ return WEA.testInterruptedAndClear(wispTask, false);
+ }
return isInterrupted(false);
}
@@ -1047,7 +1129,14 @@ class Thread implements Runnable {
* @return true
if this thread is alive;
* false
otherwise.
*/
- public final native boolean isAlive();
+ public final boolean isAlive() {
+ if (WEA != null && wispIsAlive) {
+ return true;
+ }
+ return isAlive0();
+ }
+
+ private final native boolean isAlive0();
/**
* Suspends this thread.
@@ -1581,7 +1670,29 @@ class Thread implements Runnable {
* @since 1.5
*/
public StackTraceElement[] getStackTrace() {
- if (this != Thread.currentThread()) {
+ boolean slowPath;
+ if (WEA != null) {
+ WispTask task = this.wispTask;
+ if (task == null) {
+ // When we create a thread, coroutine will not be created immediately.
+ // So if we take the stack trace at once, it will NCE.
+ // See: NullStackTrace.java and 6571589, Thread return an array which size is 0.
+ return new StackTraceElement[0];
+ }
+ if (!WEA.runningAsCoroutine(this)) {
+ slowPath = this != Thread.currentThread();
+ } else {
+ boolean isCurrentTask = WEA.getCurrentTask() == task;
+ slowPath = !isCurrentTask;
+ if (!WEA.isThreadTask(task) && !isCurrentTask) {
+ return WEA.getStackTrace(task);
+ }
+ }
+ } else {
+ slowPath = this != Thread.currentThread();
+ }
+
+ if (slowPath) {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
@@ -1864,6 +1975,11 @@ class Thread implements Runnable {
return sun.misc.VM.toThreadState(threadStatus);
}
+ /**
+ * @return if this thread is still executing the same JNI code
+ */
+ native boolean isInSameNative();
+
// Added in JSR-166
/**
@@ -2094,4 +2210,15 @@ class Thread implements Runnable {
private native void resume0();
private native void interrupt0();
private native void setNativeName(String name);
+
+ // prevent load Wisp classes accidentally
+ private static WispEngineAccess WEA;
+
+ static void wispBooted() {
+ if (!WispEngine.transparentWispSwitch()) {
+ // assert in this class will crash jvm
+ throw new AssertionError();
+ }
+ WEA = SharedSecrets.getWispEngineAccess();
+ }
}
diff --git a/src/share/classes/java/lang/management/PlatformComponent.java b/src/share/classes/java/lang/management/PlatformComponent.java
index bf84bdc983b82b920e8a0a2f85c5f0766cd6963b..93fe022a965693aba4c5e7a4a1312748624dd0a8 100644
--- a/src/share/classes/java/lang/management/PlatformComponent.java
+++ b/src/share/classes/java/lang/management/PlatformComponent.java
@@ -37,6 +37,7 @@ import javax.management.ObjectName;
import com.alibaba.management.TenantContainerMXBean;
import com.alibaba.management.ElasticHeapMXBean;
+import com.alibaba.management.WispCounterMXBean;
import com.sun.management.HotSpotDiagnosticMXBean;
import com.sun.management.UnixOperatingSystemMXBean;
@@ -303,6 +304,19 @@ enum PlatformComponent {
public List getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getElasticHeapMXBean());
}
+ }),
+
+ /**
+ * Wisp Counter.
+ */
+ WISP_COUNTER(
+ "com.alibaba.management.WispCounterMXBean",
+ "com.alibaba.management", "WispCounter", defaultKeyProperties(),
+ true, // singleton
+ new MXBeanFetcher() {
+ public List getMXBeans() {
+ return Collections.singletonList(ManagementFactoryHelper.getWispCounterMXBean());
+ }
});
diff --git a/src/share/classes/java/net/DatagramSocket.java b/src/share/classes/java/net/DatagramSocket.java
index 18f2fe1d518a7609cf8b748b9055894b15cdb9e3..73ceca624477d1da6a4a3867c17394e550a5920b 100644
--- a/src/share/classes/java/net/DatagramSocket.java
+++ b/src/share/classes/java/net/DatagramSocket.java
@@ -25,6 +25,11 @@
package java.net;
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+import sun.nio.ch.WispUdpSocketImpl;
+
import java.io.IOException;
import java.nio.channels.DatagramChannel;
import java.security.AccessController;
@@ -65,6 +70,13 @@ import java.security.PrivilegedExceptionAction;
*/
public
class DatagramSocket implements java.io.Closeable {
+
+ /**
+ * If WispEngine.transparentWispSwitch(), proxy all
+ * socket request to this impl.
+ */
+ private WispUdpSocketImpl asyncImpl;
+
/**
* Various states of this socket.
*/
@@ -235,8 +247,12 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4
*/
public DatagramSocket(SocketAddress bindaddr) throws SocketException {
- // create a datagram socket.
- createImpl();
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl = new WispUdpSocketImpl(this);
+ } else {
+ // create a datagram socket.
+ createImpl();
+ }
if (bindaddr != null) {
try {
bind(bindaddr);
@@ -322,6 +338,8 @@ class DatagramSocket implements java.io.Closeable {
static Class> implClass = null;
void createImpl() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
if (impl == null) {
if (factory != null) {
impl = factory.createDatagramSocketImpl();
@@ -349,6 +367,8 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4
*/
DatagramSocketImpl getImpl() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
if (!created)
createImpl();
return impl;
@@ -378,6 +398,10 @@ class DatagramSocket implements java.io.Closeable {
addr = new InetSocketAddress(0);
if (!(addr instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type!");
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.bind(addr);
+ return;
+ }
InetSocketAddress epoint = (InetSocketAddress) addr;
if (epoint.isUnresolved())
throw new SocketException("Unresolved address");
@@ -454,6 +478,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #disconnect
*/
public void connect(InetAddress address, int port) {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.connect(address, port);
+ return;
+ }
try {
connectInternal(address, port);
} catch (SocketException se) {
@@ -484,6 +512,10 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4
*/
public void connect(SocketAddress addr) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.connect(addr);
+ return;
+ }
if (addr == null)
throw new IllegalArgumentException("Address can't be null");
if (!(addr instanceof InetSocketAddress))
@@ -501,6 +533,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #connect
*/
public void disconnect() {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.disconnect();
+ return;
+ }
synchronized (this) {
if (isClosed())
return;
@@ -525,6 +561,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4
*/
public boolean isBound() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.isBound();
+ }
return bound;
}
@@ -539,6 +578,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4
*/
public boolean isConnected() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.isConnected();
+ }
return connectState != ST_NOT_CONNECTED;
}
@@ -553,6 +595,9 @@ class DatagramSocket implements java.io.Closeable {
* @return the address to which this socket is connected.
*/
public InetAddress getInetAddress() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getInetAddress();
+ }
return connectedAddress;
}
@@ -567,6 +612,9 @@ class DatagramSocket implements java.io.Closeable {
* @return the port number to which this socket is connected.
*/
public int getPort() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getPort();
+ }
return connectedPort;
}
@@ -652,6 +700,10 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51
*/
public void send(DatagramPacket p) throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.send(p);
+ return;
+ }
InetAddress packetAddress = null;
synchronized (p) {
if (isClosed())
@@ -726,6 +778,10 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51
*/
public synchronized void receive(DatagramPacket p) throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ p.length = asyncImpl.receive(p, p.bufLength);
+ return;
+ }
synchronized (p) {
if (!isBound())
bind(new InetSocketAddress(0));
@@ -845,6 +901,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.1
*/
public InetAddress getLocalAddress() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getLocalAddress();
+ }
if (isClosed())
return null;
InetAddress in = null;
@@ -872,6 +931,9 @@ class DatagramSocket implements java.io.Closeable {
{@code 0} if it is not bound yet.
*/
public int getLocalPort() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getLocalPort();
+ }
if (isClosed())
return -1;
try {
@@ -897,6 +959,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #getSoTimeout()
*/
public synchronized void setSoTimeout(int timeout) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setSoTimeout(timeout);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
@@ -912,6 +978,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setSoTimeout(int)
*/
public synchronized int getSoTimeout() throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getSoTimeout();
+ }
if (isClosed())
throw new SocketException("Socket is closed");
if (getImpl() == null)
@@ -956,6 +1025,10 @@ class DatagramSocket implements java.io.Closeable {
*/
public synchronized void setSendBufferSize(int size)
throws SocketException{
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setSendBufferSize(size);
+ return;
+ }
if (!(size > 0)) {
throw new IllegalArgumentException("negative send size");
}
@@ -974,6 +1047,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setSendBufferSize
*/
public synchronized int getSendBufferSize() throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getSendBufferSize();
+ }
if (isClosed())
throw new SocketException("Socket is closed");
int result = 0;
@@ -1014,6 +1090,10 @@ class DatagramSocket implements java.io.Closeable {
*/
public synchronized void setReceiveBufferSize(int size)
throws SocketException{
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setReceiveBufferSize(size);
+ return;
+ }
if (size <= 0) {
throw new IllegalArgumentException("invalid receive size");
}
@@ -1032,6 +1112,9 @@ class DatagramSocket implements java.io.Closeable {
*/
public synchronized int getReceiveBufferSize()
throws SocketException{
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getReceiveBufferSize();
+ }
if (isClosed())
throw new SocketException("Socket is closed");
int result = 0;
@@ -1077,6 +1160,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #isClosed()
*/
public synchronized void setReuseAddress(boolean on) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setReuseAddress(on);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
// Integer instead of Boolean for compatibility with older DatagramSocketImpl
@@ -1096,6 +1183,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setReuseAddress(boolean)
*/
public synchronized boolean getReuseAddress() throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getReuseAddress();
+ }
if (isClosed())
throw new SocketException("Socket is closed");
Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);
@@ -1120,6 +1210,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #getBroadcast()
*/
public synchronized void setBroadcast(boolean on) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setBroadcast(on);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on));
@@ -1134,6 +1228,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setBroadcast(boolean)
*/
public synchronized boolean getBroadcast() throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getBroadcast();
+ }
if (isClosed())
throw new SocketException("Socket is closed");
return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue();
@@ -1177,6 +1274,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #getTrafficClass
*/
public synchronized void setTrafficClass(int tc) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setTrafficClass(tc);
+ return;
+ }
if (tc < 0 || tc > 255)
throw new IllegalArgumentException("tc is not in range 0 -- 255");
@@ -1209,6 +1310,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setTrafficClass(int)
*/
public synchronized int getTrafficClass() throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getTrafficClass();
+ }
if (isClosed())
throw new SocketException("Socket is closed");
return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue();
@@ -1227,6 +1331,10 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51
*/
public void close() {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.close();
+ return;
+ }
synchronized(closeLock) {
if (isClosed())
return;
@@ -1242,6 +1350,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4
*/
public boolean isClosed() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.isClosed();
+ }
synchronized(closeLock) {
return closed;
}
@@ -1262,6 +1373,9 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51
*/
public DatagramChannel getChannel() {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getChannel();
+ }
return null;
}
diff --git a/src/share/classes/java/net/ServerSocket.java b/src/share/classes/java/net/ServerSocket.java
index 6dd0496223bc5e0831a2416cddc83be1d9e97f42..f56ec85566ac412a102e062e1b3d10f1e6ad10df 100644
--- a/src/share/classes/java/net/ServerSocket.java
+++ b/src/share/classes/java/net/ServerSocket.java
@@ -25,6 +25,9 @@
package java.net;
+import com.alibaba.wisp.engine.WispEngine;
+import sun.nio.ch.WispServerSocketImpl;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.channels.ServerSocketChannel;
@@ -52,6 +55,8 @@ import sun.security.util.SecurityConstants;
*/
public
class ServerSocket implements java.io.Closeable {
+
+ private WispServerSocketImpl asyncImpl;
/**
* Various states of this socket.
*/
@@ -80,6 +85,9 @@ class ServerSocket implements java.io.Closeable {
*/
ServerSocket(SocketImpl impl) {
checkPermission();
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
this.impl = impl;
impl.setServerSocket(this);
}
@@ -99,6 +107,10 @@ class ServerSocket implements java.io.Closeable {
* @revised 1.4
*/
public ServerSocket() throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl = new WispServerSocketImpl();
+ return;
+ }
setImpl();
}
@@ -242,7 +254,12 @@ class ServerSocket implements java.io.Closeable {
* @since JDK1.1
*/
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
- setImpl();
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl = new WispServerSocketImpl();
+ } else {
+ setImpl();
+ }
+
if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException(
"Port value out of range: " + port);
@@ -268,12 +285,18 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4
*/
SocketImpl getImpl() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (!created)
createImpl();
return impl;
}
private void checkOldImpl() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (impl == null)
return;
// SocketImpl.connect() is a protected method, therefore we need to use
@@ -294,6 +317,9 @@ class ServerSocket implements java.io.Closeable {
}
private void setImpl() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (factory != null) {
impl = factory.createSocketImpl();
checkOldImpl();
@@ -313,6 +339,9 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4
*/
void createImpl() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (impl == null)
setImpl();
try {
@@ -341,6 +370,10 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4
*/
public void bind(SocketAddress endpoint) throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.bind(endpoint);
+ return;
+ }
bind(endpoint, 50);
}
@@ -370,6 +403,10 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4
*/
public void bind(SocketAddress endpoint, int backlog) throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.bind(endpoint, backlog);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isBound())
@@ -418,6 +455,9 @@ class ServerSocket implements java.io.Closeable {
* @see SecurityManager#checkConnect
*/
public InetAddress getInetAddress() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getInetAddress();
+
if (!isBound())
return null;
try {
@@ -447,6 +487,9 @@ class ServerSocket implements java.io.Closeable {
* -1 if the socket is not bound yet.
*/
public int getLocalPort() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getLocalPort();
+
if (!isBound())
return -1;
try {
@@ -524,6 +567,9 @@ class ServerSocket implements java.io.Closeable {
throw new SocketException("Socket is closed");
if (!isBound())
throw new SocketException("Socket is not bound yet");
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.accept();
+ }
Socket s = new Socket((SocketImpl) null);
implAccept(s);
return s;
@@ -546,6 +592,9 @@ class ServerSocket implements java.io.Closeable {
* @spec JSR-51
*/
protected final void implAccept(Socket s) throws IOException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
SocketImpl si = null;
try {
if (s.impl == null)
@@ -593,6 +642,9 @@ class ServerSocket implements java.io.Closeable {
* @spec JSR-51
*/
public void close() throws IOException {
+ if (WispEngine.transparentWispSwitch())
+ asyncImpl.close();
+
synchronized(closeLock) {
if (isClosed())
return;
@@ -619,6 +671,9 @@ class ServerSocket implements java.io.Closeable {
* @spec JSR-51
*/
public ServerSocketChannel getChannel() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getChannel();
+
return null;
}
@@ -629,6 +684,8 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4
*/
public boolean isBound() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.isBound();
// Before 1.3 ServerSockets were always bound during creation
return bound || oldImpl;
}
@@ -640,6 +697,8 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4
*/
public boolean isClosed() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.isClosed();
synchronized(closeLock) {
return closed;
}
@@ -662,6 +721,10 @@ class ServerSocket implements java.io.Closeable {
* @see #getSoTimeout()
*/
public synchronized void setSoTimeout(int timeout) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setSoTimeout(timeout);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
@@ -676,6 +739,8 @@ class ServerSocket implements java.io.Closeable {
* @see #setSoTimeout(int)
*/
public synchronized int getSoTimeout() throws IOException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getSoTimeout();
if (isClosed())
throw new SocketException("Socket is closed");
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
@@ -724,6 +789,10 @@ class ServerSocket implements java.io.Closeable {
* @see #isClosed()
*/
public void setReuseAddress(boolean on) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setReuseAddress(on);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
@@ -740,6 +809,9 @@ class ServerSocket implements java.io.Closeable {
* @see #setReuseAddress(boolean)
*/
public boolean getReuseAddress() throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ return asyncImpl.getReuseAddress();
+ }
if (isClosed())
throw new SocketException("Socket is closed");
return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
@@ -759,6 +831,8 @@ class ServerSocket implements java.io.Closeable {
* @return a string representation of this socket.
*/
public String toString() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.toString();
if (!isBound())
return "ServerSocket[unbound]";
InetAddress in;
@@ -771,10 +845,14 @@ class ServerSocket implements java.io.Closeable {
}
void setBound() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
bound = true;
}
void setCreated() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
created = true;
}
@@ -809,6 +887,8 @@ class ServerSocket implements java.io.Closeable {
* @see SecurityManager#checkSetFactory
*/
public static synchronized void setSocketFactory(SocketImplFactory fac) throws IOException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
if (factory != null) {
throw new SocketException("factory already defined");
}
@@ -856,6 +936,10 @@ class ServerSocket implements java.io.Closeable {
* @see #getReceiveBufferSize
*/
public synchronized void setReceiveBufferSize (int size) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setReceiveBufferSize(size);
+ return;
+ }
if (!(size > 0)) {
throw new IllegalArgumentException("negative receive size");
}
@@ -880,6 +964,9 @@ class ServerSocket implements java.io.Closeable {
*/
public synchronized int getReceiveBufferSize()
throws SocketException{
+ if (WispEngine.transparentWispSwitch())
+ asyncImpl.getReceiveBufferSize();
+
if (isClosed())
throw new SocketException("Socket is closed");
int result = 0;
diff --git a/src/share/classes/java/net/Socket.java b/src/share/classes/java/net/Socket.java
index eed64378b532a375a4a15a6fe941014b3c3a1992..e8e530f85bc3903322bbd859a1c83c1b36bb0cad 100644
--- a/src/share/classes/java/net/Socket.java
+++ b/src/share/classes/java/net/Socket.java
@@ -26,6 +26,8 @@
package java.net;
import sun.security.util.SecurityConstants;
+import com.alibaba.wisp.engine.WispEngine;
+import sun.nio.ch.WispSocketImpl;
import java.io.InputStream;
import java.io.OutputStream;
@@ -54,6 +56,9 @@ import java.security.PrivilegedAction;
*/
public
class Socket implements java.io.Closeable {
+
+ private WispSocketImpl asyncImpl;
+
/**
* Various states of this socket.
*/
@@ -83,9 +88,19 @@ class Socket implements java.io.Closeable {
* @revised 1.4
*/
public Socket() {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl = new WispSocketImpl(this);
+ return;
+ }
setImpl();
}
+ public Socket(SocketChannel sc) {
+ if (!WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+ asyncImpl = new WispSocketImpl(sc, this);
+ }
+
/**
* Creates an unconnected socket, specifying the type of proxy, if any,
* that should be used regardless of any other settings.
@@ -115,6 +130,9 @@ class Socket implements java.io.Closeable {
* @since 1.5
*/
public Socket(Proxy proxy) {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
// Create a copy of Proxy as a security measure
if (proxy == null) {
throw new IllegalArgumentException("Invalid Proxy");
@@ -171,6 +189,8 @@ class Socket implements java.io.Closeable {
checkPermission(impl);
this.impl = impl;
if (impl != null) {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
checkOldImpl();
this.impl.setSocket(this);
}
@@ -439,14 +459,22 @@ class Socket implements java.io.Closeable {
private Socket(SocketAddress address, SocketAddress localAddr,
boolean stream) throws IOException {
- setImpl();
+ if (WispEngine.transparentWispSwitch()) {
+ if (!stream)
+ throw new UnsupportedOperationException();
+ asyncImpl = new WispSocketImpl(this);
+ } else {
+ setImpl();
+ }
+
// backward compatibility
if (address == null)
throw new NullPointerException();
try {
- createImpl(stream);
+ if (!WispEngine.transparentWispSwitch())
+ createImpl(stream);
if (localAddr != null)
bind(localAddr);
connect(address);
@@ -469,6 +497,9 @@ class Socket implements java.io.Closeable {
* @since 1.4
*/
void createImpl(boolean stream) throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (impl == null)
setImpl();
try {
@@ -480,6 +511,9 @@ class Socket implements java.io.Closeable {
}
private void checkOldImpl() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (impl == null)
return;
// SocketImpl.connect() is a protected method, therefore we need to use
@@ -512,6 +546,9 @@ class Socket implements java.io.Closeable {
* @since 1.4
*/
void setImpl() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (factory != null) {
impl = factory.createSocketImpl();
checkOldImpl();
@@ -534,6 +571,9 @@ class Socket implements java.io.Closeable {
* @since 1.4
*/
SocketImpl getImpl() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (!created)
createImpl(true);
return impl;
@@ -553,6 +593,10 @@ class Socket implements java.io.Closeable {
* @spec JSR-51
*/
public void connect(SocketAddress endpoint) throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.connect(endpoint);
+ return;
+ }
connect(endpoint, 0);
}
@@ -589,6 +633,11 @@ class Socket implements java.io.Closeable {
if (!(endpoint instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type");
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.connect(endpoint, timeout);
+ return;
+ }
+
InetSocketAddress epoint = (InetSocketAddress) endpoint;
InetAddress addr = epoint.getAddress ();
int port = epoint.getPort();
@@ -639,6 +688,11 @@ class Socket implements java.io.Closeable {
* @see #isBound
*/
public void bind(SocketAddress bindpoint) throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.bind(bindpoint);
+ return;
+ }
+
if (isClosed())
throw new SocketException("Socket is closed");
if (!oldImpl && isBound())
@@ -664,6 +718,9 @@ class Socket implements java.io.Closeable {
}
private void checkAddress (InetAddress addr, String op) {
+ if (WispEngine.transparentWispSwitch()) {
+ throw new UnsupportedOperationException();
+ }
if (addr == null) {
return;
}
@@ -676,20 +733,29 @@ class Socket implements java.io.Closeable {
* set the flags after an accept() call.
*/
final void postAccept() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
connected = true;
created = true;
bound = true;
}
void setCreated() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
created = true;
}
void setBound() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
bound = true;
}
void setConnected() {
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
connected = true;
}
@@ -704,6 +770,9 @@ class Socket implements java.io.Closeable {
* or {@code null} if the socket is not connected.
*/
public InetAddress getInetAddress() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getInetAddress();
+
if (!isConnected())
return null;
try {
@@ -729,6 +798,9 @@ class Socket implements java.io.Closeable {
* @see SecurityManager#checkConnect
*/
public InetAddress getLocalAddress() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getLocalAddress();
+
// This is for backward compatibility
if (!isBound())
return InetAddress.anyLocalAddress();
@@ -760,6 +832,9 @@ class Socket implements java.io.Closeable {
* 0 if the socket is not connected yet.
*/
public int getPort() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getPort();
+
if (!isConnected())
return 0;
try {
@@ -781,6 +856,9 @@ class Socket implements java.io.Closeable {
* if the socket is not bound yet.
*/
public int getLocalPort() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getLocalPort();
+
if (!isBound())
return -1;
try {
@@ -868,6 +946,9 @@ class Socket implements java.io.Closeable {
* @spec JSR-51
*/
public SocketChannel getChannel() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getChannel();
+
return null;
}
@@ -917,6 +998,9 @@ class Socket implements java.io.Closeable {
* @spec JSR-51
*/
public InputStream getInputStream() throws IOException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getInputStream();
+
if (isClosed())
throw new SocketException("Socket is closed");
if (!isConnected())
@@ -957,6 +1041,9 @@ class Socket implements java.io.Closeable {
* @spec JSR-51
*/
public OutputStream getOutputStream() throws IOException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getOutputStream();
+
if (isClosed())
throw new SocketException("Socket is closed");
if (!isConnected())
@@ -993,6 +1080,10 @@ class Socket implements java.io.Closeable {
* @see #getTcpNoDelay()
*/
public void setTcpNoDelay(boolean on) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setTcpNoDelay(on);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
@@ -1009,6 +1100,9 @@ class Socket implements java.io.Closeable {
* @see #setTcpNoDelay(boolean)
*/
public boolean getTcpNoDelay() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getTcpNoDelay();
+
if (isClosed())
throw new SocketException("Socket is closed");
return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue();
@@ -1030,6 +1124,10 @@ class Socket implements java.io.Closeable {
* @see #getSoLinger()
*/
public void setSoLinger(boolean on, int linger) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setSoLinger(on, linger);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
if (!on) {
@@ -1058,6 +1156,9 @@ class Socket implements java.io.Closeable {
* @see #setSoLinger(boolean, int)
*/
public int getSoLinger() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getSoLinger();
+
if (isClosed())
throw new SocketException("Socket is closed");
Object o = getImpl().getOption(SocketOptions.SO_LINGER);
@@ -1079,6 +1180,10 @@ class Socket implements java.io.Closeable {
* @since 1.4
*/
public void sendUrgentData (int data) throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.sendUrgentData(data);
+ return;
+ }
if (!getImpl().supportsUrgentData ()) {
throw new SocketException ("Urgent data not supported");
}
@@ -1111,6 +1216,10 @@ class Socket implements java.io.Closeable {
* @see #getOOBInline()
*/
public void setOOBInline(boolean on) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setOOBInline(on);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
@@ -1128,6 +1237,9 @@ class Socket implements java.io.Closeable {
* @see #setOOBInline(boolean)
*/
public boolean getOOBInline() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getOOBInline();
+
if (isClosed())
throw new SocketException("Socket is closed");
return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue();
@@ -1153,6 +1265,10 @@ class Socket implements java.io.Closeable {
public synchronized void setSoTimeout(int timeout) throws SocketException {
if (isClosed())
throw new SocketException("Socket is closed");
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setSoTimeout(timeout);
+ return;
+ }
if (timeout < 0)
throw new IllegalArgumentException("timeout can't be negative");
@@ -1173,6 +1289,8 @@ class Socket implements java.io.Closeable {
public synchronized int getSoTimeout() throws SocketException {
if (isClosed())
throw new SocketException("Socket is closed");
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getSoTimeout();
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
/* extra type safety */
if (o instanceof Integer) {
@@ -1207,6 +1325,10 @@ class Socket implements java.io.Closeable {
*/
public synchronized void setSendBufferSize(int size)
throws SocketException{
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setSendBufferSize(size);
+ return;
+ }
if (!(size > 0)) {
throw new IllegalArgumentException("negative send size");
}
@@ -1229,6 +1351,9 @@ class Socket implements java.io.Closeable {
* @since 1.2
*/
public synchronized int getSendBufferSize() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getSendBufferSize();
+
if (isClosed())
throw new SocketException("Socket is closed");
int result = 0;
@@ -1281,6 +1406,10 @@ class Socket implements java.io.Closeable {
*/
public synchronized void setReceiveBufferSize(int size)
throws SocketException{
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setReceiveBufferSize(size);
+ return;
+ }
if (size <= 0) {
throw new IllegalArgumentException("invalid receive size");
}
@@ -1303,6 +1432,9 @@ class Socket implements java.io.Closeable {
*/
public synchronized int getReceiveBufferSize()
throws SocketException{
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getReceiveBufferSize();
+
if (isClosed())
throw new SocketException("Socket is closed");
int result = 0;
@@ -1323,6 +1455,10 @@ class Socket implements java.io.Closeable {
* @see #getKeepAlive()
*/
public void setKeepAlive(boolean on) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setKeepAlive(on);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
@@ -1339,6 +1475,9 @@ class Socket implements java.io.Closeable {
* @see #setKeepAlive(boolean)
*/
public boolean getKeepAlive() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getKeepAlive();
+
if (isClosed())
throw new SocketException("Socket is closed");
return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue();
@@ -1391,6 +1530,10 @@ class Socket implements java.io.Closeable {
* @see SocketOptions#IP_TOS
*/
public void setTrafficClass(int tc) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setTrafficClass(tc);
+ return;
+ }
if (tc < 0 || tc > 255)
throw new IllegalArgumentException("tc is not in range 0 -- 255");
@@ -1423,6 +1566,9 @@ class Socket implements java.io.Closeable {
* @see SocketOptions#IP_TOS
*/
public int getTrafficClass() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getTrafficClass();
+
return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();
}
@@ -1462,6 +1608,10 @@ class Socket implements java.io.Closeable {
* @see #isBound()
*/
public void setReuseAddress(boolean on) throws SocketException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.setReuseAddress(on);
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
@@ -1478,6 +1628,9 @@ class Socket implements java.io.Closeable {
* @see #setReuseAddress(boolean)
*/
public boolean getReuseAddress() throws SocketException {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.getReuseAddress();
+
if (isClosed())
throw new SocketException("Socket is closed");
return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
@@ -1506,6 +1659,10 @@ class Socket implements java.io.Closeable {
* @see #isClosed
*/
public synchronized void close() throws IOException {
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.close();
+ return;
+ }
synchronized(closeLock) {
if (isClosed())
return;
@@ -1535,6 +1692,10 @@ class Socket implements java.io.Closeable {
*/
public void shutdownInput() throws IOException
{
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.shutdownInput();
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
if (!isConnected())
@@ -1565,6 +1726,10 @@ class Socket implements java.io.Closeable {
*/
public void shutdownOutput() throws IOException
{
+ if (WispEngine.transparentWispSwitch()) {
+ asyncImpl.shutdownOutput();
+ return;
+ }
if (isClosed())
throw new SocketException("Socket is closed");
if (!isConnected())
@@ -1581,6 +1746,9 @@ class Socket implements java.io.Closeable {
* @return a string representation of this socket.
*/
public String toString() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.toString();
+
try {
if (isConnected())
return "Socket[addr=" + getImpl().getInetAddress() +
@@ -1603,6 +1771,9 @@ class Socket implements java.io.Closeable {
* @since 1.4
*/
public boolean isConnected() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.isConnected();
+
// Before 1.3 Sockets were always connected during creation
return connected || oldImpl;
}
@@ -1620,6 +1791,9 @@ class Socket implements java.io.Closeable {
* @see #bind
*/
public boolean isBound() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.isBound();
+
// Before 1.3 Sockets were always bound during creation
return bound || oldImpl;
}
@@ -1632,6 +1806,9 @@ class Socket implements java.io.Closeable {
* @see #close
*/
public boolean isClosed() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.isClosed();
+
synchronized(closeLock) {
return closed;
}
@@ -1645,6 +1822,9 @@ class Socket implements java.io.Closeable {
* @see #shutdownInput
*/
public boolean isInputShutdown() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.isInputShutdown();
+
return shutIn;
}
@@ -1656,6 +1836,9 @@ class Socket implements java.io.Closeable {
* @see #shutdownOutput
*/
public boolean isOutputShutdown() {
+ if (WispEngine.transparentWispSwitch())
+ return asyncImpl.isOutputShutdown();
+
return shutOut;
}
@@ -1691,6 +1874,9 @@ class Socket implements java.io.Closeable {
public static synchronized void setSocketImplFactory(SocketImplFactory fac)
throws IOException
{
+ if (WispEngine.transparentWispSwitch())
+ throw new UnsupportedOperationException();
+
if (factory != null) {
throw new SocketException("factory already defined");
}
diff --git a/src/share/classes/java/nio/channels/Selector.java b/src/share/classes/java/nio/channels/Selector.java
index ea72acb6400b7e748ffc6db78f75ac645d2f9073..620a46c8711c0e523c77f8d93a2de30d4657f5cf 100644
--- a/src/share/classes/java/nio/channels/Selector.java
+++ b/src/share/classes/java/nio/channels/Selector.java
@@ -25,6 +25,8 @@
package java.nio.channels;
+import com.alibaba.wisp.engine.WispEngine;
+
import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.spi.SelectorProvider;
diff --git a/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java
index 73d3da049ec22c69a41fc5cd3a379c541a72f65a..080517d9bc8fd75dc5b8df8a5973c1f028649eae 100644
--- a/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java
+++ b/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java
@@ -154,6 +154,10 @@ public class LinkedBlockingDeque
/** Maximum number of items in the deque */
private final int capacity;
+ int getCapacity() {
+ return capacity;
+ }
+
/** Main lock guarding all access */
final ReentrantLock lock = new ReentrantLock();
diff --git a/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java b/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java
index d7a1587146af4da123ea5dc5b995c9d0b7b225ec..281ead2ec9e82e9b02809f2f5e13702d7cc107ee 100644
--- a/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java
+++ b/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java
@@ -136,6 +136,10 @@ public class LinkedBlockingQueue extends AbstractQueue
/** The capacity bound, or Integer.MAX_VALUE if none */
private final int capacity;
+ int getCapacity() {
+ return capacity;
+ }
+
/** Current number of elements */
private final AtomicInteger count = new AtomicInteger();
diff --git a/src/share/classes/java/util/concurrent/SynchronousQueue.java b/src/share/classes/java/util/concurrent/SynchronousQueue.java
index fdc42f926eece574cc28b2126ae9b53426f37c1a..bad8e59869a11e461d95fd781161c02e407deee5 100644
--- a/src/share/classes/java/util/concurrent/SynchronousQueue.java
+++ b/src/share/classes/java/util/concurrent/SynchronousQueue.java
@@ -35,6 +35,10 @@
*/
package java.util.concurrent;
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.*;
@@ -85,6 +89,8 @@ public class SynchronousQueue extends AbstractQueue
implements BlockingQueue, java.io.Serializable {
private static final long serialVersionUID = -3223113410248163686L;
+ private static WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
+
/*
* This class implements extensions of the dual stack and dual
* queue algorithms described in "Nonblocking Concurrent Objects
@@ -456,7 +462,8 @@ public class SynchronousQueue extends AbstractQueue
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
LockSupport.park(this);
- else if (nanos > spinForTimeoutThreshold)
+ else if (nanos > spinForTimeoutThreshold ||
+ WispEngine.transparentWispSwitch() && WEA.hasMoreTasks())
LockSupport.parkNanos(this, nanos);
}
}
@@ -466,6 +473,9 @@ public class SynchronousQueue extends AbstractQueue
* fulfiller.
*/
boolean shouldSpin(SNode s) {
+ if (WispEngine.transparentWispSwitch() && WEA.hasMoreTasks()) {
+ return false;
+ }
SNode h = head;
return (h == s || h == null || isFulfilling(h.mode));
}
@@ -760,7 +770,8 @@ public class SynchronousQueue extends AbstractQueue
s.waiter = w;
else if (!timed)
LockSupport.park(this);
- else if (nanos > spinForTimeoutThreshold)
+ else if (nanos > spinForTimeoutThreshold ||
+ WispEngine.transparentWispSwitch() && WEA.hasMoreTasks())
LockSupport.parkNanos(this, nanos);
}
}
diff --git a/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index dce35765df71e053f579f7d87f9b9f61cff42aef..db2c8b1b707fd6c4e0fadab46c99e80b90544157 100644
--- a/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -38,7 +38,11 @@ import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
import sun.misc.Unsafe;
+import sun.misc.WispEngineAccess;
/**
* Provides a framework for implementing blocking locks and related
@@ -292,6 +296,8 @@ public abstract class AbstractQueuedSynchronizer
private static final long serialVersionUID = 7373984972572414691L;
+ private static WispEngineAccess WA = SharedSecrets.getWispEngineAccess();
+
/**
* Creates a new {@code AbstractQueuedSynchronizer} instance
* with initial synchronization state of zero.
@@ -930,7 +936,8 @@ public abstract class AbstractQueuedSynchronizer
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > spinForTimeoutThreshold)
+ (nanosTimeout > spinForTimeoutThreshold ||
+ WispEngine.transparentWispSwitch() && WA.hasMoreTasks()))
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
@@ -1033,7 +1040,8 @@ public abstract class AbstractQueuedSynchronizer
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > spinForTimeoutThreshold)
+ (nanosTimeout > spinForTimeoutThreshold ||
+ WispEngine.transparentWispSwitch() && WA.hasMoreTasks()))
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
@@ -2074,7 +2082,8 @@ public abstract class AbstractQueuedSynchronizer
transferAfterCancelledWait(node);
break;
}
- if (nanosTimeout >= spinForTimeoutThreshold)
+ if (nanosTimeout >= spinForTimeoutThreshold ||
+ WispEngine.transparentWispSwitch() && WA.hasMoreTasks())
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
@@ -2159,7 +2168,8 @@ public abstract class AbstractQueuedSynchronizer
timedout = transferAfterCancelledWait(node);
break;
}
- if (nanosTimeout >= spinForTimeoutThreshold)
+ if (nanosTimeout >= spinForTimeoutThreshold ||
+ WispEngine.transparentWispSwitch() && WA.hasMoreTasks())
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
diff --git a/src/share/classes/java/util/concurrent/locks/LockSupport.java b/src/share/classes/java/util/concurrent/locks/LockSupport.java
index 46a0ab597c87d17ace150c256bcdc58f1e6e3051..17f0409f2ffe3ac1213fd516521697a4c324e74b 100644
--- a/src/share/classes/java/util/concurrent/locks/LockSupport.java
+++ b/src/share/classes/java/util/concurrent/locks/LockSupport.java
@@ -34,6 +34,7 @@
*/
package java.util.concurrent.locks;
+
import sun.misc.Unsafe;
/**
diff --git a/src/share/classes/sun/management/ManagementFactoryHelper.java b/src/share/classes/sun/management/ManagementFactoryHelper.java
index 30dcc41ccc103349b0beee570bf546b87aeb5b0d..40a0d6325797a9001c4570ae1eb4f9d3cdca7a16 100644
--- a/src/share/classes/sun/management/ManagementFactoryHelper.java
+++ b/src/share/classes/sun/management/ManagementFactoryHelper.java
@@ -41,8 +41,10 @@ import java.security.PrivilegedExceptionAction;
import com.alibaba.management.TenantContainerMXBean;
import com.alibaba.management.ElasticHeapMXBean;
+import com.alibaba.management.WispCounterMXBean;
import com.alibaba.tenant.TenantContainerMXBeanImpl;
import com.alibaba.jvm.gc.ElasticHeapMXBeanImpl;
+import com.alibaba.wisp.engine.WispCounterMXBeanImpl;
import sun.util.logging.LoggingSupport;
import java.util.ArrayList;
@@ -71,6 +73,7 @@ public class ManagementFactoryHelper {
private static OperatingSystemImpl osMBean = null;
private static TenantContainerMXBeanImpl tenantContainerMBean = null;
private static ElasticHeapMXBeanImpl elasticHeapMXBean = null;
+ private static WispCounterMXBeanImpl wispCounterMBean = null;
public static synchronized ClassLoadingMXBean getClassLoadingMXBean() {
if (classMBean == null) {
@@ -128,6 +131,13 @@ public class ManagementFactoryHelper {
return elasticHeapMXBean;
}
+ public static synchronized WispCounterMXBean getWispCounterMXBean() {
+ if (wispCounterMBean == null) {
+ wispCounterMBean = new WispCounterMXBeanImpl();
+ }
+ return wispCounterMBean;
+ }
+
public static List getMemoryPoolMXBeans() {
MemoryPoolMXBean[] pools = MemoryImpl.getMemoryPools();
List list = new ArrayList<>(pools.length);
diff --git a/src/share/classes/sun/misc/JavaLangAccess.java b/src/share/classes/sun/misc/JavaLangAccess.java
index 04494e668f89c6eddd084b2c5c831a222eea48a2..8f26f843d12e85a0d62c6b6a18f67e5146055cbe 100644
--- a/src/share/classes/sun/misc/JavaLangAccess.java
+++ b/src/share/classes/sun/misc/JavaLangAccess.java
@@ -31,6 +31,8 @@ import java.security.AccessControlContext;
import java.util.Map;
import com.alibaba.rcm.internal.AbstractResourceContainer;
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
import sun.reflect.ConstantPool;
import sun.reflect.annotation.AnnotationType;
import sun.nio.ch.Interruptible;
@@ -150,4 +152,23 @@ public interface JavaLangAccess {
* Get the reference to the thread's inherited {@code ResourceContainer}
*/
AbstractResourceContainer getInheritedResourceContainer(Thread thread);
+
+ /**
+ * Returns a reference to the currently executing thread object.
+ */
+ Thread currentThread0();
+
+ void yield0();
+
+ void setWispTask(Thread thread, WispTask task);
+
+ WispTask getWispTask(Thread thread);
+
+ void setWispAlive(Thread thread, boolean b);
+
+ boolean isInSameNative(Thread thread);
+
+ void threadExit(Thread thread);
+
+ void wispBooted();
}
diff --git a/src/share/classes/sun/misc/SharedSecrets.java b/src/share/classes/sun/misc/SharedSecrets.java
index e266fbf3e7b1be8c4e172617ea862792811cdc71..2afc945ef1aabed62a8be06eac0d8a942884a200 100644
--- a/src/share/classes/sun/misc/SharedSecrets.java
+++ b/src/share/classes/sun/misc/SharedSecrets.java
@@ -26,6 +26,9 @@
package sun.misc;
import javax.crypto.SealedObject;
+
+import sun.nio.ch.IOEventAccess;
+
import java.util.jar.JarFile;
import java.io.Console;
import java.io.FileDescriptor;
@@ -64,6 +67,8 @@ public class SharedSecrets {
private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
private static TenantAccess tenantAccess;
private static JavaSecuritySignatureAccess javaSecuritySignatureAccess;
+ private static WispEngineAccess wispEngineAccess;
+ private static IOEventAccess ioEventAccess;
public static JavaUtilJarAccess javaUtilJarAccess() {
if (javaUtilJarAccess == null) {
@@ -257,4 +262,27 @@ public class SharedSecrets {
public static TenantAccess getTenantAccess() {
return tenantAccess;
}
+
+ public static WispEngineAccess getWispEngineAccess() {
+ return wispEngineAccess;
+ }
+
+ public static void setWispEngineAccess(WispEngineAccess wispEngineAccess) {
+ SharedSecrets.wispEngineAccess = wispEngineAccess;
+ }
+
+ public static UnsafeAccess getUnsafeAccess() {
+ return Unsafe.access;
+ }
+
+ public static IOEventAccess getIOEventAccess() {
+ if (ioEventAccess == null) {
+ IOEventAccess.initializeEvent();
+ }
+ return ioEventAccess;
+ }
+
+ public static void setIOEventAccess(IOEventAccess ioEventAccess) {
+ SharedSecrets.ioEventAccess = ioEventAccess;
+ }
}
diff --git a/src/share/classes/sun/misc/Unsafe.java b/src/share/classes/sun/misc/Unsafe.java
index 99e4658029c3d23c0d38bb7248ad55d5539d3da5..fd6bc7f43c66742e241ac2dfbbc5f069494d8afe 100644
--- a/src/share/classes/sun/misc/Unsafe.java
+++ b/src/share/classes/sun/misc/Unsafe.java
@@ -28,6 +28,7 @@ package sun.misc;
import java.security.*;
import java.lang.reflect.*;
+import com.alibaba.wisp.engine.WispEngine;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -53,6 +54,18 @@ public final class Unsafe {
private static final Unsafe theUnsafe = new Unsafe();
+ static final UnsafeAccess access = new UnsafeAccess() {
+ @Override
+ public void unpark0(Object thread) {
+ theUnsafe.unpark0(thread);
+ }
+
+ @Override
+ public void park0(boolean isAbsolute, long time) {
+ theUnsafe.park0(isAbsolute, time);
+ }
+ };
+
/**
* Provides the caller with the capability of performing unsafe
* operations.
@@ -971,7 +984,7 @@ public final class Unsafe {
public native void putOrderedLong(Object o, long offset, long x);
/**
- * Unblock the given thread blocked on park , or, if it is
+ * Unblock the given thread(or coroutine) blocked on park , or, if it is
* not blocked, cause the subsequent call to park not to
* block. Note: this operation is "unsafe" solely because the
* caller must somehow ensure that the thread has not been
@@ -982,10 +995,25 @@ public final class Unsafe {
* @param thread the thread to unpark.
*
*/
- public native void unpark(Object thread);
+ public void unpark(Object thread) {
+ if (WispEngine.transparentWispSwitch()) {
+ if (thread instanceof Thread) {
+ SharedSecrets.getWispEngineAccess().unpark(
+ SharedSecrets.getJavaLangAccess().getWispTask((Thread) thread));
+ }
+ return;
+ }
+ unpark0(thread);
+ }
/**
- * Block current thread, returning when a balancing
+ * Unblock the given thread. Always use the thread semantic.
+ * @param thread
+ */
+ private native void unpark0(Object thread);
+
+ /**
+ * Block current thread(or coroutine), returning when a balancing
* unpark occurs, or a balancing unpark has
* already occurred, or the thread is interrupted, or, if not
* absolute and time is not zero, the given time nanoseconds have
@@ -995,7 +1023,25 @@ public final class Unsafe {
* because unpark is, so it would be strange to place it
* elsewhere.
*/
- public native void park(boolean isAbsolute, long time);
+ public void park(boolean isAbsolute, long time) {
+ if (WispEngine.transparentWispSwitch()) {
+ if (time <= 0) { // non-timeouted park
+ SharedSecrets.getWispEngineAccess().park(0);
+ }
+ long timeout = !isAbsolute ? time:
+ java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(time - System.currentTimeMillis());
+ if (timeout > 0) {
+ SharedSecrets.getWispEngineAccess().park(timeout);
+ }
+ return;
+ }
+ park0(isAbsolute, time);
+ }
+
+ /**
+ * Block current thread. Always use the thread semantic.
+ */
+ private native void park0(boolean isAbsolute, long time);
/**
* Gets the load average in the system run queue assigned
diff --git a/src/share/classes/sun/misc/UnsafeAccess.java b/src/share/classes/sun/misc/UnsafeAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca66a18b60671bf6ec41556b91c13784a3872761
--- /dev/null
+++ b/src/share/classes/sun/misc/UnsafeAccess.java
@@ -0,0 +1,7 @@
+package sun.misc;
+
+public interface UnsafeAccess {
+ void unpark0(Object thread);
+
+ void park0(boolean isAbsolute, long time);
+}
diff --git a/src/share/classes/sun/misc/VM.java b/src/share/classes/sun/misc/VM.java
index 2e2c1cc492f86cdfbef90fa545c8f970fe98c2f1..5b5fbd98d763094a995e6519fc05b644739fbf84 100644
--- a/src/share/classes/sun/misc/VM.java
+++ b/src/share/classes/sun/misc/VM.java
@@ -410,6 +410,7 @@ public class VM {
private final static int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010;
private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020;
+
/*
* Returns first non-privileged class loader on the stack (excluding
* reflection generated frames) or the extension class loader if only
diff --git a/src/share/classes/sun/misc/WispEngineAccess.java b/src/share/classes/sun/misc/WispEngineAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..41fbb5ac46d35d40b022d41cf52022d50525b3e2
--- /dev/null
+++ b/src/share/classes/sun/misc/WispEngineAccess.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.misc;
+
+
+import com.alibaba.wisp.engine.WispTask;
+
+import java.io.IOException;
+import java.nio.channels.SelectableChannel;
+import java.util.concurrent.atomic.AtomicReference;
+
+public interface WispEngineAccess {
+
+ WispTask getCurrentTask();
+
+ void registerEvent(SelectableChannel ch, int events) throws IOException;
+
+ void unregisterEvent();
+
+ int epollWait(int epfd, long pollArray, int arraySize, long timeout,
+ AtomicReference status, final Object INTERRUPTED) throws IOException;
+
+ void interruptEpoll(AtomicReference status, Object INTERRUPTED, int interruptFD);
+
+ void addTimer(long deadlineNano);
+
+ void cancelTimer();
+
+ void sleep(long ms);
+
+ void yield();
+
+ boolean isThreadTask(WispTask task);
+
+ boolean isTimeout();
+
+ void park(long timeoutNanos);
+
+ void unpark(WispTask task);
+
+ void destroy();
+
+ boolean isAlive(WispTask task);
+
+ void interrupt(WispTask task);
+
+ boolean testInterruptedAndClear(WispTask task, boolean clear);
+
+ boolean hasMoreTasks();
+
+ boolean runningAsCoroutine(Thread t);
+
+ boolean usingWispEpoll();
+
+ boolean isAllThreadAsWisp();
+
+ boolean tryStartThreadAsWisp(Thread thread, Runnable target);
+
+ boolean useDirectSelectorWakeup();
+
+ boolean enableSocketLock();
+
+ StackTraceElement[] getStackTrace(WispTask task);
+}
diff --git a/src/share/classes/sun/nio/ch/IOEventAccess.java b/src/share/classes/sun/nio/ch/IOEventAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f7358c04670cbccc5c14537aa75de459c21b7b0
--- /dev/null
+++ b/src/share/classes/sun/nio/ch/IOEventAccess.java
@@ -0,0 +1,47 @@
+package sun.nio.ch;
+
+import sun.misc.Unsafe;
+
+import java.io.IOException;
+
+public interface IOEventAccess {
+
+ int eventCtlAdd();
+
+ int eventCtlDel();
+
+ int eventCtlMod();
+
+ int eventOneShot();
+
+ int noEvent();
+
+ long allocatePollArray(int count);
+
+ void freePollArray(long address);
+
+ long getEvent(long address, int i);
+
+ int getDescriptor(long eventAddress);
+
+ int getEvents(long eventAddress);
+
+ int eventCreate() throws IOException;
+
+ int eventCtl(int epfd, int opcode, int fd, int events);
+
+ int eventWait(int epfd, long pollAddress, int numfds, int timeout) throws IOException;
+
+ void socketpair(int[] sv) throws IOException;
+
+ void interrupt(int fd) throws IOException;
+
+ void drain(int fd) throws IOException;
+
+ void close(int fd);
+
+ static void initializeEvent() {
+ Unsafe.getUnsafe().ensureClassInitialized(IOEvent.eventClass());
+ }
+
+}
\ No newline at end of file
diff --git a/src/share/classes/sun/nio/ch/SelectionKeyImpl.java b/src/share/classes/sun/nio/ch/SelectionKeyImpl.java
index 28102d78fcf07ac37df49b8fd39ee9fb446c3361..8e6c2e1caec18ca67eac1188b9495ce6ff93aeda 100644
--- a/src/share/classes/sun/nio/ch/SelectionKeyImpl.java
+++ b/src/share/classes/sun/nio/ch/SelectionKeyImpl.java
@@ -46,6 +46,7 @@ public class SelectionKeyImpl
private volatile int interestOps;
private int readyOps;
+ public int wispOps; // pass argument, access by WispSelector
SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) {
channel = ch;
@@ -102,6 +103,7 @@ public class SelectionKeyImpl
public SelectionKey nioInterestOps(int ops) {
if ((ops & ~channel().validOps()) != 0)
throw new IllegalArgumentException();
+ wispOps = ops; // read by WispSelector.putEventOps
channel.translateAndSetInterestOps(ops, this);
interestOps = ops;
return this;
diff --git a/src/share/classes/sun/nio/ch/SelectorImpl.java b/src/share/classes/sun/nio/ch/SelectorImpl.java
index db8ce1fd0e1d0aadf479e5ce2fd0a8ea42e4cdea..1bb692f9f0749e47153dee35bead78e56f6cae7b 100644
--- a/src/share/classes/sun/nio/ch/SelectorImpl.java
+++ b/src/share/classes/sun/nio/ch/SelectorImpl.java
@@ -141,17 +141,28 @@ public abstract class SelectorImpl
// Precondition: Synchronized on this, keys, and selectedKeys
Set cks = cancelledKeys();
synchronized (cks) {
+ if (cks.isEmpty()) {
+ return;
+ }
+ cks = new HashSet<>(cks);
+ cancelledKeys().clear();
+ }
+ try { // now cks is a thread local copy
+ Iterator i = cks.iterator();
+ while (i.hasNext()) {
+ SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
+ try {
+ implDereg(ski);
+ } catch (SocketException se) {
+ throw new IOException("Error deregistering key", se);
+ } finally {
+ i.remove();
+ }
+ }
+ } finally {
if (!cks.isEmpty()) {
- Iterator i = cks.iterator();
- while (i.hasNext()) {
- SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
- try {
- implDereg(ski);
- } catch (SocketException se) {
- throw new IOException("Error deregistering key", se);
- } finally {
- i.remove();
- }
+ synchronized (cancelledKeys()) {
+ cancelledKeys().addAll(cks);
}
}
}
diff --git a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
index 563f948cf924bc804e248c06a1182cb7b0f66138..292cbfb6db4153e2304b23b35fdca15b7deec6d6 100644
--- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
@@ -31,6 +31,10 @@ import java.net.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
import sun.net.NetHooks;
@@ -42,6 +46,7 @@ class ServerSocketChannelImpl
extends ServerSocketChannel
implements SelChImpl
{
+ private static final WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
// Used to make native close and configure calls
private static NativeDispatcher nd;
@@ -238,18 +243,31 @@ class ServerSocketChannelImpl
FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1];
+ final boolean wispAndBlocking = WispEngine.transparentWispSwitch() && isBlocking() &&
+ WEA.usingWispEpoll();
try {
begin();
if (!isOpen())
return null;
thread = NativeThread.current();
+ if (wispAndBlocking) {
+ IOUtil.configureBlocking(fd, false);
+ }
for (;;) {
n = accept(this.fd, newfd, isaa);
if ((n == IOStatus.INTERRUPTED) && isOpen())
continue;
+ if (wispAndBlocking && n < 0) {
+ WEA.registerEvent(this, SelectionKey.OP_ACCEPT);
+ WEA.park(-1);
+ continue;
+ }
break;
}
} finally {
+ if (wispAndBlocking) {
+ IOUtil.configureBlocking(fd, true);
+ }
thread = 0;
end(n > 0);
assert IOStatus.check(n);
diff --git a/src/share/demo/jvmti/java_crw_demo/java_crw_demo.c b/src/share/demo/jvmti/java_crw_demo/java_crw_demo.c
index eaa271e9e189b09cd61055a2e4dc1e25f2e1d02f..27cee0fabe41efd027b5a3b0b2ed5d9cf7dd3f4b 100644
--- a/src/share/demo/jvmti/java_crw_demo/java_crw_demo.c
+++ b/src/share/demo/jvmti/java_crw_demo/java_crw_demo.c
@@ -2032,6 +2032,14 @@ skip_method(CrwClassImage *ci, const char *name,
unsigned access_flags, ByteOffset code_len,
int system_class, jboolean *pskip_call_return_sites)
{
+ if (strcmp(name,"currentThread0") == 0 ||
+ strcmp(name,"getJavaLangAccess") == 0) {
+ /*
+ * bypass here otherwise the jdk/test/demo/jvmti/hprof/ tests will fail
+ * caused by the change to the Thread.currentThread() in co-routine feature
+ */
+ return JNI_TRUE;
+ }
*pskip_call_return_sites = JNI_FALSE;
if ( system_class ) {
if ( code_len == 1 && is_init_method(name) ) {
diff --git a/src/share/javavm/export/jvm.h b/src/share/javavm/export/jvm.h
index cfcc5d509a093655f9b88fd9fab5da87160be4a9..27dd064b6c100d66f5fa4f4e8e4f7de303c0ca2d 100644
--- a/src/share/javavm/export/jvm.h
+++ b/src/share/javavm/export/jvm.h
@@ -268,6 +268,9 @@ JVM_Interrupt(JNIEnv *env, jobject thread);
JNIEXPORT jboolean JNICALL
JVM_IsInterrupted(JNIEnv *env, jobject thread, jboolean clearInterrupted);
+JNIEXPORT jboolean JNICALL
+JVM_CheckAndClearNativeInterruptForWisp(JNIEnv* env, jobject task, jobject jthread);
+
JNIEXPORT jboolean JNICALL
JVM_HoldsLock(JNIEnv *env, jclass threadClass, jobject obj);
@@ -280,6 +283,9 @@ JVM_GetAllThreads(JNIEnv *env, jclass dummy);
JNIEXPORT void JNICALL
JVM_SetNativeThreadName(JNIEnv *env, jobject jthread, jstring name);
+JNIEXPORT jboolean JNICALL
+JVM_IsInSameNative(JNIEnv *env, jobject thread);
+
/* getStackTrace() and getAllStackTraces() method */
JNIEXPORT jobjectArray JNICALL
JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobjectArray threads);
@@ -342,6 +348,15 @@ JVM_CheckJWarmUpCompilationIsComplete(JNIEnv *env, jclass clz);
JNIEXPORT void JNICALL
JVM_NotifyJVMDeoptWarmUpMethods(JNIEnv* env, jclass clz);
+JNIEXPORT void JNICALL
+JVM_SetWispTask(JNIEnv* env, jclass clz, jlong coroutinePtr, jint task_id, jobject task, jobject engine);
+
+JNIEXPORT jint JNICALL
+JVM_GetProxyUnpark(JNIEnv* env, jclass clz, jintArray res);
+
+JNIEXPORT void JNICALL
+JVM_MarkPreempted(JNIEnv* env, jclass clz, jobject thread);
+
/*
* com.alibaba.management.ElasticHeapMXBean
*/
diff --git a/src/share/native/java/dyn/Coroutine.c b/src/share/native/java/dyn/Coroutine.c
new file mode 100644
index 0000000000000000000000000000000000000000..7aa8bc880d614fe96c99022e7a22e226720e3150
--- /dev/null
+++ b/src/share/native/java/dyn/Coroutine.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "jni.h"
+#include "jvm.h"
+#include "java_dyn_Coroutine.h"
+
+#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
+
+#define LANG "Ljava/lang/"
+#define OBJ LANG"Object;"
+
+static JNINativeMethod methods[] = {
+ {"setWispTask","(JI"OBJ OBJ")V", (void *)&JVM_SetWispTask},
+};
+
+JNIEXPORT void JNICALL
+Java_java_dyn_Coroutine_registerNatives(JNIEnv *env, jclass cls)
+{
+ (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
+}
diff --git a/src/share/native/java/lang/Thread.c b/src/share/native/java/lang/Thread.c
index 05be07e7724f303fd2da242071d69f671e00c8da..5d7dab917091145e41b5f40067ff2b509efc2bca 100644
--- a/src/share/native/java/lang/Thread.c
+++ b/src/share/native/java/lang/Thread.c
@@ -43,13 +43,13 @@
static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread},
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
- {"isAlive", "()Z", (void *)&JVM_IsThreadAlive},
+ {"isAlive0", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread},
{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
- {"yield", "()V", (void *)&JVM_Yield},
- {"sleep", "(J)V", (void *)&JVM_Sleep},
- {"currentThread", "()" THD, (void *)&JVM_CurrentThread},
+ {"yield0", "()V", (void *)&JVM_Yield},
+ {"sleep0", "(J)V", (void *)&JVM_Sleep},
+ {"currentThread0", "()" THD, (void *)&JVM_CurrentThread},
{"countStackFrames", "()I", (void *)&JVM_CountStackFrames},
{"interrupt0", "()V", (void *)&JVM_Interrupt},
{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
@@ -57,6 +57,7 @@ static JNINativeMethod methods[] = {
{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
+ {"isInSameNative", "()Z", (void *)&JVM_IsInSameNative},
};
#undef THD
diff --git a/src/solaris/classes/sun/nio/ch/EPoll.java b/src/solaris/classes/sun/nio/ch/EPoll.java
index bb2b9e5171fb9416eb98b1d9ef9ec0773f789345..321b1ad307434b7cfd27f40613174f8ae2a1be99 100644
--- a/src/solaris/classes/sun/nio/ch/EPoll.java
+++ b/src/solaris/classes/sun/nio/ch/EPoll.java
@@ -26,6 +26,8 @@
package sun.nio.ch;
import java.io.IOException;
+
+import sun.misc.SharedSecrets;
import sun.misc.Unsafe;
/**
@@ -62,6 +64,8 @@ class EPoll {
// flags
static final int EPOLLONESHOT = (1 << 30);
+ static final int ENOENT;
+
/**
* Allocates a poll array to handle up to {@code count} events.
*/
@@ -109,10 +113,17 @@ class EPoll {
static native int epollCtl(int epfd, int opcode, int fd, int events);
- static native int epollWait(int epfd, long pollAddress, int numfds)
+ static int epollWait(int epfd, long pollAddress, int numfds) throws IOException {
+ return epollWait(epfd, pollAddress, numfds, -1);
+ }
+
+ static native int epollWait(int epfd, long pollAddress, int numfds, int timeout)
throws IOException;
+ static native int errnoENOENT();
+
static {
IOUtil.load();
+ ENOENT = errnoENOENT();
}
}
diff --git a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java
index e6a2b584d960a2cc1eb0d19ad79485cd0af4ec63..7c82f344e8864f8337dd245cfef2b38703c33b4a 100644
--- a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java
+++ b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java
@@ -30,6 +30,13 @@ import java.security.AccessController;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
import sun.security.action.GetIntegerAction;
/**
@@ -57,6 +64,8 @@ import sun.security.action.GetIntegerAction;
*/
class EPollArrayWrapper {
+ private static final WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
+
// EPOLL_EVENTS
private static final int EPOLLIN = 0x001;
@@ -266,7 +275,9 @@ class EPollArrayWrapper {
int poll(long timeout) throws IOException {
updateRegistrations();
- updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
+ updated = WispEngine.transparentWispSwitch() ?
+ handleEPollWithWisp(timeout) :
+ epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
for (int i=0; i status = new AtomicReference<>();
+ // null: initial status
+ // INTERRUPTED: interrupted by wakeup()
+ // other: task blocking on this selector
+
+ private int handleEPollWithWisp(long timeout) throws IOException {
+ int updated = WEA.epollWait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, timeout, status, INTERRUPTED);
+ if (WEA.useDirectSelectorWakeup() && status.get() == INTERRUPTED) {
+ interrupted = true;
+ }
+ return updated;
+ }
+
/**
* Update the pending registrations.
*/
@@ -314,7 +339,11 @@ class EPollArrayWrapper {
private boolean interrupted = false;
public void interrupt() {
- interrupt(outgoingInterruptFD);
+ if (WispEngine.transparentWispSwitch() && WEA.useDirectSelectorWakeup()) {
+ WEA.interruptEpoll(status, INTERRUPTED, outgoingInterruptFD);
+ } else {
+ interrupt(outgoingInterruptFD);
+ }
}
public int interruptedIndex() {
@@ -327,6 +356,10 @@ class EPollArrayWrapper {
void clearInterrupted() {
interrupted = false;
+ if (WispEngine.transparentWispSwitch() && WEA.useDirectSelectorWakeup()) {
+ assert status.get() == INTERRUPTED;
+ status.lazySet(null);
+ }
}
static {
diff --git a/src/solaris/classes/sun/nio/ch/EPollPort.java b/src/solaris/classes/sun/nio/ch/EPollPort.java
index 651457e98df2ed7ea27efd86edc7967b62ffa203..c184593fc32c8355f1f1b7ce5179a27672f26e3e 100644
--- a/src/solaris/classes/sun/nio/ch/EPollPort.java
+++ b/src/solaris/classes/sun/nio/ch/EPollPort.java
@@ -25,6 +25,8 @@
package sun.nio.ch;
+import sun.misc.SharedSecrets;
+
import java.nio.channels.spi.AsynchronousChannelProvider;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
@@ -319,5 +321,91 @@ final class EPollPort
static {
IOUtil.load();
+ SharedSecrets.setIOEventAccess(new IOEventAccess() {
+ @Override
+ public int eventCtlAdd() {
+ return EPoll.EPOLL_CTL_ADD;
+ }
+
+ @Override
+ public int eventCtlDel() {
+ return EPoll.EPOLL_CTL_DEL;
+ }
+
+ @Override
+ public int eventCtlMod() {
+ return EPoll.EPOLL_CTL_MOD;
+ }
+
+ @Override
+ public int eventOneShot() {
+ return EPoll.EPOLLONESHOT;
+ }
+
+ @Override
+ public int noEvent() {
+ return EPoll.ENOENT;
+ }
+
+ @Override
+ public long allocatePollArray(int count) {
+ return EPoll.allocatePollArray(count);
+ }
+
+ @Override
+ public void freePollArray(long address) {
+ EPoll.freePollArray(address);
+ }
+
+ @Override
+ public long getEvent(long address, int i) {
+ return EPoll.getEvent(address, i);
+ }
+
+ @Override
+ public int getDescriptor(long eventAddress) {
+ return EPoll.getDescriptor(eventAddress);
+ }
+
+ @Override
+ public int getEvents(long eventAddress) {
+ return EPoll.getEvents(eventAddress);
+ }
+
+ @Override
+ public int eventCreate() throws IOException {
+ return EPoll.epollCreate();
+ }
+
+ @Override
+ public int eventCtl(int epfd, int opcode, int fd, int events) {
+ return EPoll.epollCtl(epfd, opcode, fd, events);
+ }
+
+ @Override
+ public int eventWait(int epfd, long pollAddress, int numfds, int timeout) throws IOException {
+ return EPoll.epollWait(epfd, pollAddress, numfds, timeout);
+ }
+
+ @Override
+ public void socketpair(int[] sv) throws IOException {
+ EPollPort.socketpair(sv);
+ }
+
+ @Override
+ public void interrupt(int fd) throws IOException {
+ EPollPort.interrupt(fd);
+ }
+
+ @Override
+ public void drain(int fd) throws IOException {
+ EPollPort.drain1(fd);
+ }
+
+ @Override
+ public void close(int fd) {
+ EPollPort.close0(fd);
+ }
+ });
}
}
diff --git a/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java b/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java
index 1528b9e16b8182864bf113235f336f6882243096..8cb800acd7a732a5bac322b6452e7fb20fb2ccbe 100644
--- a/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java
+++ b/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java
@@ -29,6 +29,8 @@ import java.io.IOException;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
+
+import com.alibaba.wisp.engine.WispEngine;
import sun.misc.*;
/**
@@ -38,6 +40,7 @@ import sun.misc.*;
class EPollSelectorImpl
extends SelectorImpl
{
+ private static final WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
// File descriptors used for interrupt
protected int fd0;
@@ -101,7 +104,12 @@ class EPollSelectorImpl
pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0);
synchronized (interruptLock) {
pollWrapper.clearInterrupted();
- IOUtil.drain(fd0);
+ if (WispEngine.transparentWispSwitch()
+ && WEA.useDirectSelectorWakeup() && WEA.isAllThreadAsWisp()) {
+ // skip
+ } else {
+ IOUtil.drain(fd0);
+ }
interruptTriggered = false;
}
}
diff --git a/src/solaris/native/sun/nio/ch/EPoll.c b/src/solaris/native/sun/nio/ch/EPoll.c
index ea9cdf4dd039a52330cc00b838c645eb13972918..7b1936c94a0e61ae6181706d6e37196607e8f741 100644
--- a/src/solaris/native/sun/nio/ch/EPoll.c
+++ b/src/solaris/native/sun/nio/ch/EPoll.c
@@ -84,12 +84,12 @@ Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd,
JNIEXPORT jint JNICALL
Java_sun_nio_ch_EPoll_epollWait(JNIEnv *env, jclass c,
- jint epfd, jlong address, jint numfds)
+ jint epfd, jlong address, jint numfds, jint timeout)
{
struct epoll_event *events = jlong_to_ptr(address);
int res;
- RESTARTABLE(epoll_wait(epfd, events, numfds, -1), res);
+ RESTARTABLE(epoll_wait(epfd, events, numfds, timeout), res);
if (res < 0) {
JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
}
@@ -101,3 +101,8 @@ Java_sun_nio_ch_EPoll_close0(JNIEnv *env, jclass c, jint epfd) {
int res;
RESTARTABLE(close(epfd), res);
}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_EPoll_errnoENOENT(JNIEnv *env, jclass this) {
+ return (jint)ENOENT;
+}
diff --git a/src/windows/classes/com/alibaba/wisp/engine/WispCounter.java b/src/windows/classes/com/alibaba/wisp/engine/WispCounter.java
new file mode 100644
index 0000000000000000000000000000000000000000..0975f673773484378f4e1eec88d918d2983a5c9e
--- /dev/null
+++ b/src/windows/classes/com/alibaba/wisp/engine/WispCounter.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+final public class WispCounter {
+
+}
diff --git a/src/windows/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java b/src/windows/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6438cc340fa97601eec5dfe5b8bbb484889b4104
--- /dev/null
+++ b/src/windows/classes/com/alibaba/wisp/engine/WispCounterMXBeanImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import com.alibaba.management.WispCounterMXBean;
+
+import javax.management.ObjectName;
+import java.util.List;
+
+public class WispCounterMXBeanImpl implements WispCounterMXBean {
+
+ @Override
+ public List getRunningStates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getSwitchCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getWaitTimeTotal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getRunningTimeTotal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getCompleteTaskCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getCreateTaskCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getParkCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getUnparkCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getLazyUnparkCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getUnparkInterruptSelectorCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getSelectableIOCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTimeOutCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getEventLoopCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getQueueLength() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getNumberOfRunningTasks() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalEnqueueTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getEnqueueCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalExecutionTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getExecutionCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalWaitSocketIOTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getWaitSocketIOCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getTotalBlockingTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public WispCounter getWispCounter(long id) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName getObjectName() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/windows/classes/com/alibaba/wisp/engine/WispEngine.java b/src/windows/classes/com/alibaba/wisp/engine/WispEngine.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd5a9354ba97ca23d891e20e8b7004f224036c27
--- /dev/null
+++ b/src/windows/classes/com/alibaba/wisp/engine/WispEngine.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.io.IOException;
+import java.nio.channels.SelectableChannel;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class WispEngine {
+
+ public static boolean transparentWispSwitch() {
+ return false;
+ }
+
+ public static boolean enableThreadAsWisp() {
+ return false;
+ }
+
+ private static void setWispEngineAccess() {
+ SharedSecrets.setWispEngineAccess(new WispEngineAccess() {
+
+ @Override
+ public WispTask getCurrentTask() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void registerEvent(SelectableChannel ch, int events) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unregisterEvent() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int epollWait(int epfd, long pollArray, int arraySize, long timeout,
+ AtomicReference status, Object INTERRUPTED) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void interruptEpoll(AtomicReference status, Object INTERRUPTED, int interruptFd) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addTimer(long deadlineNano) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void cancelTimer() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void sleep(long ms) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void yield() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isThreadTask(WispTask task) {
+ return false;
+ }
+
+ @Override
+ public boolean isTimeout() {
+ return false;
+ }
+
+ @Override
+ public void park(long timeoutNano) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unpark(WispTask task) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void destroy() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean hasMoreTasks() {
+ return false;
+ }
+
+ @Override
+ public boolean runningAsCoroutine(Thread t) {
+ return false;
+ }
+
+ @Override
+ public boolean usingWispEpoll() {
+ return false;
+ }
+
+ public boolean isAlive(WispTask task) {
+ return false;
+ }
+
+ @Override
+ public void interrupt(WispTask task) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean testInterruptedAndClear(WispTask task, boolean clear) {
+ return false;
+ }
+
+ @Override
+ public boolean tryStartThreadAsWisp(Thread thread, Runnable target) {
+ return false;
+ }
+
+ @Override
+ public boolean isAllThreadAsWisp() {
+ return false;
+ }
+
+ @Override
+ public boolean useDirectSelectorWakeup() {
+ return false;
+ }
+
+ @Override
+ public boolean enableSocketLock() {
+ return false;
+ }
+
+ @Override
+ public StackTraceElement[] getStackTrace(WispTask task) {
+ throw new UnsupportedOperationException();
+ }
+ });
+ }
+
+}
diff --git a/src/windows/classes/com/alibaba/wisp/engine/WispTask.java b/src/windows/classes/com/alibaba/wisp/engine/WispTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..40ef3fc58213f8897097718b48eebe978e613cc1
--- /dev/null
+++ b/src/windows/classes/com/alibaba/wisp/engine/WispTask.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+
+public class WispTask {
+
+ public Thread getThreadWrapper() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/windows/classes/com/alibaba/wisp/engine/WispThreadWrapper.java b/src/windows/classes/com/alibaba/wisp/engine/WispThreadWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..67999b115507afb9e8a02f1ebc7bbee356fc8677
--- /dev/null
+++ b/src/windows/classes/com/alibaba/wisp/engine/WispThreadWrapper.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package com.alibaba.wisp.engine;
+
+
+import sun.reflect.CallerSensitive;
+
+import java.dyn.CoroutineSupport;
+
+class WispThreadWrapper extends Thread {
+
+ @Override
+ public CoroutineSupport getCoroutineSupport() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void start() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ @Deprecated
+ public void destroy() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ @Deprecated
+ public int countStackFrames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ @CallerSensitive
+ public ClassLoader getContextClassLoader() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setContextClassLoader(ClassLoader cl) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public StackTraceElement[] getStackTrace() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public State getState() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/windows/classes/sun/nio/ch/IOEvent.java b/src/windows/classes/sun/nio/ch/IOEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..51db2db85782dbb1f5e11edff72073c70edb7de8
--- /dev/null
+++ b/src/windows/classes/sun/nio/ch/IOEvent.java
@@ -0,0 +1,8 @@
+package sun.nio.ch;
+
+public class IOEvent {
+
+ public static Class> eventClass() {
+ return IOEventRegister.class;
+ }
+}
\ No newline at end of file
diff --git a/src/windows/classes/sun/nio/ch/IOEventRegister.java b/src/windows/classes/sun/nio/ch/IOEventRegister.java
new file mode 100644
index 0000000000000000000000000000000000000000..06f724db98d04d20d991d0d51ad6fe9afebf6b83
--- /dev/null
+++ b/src/windows/classes/sun/nio/ch/IOEventRegister.java
@@ -0,0 +1,99 @@
+package sun.nio.ch;
+
+import sun.misc.SharedSecrets;
+
+import java.io.IOException;
+
+public class IOEventRegister {
+
+ static {
+ SharedSecrets.setIOEventAccess(new IOEventAccess() {
+
+ @Override
+ public int eventCtlAdd() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCtlDel() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCtlMod() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventOneShot() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int noEvent() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long allocatePollArray(int count) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void freePollArray(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getEvent(long address, int i) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getDescriptor(long eventAddress) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getEvents(long eventAddress) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCreate() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventCtl(int epfd, int opcode, int fd, int events) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int eventWait(int epfd, long pollAddress, int numfds, int timeout) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void socketpair(int[] sv) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void interrupt(int fd) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drain(int fd) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close(int fd) {
+ throw new UnsupportedOperationException();
+ }
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/src/windows/classes/sun/nio/ch/WispServerSocketImpl.java b/src/windows/classes/sun/nio/ch/WispServerSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6fdd26984c6197a8bcc47b30f0ba5423e88b47a
--- /dev/null
+++ b/src/windows/classes/sun/nio/ch/WispServerSocketImpl.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.ServerSocketChannel;
+
+
+public class WispServerSocketImpl
+{
+
+ public WispServerSocketImpl() {
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void bind(SocketAddress local, int backlog) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getInetAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getLocalPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Socket accept() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void close() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ServerSocketChannel getChannel() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isBound() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isClosed() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoTimeout() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/windows/classes/sun/nio/ch/WispSocketImpl.java b/src/windows/classes/sun/nio/ch/WispSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..318ad6436fe376a472c9c2dc4283a41e60c72f56
--- /dev/null
+++ b/src/windows/classes/sun/nio/ch/WispSocketImpl.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+
+
+public class WispSocketImpl
+{
+
+ public WispSocketImpl(Socket so) {
+ throw new UnsupportedOperationException();
+ }
+
+ public WispSocketImpl(SocketChannel sc, Socket so) {
+ throw new UnsupportedOperationException();
+ }
+
+ public SocketChannel getChannel() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(SocketAddress remote) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(SocketAddress remote, int timeout) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getInetAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getLocalAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getLocalPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getTcpNoDelay() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoLinger(boolean on, int linger) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoLinger() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void sendUrgentData(int data) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setOOBInline(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getOOBInline() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoTimeout() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setKeepAlive(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getKeepAlive() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getTrafficClass() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void close() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void shutdownInput() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void shutdownOutput() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isConnected() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isBound() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isClosed() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isInputShutdown() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isOutputShutdown() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/windows/classes/sun/nio/ch/WispSocketLockSupport.java b/src/windows/classes/sun/nio/ch/WispSocketLockSupport.java
new file mode 100644
index 0000000000000000000000000000000000000000..62373f0c88135b99343803d7189288fc920bb27e
--- /dev/null
+++ b/src/windows/classes/sun/nio/ch/WispSocketLockSupport.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+class WispSocketLockSupport {
+
+}
diff --git a/src/windows/classes/sun/nio/ch/WispUdpSocketImpl.java b/src/windows/classes/sun/nio/ch/WispUdpSocketImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3d5f79fd9d5b1ba4f7b460eab9729fb2c2b0f5e
--- /dev/null
+++ b/src/windows/classes/sun/nio/ch/WispUdpSocketImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.DatagramChannel;
+
+
+// Make a udp socket channel look like a datagram socket.
+
+public class WispUdpSocketImpl {
+
+ public WispUdpSocketImpl(DatagramSocket so) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void bind(SocketAddress local) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(InetAddress address, int port) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void connect(SocketAddress remote) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void disconnect() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isBound() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isConnected() {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getInetAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void send(DatagramPacket p) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ private SocketAddress receive(ByteBuffer bb) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int receive(DatagramPacket p, int bufLen) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public InetAddress getLocalAddress() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getLocalPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSoTimeout() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setBroadcast(boolean on) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getBroadcast() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getTrafficClass() throws SocketException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void close() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isClosed() {
+ throw new UnsupportedOperationException();
+ }
+
+ public DatagramChannel getChannel() {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/test/com/alibaba/management/WispCounterMXBean/TestWispCounter.java b/test/com/alibaba/management/WispCounterMXBean/TestWispCounter.java
new file mode 100644
index 0000000000000000000000000000000000000000..1828b6756029f6091dc51e2dd5d76f590d341d5d
--- /dev/null
+++ b/test/com/alibaba/management/WispCounterMXBean/TestWispCounter.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+import com.alibaba.management.WispCounterMXBean;
+
+import javax.management.MBeanServer;
+import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+/* @test
+ * @summary WispCounterMXBean unit test
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm/timeout=2000 -XX:+UseWisp2 -Dcom.alibaba.wisp.config=/tmp/wisp.config TestWispCounter
+ */
+
+public class TestWispCounter {
+
+ public static void main(String[] args) throws Exception {
+ startNetServer();
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ WispCounterMXBean mbean = null;
+ try {
+
+ mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+ "com.alibaba.management:type=WispCounter", WispCounterMXBean.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ ExecutorService es = Executors.newFixedThreadPool(20);
+ int taskTotal = 40;
+ for (int i = 0; i < taskTotal; i++) {
+ // submit task
+ es.submit(() -> {
+ // do park/unpark
+ synchronized (TestWispCounter.class) {
+ // do sleep
+ try {
+ Thread.sleep(10L);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ // do net IO
+ doNetIO();
+ });
+ }
+
+ System.out.println(mbean.getRunningStates());
+ System.out.println(mbean.getQueueLength());
+ // wait task complete
+ Thread.sleep(1_000L);
+ System.out.println(mbean.getSwitchCount());
+ assertTrue(mbean.getSwitchCount().stream().mapToLong(Long::longValue).sum() >= taskTotal);
+ System.out.println(mbean.getSelectableIOCount());
+ assertTrue(mbean.getSwitchCount().stream().mapToLong(Long::longValue).sum() > 0);
+ System.out.println(mbean.getParkCount());
+ assertTrue(mbean.getParkCount().stream().mapToLong(Long::longValue).sum() > 0);
+ }
+
+ private static ServerSocket ss;
+ private static final int PORT = 23000;
+ private static final int BUFFER_SIZE = 1024;
+
+ private static void startNetServer() throws IOException {
+ ss = new ServerSocket(PORT);
+ Thread t = new Thread(() -> {
+ try {
+ while (true) {
+ Socket cs = ss.accept();
+ InputStream is = cs.getInputStream();
+ int r = is.read(new byte[BUFFER_SIZE]);
+ is.close();
+ cs.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ t.setDaemon(true);
+ t.start();
+ }
+
+ private static void doNetIO() {
+ try {
+ Socket so = new Socket("localhost", PORT);
+ OutputStream os = so.getOutputStream();
+ os.write(new byte[BUFFER_SIZE]);
+ os.flush();
+ os.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new Error(e);
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/ConfigurationCompatibilityCheckTest.java b/test/com/alibaba/wisp/ConfigurationCompatibilityCheckTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ffe1b391c755919a1bb7e39e71f8ab08d1fe926
--- /dev/null
+++ b/test/com/alibaba/wisp/ConfigurationCompatibilityCheckTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test the config compatibility in different wisp version
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main ConfigurationCompatibilityCheckTest
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class ConfigurationCompatibilityCheckTest {
+ public static void main(String[] args) throws Exception {
+ incompatibility("-Dcom.alibaba.wisp.enableThreadAsWisp=true");
+ incompatibility("-Dcom.alibaba.wisp.enableThreadAsWisp=true", "-Dcom.alibaba.wisp.transparentWispSwitch=false");
+ incompatibility("-Dcom.alibaba.wisp.allThreadAsWisp=true");
+ incompatibility("-Dcom.alibaba.wisp.allThreadAsWisp=true", "-Dcom.alibaba.wisp.enableThreadAsWisp=false");
+ incompatibility("-Dcom.alibaba.wisp.useCarrierAsPoller=true", "-Dcom.alibaba.wisp.allThreadAsWisp=false");
+ }
+
+ private static void incompatibility(String... args) throws Exception {
+ ArrayList list = new ArrayList<>();
+ list.add("-XX:+EnableCoroutine");
+ list.addAll(Arrays.asList(args));
+ list.add("-version");
+ ProcessBuilder pb = jdk.testlibrary.ProcessTools.createJavaProcessBuilder(list.toArray(new String[0]));
+ jdk.testlibrary.OutputAnalyzer output = new jdk.testlibrary.OutputAnalyzer(pb.start());
+ output.shouldContain("IllegalArgumentException");
+ }
+}
diff --git a/test/com/alibaba/wisp/CoroutineTest.java b/test/com/alibaba/wisp/CoroutineTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fa273d144407367c3a9b7fece4dcf63bf0cee51
--- /dev/null
+++ b/test/com/alibaba/wisp/CoroutineTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test low level coroutine implement
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine CoroutineTest
+ */
+
+import java.dyn.Coroutine;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * test low level coroutine implement
+ * 2 coroutine switch to each other and see the sequence
+ */
+public class CoroutineTest {
+ static int i = 0;
+ static Coroutine co1, co2;
+
+ public static void main(String[] args) {
+ try {
+
+ co1 = new Coroutine(() -> {
+ try {
+ if (i++ != 0)
+ throw new RuntimeException("co1 wrong sequence, expect 0");
+ Coroutine.yieldTo(co2);
+ if (i++ != 2)
+ throw new RuntimeException("co1 wrong sequence, expect 2");
+ Coroutine.yieldTo(co2);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ co2 = new Coroutine(() -> {
+
+ try {
+ if (i++ != 1)
+ throw new RuntimeException("co2 wrong sequence, expect 1");
+ Coroutine.yieldTo(co1);
+ if (i++ != 3)
+ throw new RuntimeException("co2 wrong sequence, expect 3");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ Coroutine.yieldTo(co1);
+
+
+ } catch (Exception e) {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/ExecutionTest.java b/test/com/alibaba/wisp/ExecutionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d0878bd7364a5b51d4b9702e063988ba634db0d
--- /dev/null
+++ b/test/com/alibaba/wisp/ExecutionTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test WispCarrier's multi-task schedule
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ExecutionTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+/**
+ * test the coroutine execute engine
+ */
+public class ExecutionTest {
+
+ static int finishCnt = 0;
+
+ public static void main(String[] args) {
+ Callable handler = () -> {
+ /**
+ * transform from:
+ * if ((nodeA() + nodeB()).equals("A:done\nB1:done\nB2:done\n"))
+ * throw new Error("result error");
+ */
+ FutureTask futureA = new FutureTask<>(ExecutionTest::nodeA);
+ FutureTask futureB = new FutureTask<>(ExecutionTest::nodeB);
+ WispEngine.current().execute(futureA);
+ WispEngine.current().execute(futureB);
+ String result;
+ try {
+ result = futureA.get() + futureB.get();
+ } catch (Exception e) {
+ throw new Error("exception during task execution");
+ }
+
+ if (!result.equals("A:done\nB1:done\nB2:done\n"))
+ throw new Error("result error");
+
+ finishCnt++;
+ return null;
+ };
+
+ /**
+ *
+ * WispCarrier.local().createTask(() -> {
+ * while (client = accept()) {
+ * WispCarrier.local().createTask(()->handler(client), "client handler");
+ * }
+ * }, "accepter");
+ *
+ * a web server can using a accepter {@link WispTask} create handler for every request
+ * we don't have request, create 3 handler manually
+ *
+ * every handler is a tree root
+ * handler handler handler
+ * / \ / \ / \
+ * A B A B A B
+ * / \ / \ / \
+ * B1 B2 B1 B2 B1 B2
+ *
+ *
+ * look into a particular tree:
+ * B1 and B2 is created when nodeB is executed after nodeA blocked
+ * business code drive the node create ..
+ *
+ * then B1 block; B2 executed and block
+ * then the engine block on pump about 100ms..
+ *
+ *
+ * 3 tree execute concurrently
+ *
+ */
+ for (int i = 0; i < 3; i++) {
+ WispEngine.current().execute(() -> {
+ try {
+ handler.call();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ SharedSecrets.getWispEngineAccess().sleep(200);
+ // the 3 tree should finish after 100ms+, but the switch need warm up, give more time..
+ if (finishCnt != 3) throw new Error("not finished");
+ }
+
+ static String nodeA() {
+ // node A could also be a function call after B created
+ return slowReq("A");
+ }
+
+ static String nodeB() {
+ /*
+ transform from:
+ return slowReq("B1") + slowReq("B2");
+ */
+ FutureTask future1 = new FutureTask<>(() -> slowReq("B1"));
+ FutureTask future2 = new FutureTask<>(() -> slowReq("B2"));
+ WispEngine.current().execute(future1);
+ WispEngine.current().execute(future2);
+
+ try {
+ return future1.get() + future2.get();
+ } catch (Exception e) {
+ throw new Error("exception during task execution");
+ }
+ }
+
+ // mimic an IO call
+ static String slowReq(String arg) {
+ SharedSecrets.getWispEngineAccess().sleep(100); // only block current coroutine
+ return arg + ":done\n";
+ }
+}
diff --git a/test/com/alibaba/wisp/IoTest.java b/test/com/alibaba/wisp/IoTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c982687f811aa66a8bf2eb1b4f64aa77764bac7
--- /dev/null
+++ b/test/com/alibaba/wisp/IoTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test Wisp engine's NIO support
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true IoTest
+ */
+
+import sun.misc.SharedSecrets;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.Properties;
+
+public class IoTest {
+
+ static Properties p;
+ static String socketAddr;
+ static {
+ p = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+ );
+ socketAddr = (String)p.get("test.wisp.socketAddress");
+ if (socketAddr == null) {
+ socketAddr = "www.example.com";
+ }
+ }
+
+ public static void main(String[] args) {
+ String result = http();
+
+ System.out.println(result);
+
+ if (!result.startsWith("HTTP") ||
+ !result.contains("Content-") ||
+ !result.contains("Server:"))
+ throw new Error("protocol error");
+ }
+
+ static String http() {
+ String host = socketAddr;
+
+ try {
+ SocketChannel ch = SocketChannel.open();
+ ch.configureBlocking(false);
+
+ connect(ch, InetAddress.getByName(host).getHostAddress());
+ ByteBuffer bb = ByteBuffer.allocate(1000);
+ String request = "HEAD / HTTP/1.0\r\nHost:" + host + "\r\n\r\n";
+ bb.put(request.getBytes());
+ bb.flip();
+ write(ch, bb);
+ bb.clear();
+ read(ch, bb);
+
+ return new String(bb.array(), 0, bb.remaining());
+
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ }
+
+ static int read(SocketChannel ch, ByteBuffer bb) throws IOException {
+ int n, retry = 0;
+ while ((n = ch.read(bb)) == 0) {
+ if (retry++ > 3)
+ throw new Error("busy loop"); // make sure we're not in a busy loop
+ SharedSecrets.getWispEngineAccess().registerEvent(ch, SelectionKey.OP_READ);
+ SharedSecrets.getWispEngineAccess().park(-1);
+ }
+ return n;
+ }
+
+ static int write(SocketChannel ch, ByteBuffer bb) throws IOException {
+ int n, retry = 0;
+ while ((n = ch.write(bb)) == 0) {
+ if (retry++ > 3) throw new Error("busy loop");
+ SharedSecrets.getWispEngineAccess().registerEvent(ch, SelectionKey.OP_WRITE);
+ SharedSecrets.getWispEngineAccess().park(-1);
+ }
+ return n;
+ }
+
+ static void connect(SocketChannel ch, String ip) throws IOException {
+ ch.connect(new InetSocketAddress(ip, 80));
+ int retry = 0;
+ while (!ch.finishConnect()) {
+ if (retry++ > 3) throw new Error("busy loop");
+ SharedSecrets.getWispEngineAccess().registerEvent(ch, SelectionKey.OP_CONNECT);
+ SharedSecrets.getWispEngineAccess().park(-1);
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/LoadClassInnerWispGuard.java b/test/com/alibaba/wisp/LoadClassInnerWispGuard.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1a4f6dd05bd1df900ef39dec1062f270aa1426b
--- /dev/null
+++ b/test/com/alibaba/wisp/LoadClassInnerWispGuard.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary verify there's no wisp class loaded after wisp initialize finished
+ * @requires os.family == "linux"
+ * @run main LoadClassInnerWispGuard
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.concurrent.*;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+import static jdk.testlibrary.Asserts.fail;
+
+public class LoadClassInnerWispGuard {
+ private static final String START = "LoadClassInnerWispGuard_START";
+ private static final String END = "LoadClassInnerWispGuard_END";
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 0) {
+ driver();
+ } else {
+ doSomeWispOperation();
+ }
+ }
+
+ /*
+ Here is a sample output from OutputAnalyzer:
+
+ [Loaded java.util.concurrent.ArrayBlockingQueue from: ...images/j2sdk-image/jre/lib/rt.jar]
+ LoadClassInnerWispGuard_START
+ [Loaded LoadClassInnerWispGuard$PingPong from file:...classes/com/alibaba/wisp/]
+ LoadClassInnerWispGuard_END
+
+ if class loading is happened during the test,
+ [Loaded com.alibaba.wisp.engine.WispEngine*...] will exist between
+ LoadClassInnerWispGuard_START and LoadClassInnerWispGuard_END
+ and we'll fail
+ */
+ private static void driver() throws Exception {
+ ProcessBuilder pb = jdk.testlibrary.ProcessTools.createJavaProcessBuilder(
+ "-XX:+UseWisp2", "-Dcom.alibaba.wisp.allThreadAsWisp=false", "-verbose:class",
+ "-cp", System.getProperty("java.class.path"),
+ LoadClassInnerWispGuard.class.getName(), "1");
+ jdk.testlibrary.OutputAnalyzer output = new jdk.testlibrary.OutputAnalyzer(pb.start());
+ String out = output.getStdout();
+ int off = out.indexOf(START);
+ for (String line : out.substring(off + START.length() + 1).split("\n")) {
+ if (line.startsWith(END)) break;
+ if (!line.startsWith("[Loaded")) continue;
+ if (line.contains(LoadClassInnerWispGuard.class.getName())) continue;
+ fail(line + "\n" + "wisp class loaded during runtime");
+ }
+ }
+
+ private static class TF implements ThreadFactory {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(r, "T");
+ thread.setDaemon(true);
+ return thread;
+ }
+ }
+
+ private static void doSomeWispOperation() throws Exception {
+ assertTrue(true); // preload jdk.testlibrary.Assert
+ Runnable r = () -> { /**/};
+ Executors.newCachedThreadPool(new TF()).submit(r).get();
+ WispEngine g = WispEngine.current();
+ BlockingQueue q1 = new ArrayBlockingQueue<>(1);
+ BlockingQueue q2 = new ArrayBlockingQueue<>(1);
+ CountDownLatch latch = new CountDownLatch(2);
+ System.out.println(START);
+ // 1. simple case
+ g.submit(r).get();
+ // 2. work stealing
+ g.submit(new PingPong(q1, q2, latch));
+ g.submit(new PingPong(q2, q1, latch));
+ q1.offer(1); // start
+ latch.await();
+ System.out.println(END);
+ }
+
+ static class PingPong implements Runnable {
+ final BlockingQueue pingQ;
+ final BlockingQueue pongQ;
+ final CountDownLatch latch;
+
+ public PingPong(BlockingQueue pingQ, BlockingQueue pongQ, CountDownLatch latch) {
+ this.pingQ = pingQ;
+ this.pongQ = pongQ;
+ this.latch = latch;
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (int i = 0; i < 100000; i++) {
+ pingQ.poll(1, TimeUnit.HOURS);
+ pongQ.offer(1);
+ }
+ latch.countDown();
+ } catch (Exception e) {
+ }
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/NormalExitTest.java b/test/com/alibaba/wisp/NormalExitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..486c591af7d2cb6f010117532d026f19f266f140
--- /dev/null
+++ b/test/com/alibaba/wisp/NormalExitTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test the exit without exception
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main NormalExitTest
+ */
+
+public class NormalExitTest {
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = jdk.testlibrary.ProcessTools.createJavaProcessBuilder("-XX:+UseWisp2", "-version");
+ jdk.testlibrary.OutputAnalyzer output = new jdk.testlibrary.OutputAnalyzer(pb.start());
+ output.shouldNotContain("IllegalArgumentException");
+ }
+}
diff --git a/test/com/alibaba/wisp/ParkTest.java b/test/com/alibaba/wisp/ParkTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..eaa74296fe1c09603bcb9eeb6d1b479660b1936b
--- /dev/null
+++ b/test/com/alibaba/wisp/ParkTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test Wisp engine park / unpark
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+UseWisp2 ParkTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class ParkTest {
+ public static void main(String[] args) throws Exception {
+ WispEngineAccess access = SharedSecrets.getWispEngineAccess();
+
+ WispTask[] task = new WispTask[1];
+
+ FutureTask ft = new FutureTask<>(() -> {
+ task[0] = access.getCurrentTask();
+ long start, diff;
+
+ start = System.currentTimeMillis();
+ access.park(0);
+
+ diff = System.currentTimeMillis() - start;
+ if (diff < 200 || diff > 220)
+ throw new Error("error test unpark by other thread");
+
+
+ start = start + diff;
+ access.park(TimeUnit.MILLISECONDS.toNanos(200));
+ diff = System.currentTimeMillis() - start;
+
+ if (diff < 200 || diff > 220)
+ throw new Error("error test timed park");
+
+
+ start = start + diff;
+ access.unpark(access.getCurrentTask());
+ access.park(0);
+ diff = System.currentTimeMillis() - start;
+ if (diff > 20)
+ throw new Error("error test permitted park");
+
+ return true;
+ });
+
+ WispEngine.current().execute(ft);
+
+ Thread unparkThread = new Thread(() -> {
+ access.sleep(200);
+ access.unpark(task[0]);
+ });
+ unparkThread.start();
+
+ assertTrue(ft.get(5, TimeUnit.SECONDS));
+ }
+}
diff --git a/test/com/alibaba/wisp/TestWispDetailCounter.java b/test/com/alibaba/wisp/TestWispDetailCounter.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e642ed42544505998cad9a34f7f81b42f025c23
--- /dev/null
+++ b/test/com/alibaba/wisp/TestWispDetailCounter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+import com.alibaba.management.WispCounterMXBean;
+
+import javax.management.MBeanServer;
+import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+/* @test
+ * @summary WispCounterMXBean unit test for Detail profile data
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm/timeout=2000 -XX:+UseWisp2 -Dcom.alibaba.wisp.config=/tmp/wisp.config -Dcom.alibaba.wisp.profile=true -Dcom.alibaba.wisp.enableProfileLog=true -Dcom.alibaba.wisp.logTimeInternalMillis=3000 TestWispDetailCounter
+ */
+
+public class TestWispDetailCounter {
+
+ public static void main(String[] args) throws Exception {
+ startNetServer();
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ WispCounterMXBean mbean = null;
+ try {
+ mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+ "com.alibaba.management:type=WispCounter", WispCounterMXBean.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ ExecutorService es = Executors.newFixedThreadPool(20);
+ int taskTotal = 40;
+ for (int i = 0; i < taskTotal; i++) {
+ // submit task
+ es.submit(() -> {
+ // do park/unpark
+ synchronized (TestWispDetailCounter.class) {
+ // do sleep
+ try {
+ Thread.sleep(10L);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ // do net IO
+ doNetIO();
+ });
+ }
+
+ System.out.println(mbean.getRunningStates());
+ System.out.println(mbean.getQueueLength());
+ System.out.println(mbean.getNumberOfRunningTasks());
+ // wait task complete
+ Thread.sleep(1_000L);
+ System.out.println(mbean.getCreateTaskCount());
+ System.out.println(mbean.getCompleteTaskCount());
+ System.out.println(mbean.getUnparkCount());
+ assertTrue(mbean.getUnparkCount().stream().mapToLong(Long::longValue).sum() > 0);
+ System.out.println(mbean.getTotalBlockingTime());
+ assertTrue(mbean.getTotalBlockingTime().stream().mapToLong(Long::longValue).sum() > 0);
+ System.out.println(mbean.getWaitSocketIOCount());
+ System.out.println(mbean.getTotalWaitSocketIOTime());
+ System.out.println(mbean.getEnqueueCount());
+ assertTrue(mbean.getEnqueueCount().stream().mapToLong(Long::longValue).sum() > 0);
+ System.out.println(mbean.getTotalEnqueueTime());
+ assertTrue(mbean.getTotalEnqueueTime().stream().mapToLong(Long::longValue).sum() > 0);
+ System.out.println(mbean.getExecutionCount());
+ assertTrue(mbean.getExecutionCount().stream().mapToLong(Long::longValue).sum() > 0);
+ System.out.println(mbean.getTotalExecutionTime());
+ assertTrue(mbean.getTotalExecutionTime().stream().mapToLong(Long::longValue).sum() > 0);
+
+ es.submit(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e) {
+ }
+ });
+ System.out.println(mbean.getNumberOfRunningTasks());
+ assertTrue(mbean.getNumberOfRunningTasks().stream().mapToLong(Long::longValue).sum() > 0);
+
+ // check log file exist
+ File file = new File("wisplog0.log");
+ if (!file.exists()) {
+ assertTrue(false, "log file isn't generated");
+ }
+ }
+
+ private static ServerSocket ss;
+ private static final int PORT = 23000;
+ private static final int BUFFER_SIZE = 1024;
+
+ private static void startNetServer() throws IOException {
+ ss = new ServerSocket(PORT);
+ Thread t = new Thread(() -> {
+ try {
+ while (true) {
+ Socket cs = ss.accept();
+ InputStream is = cs.getInputStream();
+ int r = is.read(new byte[BUFFER_SIZE]);
+ is.close();
+ cs.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ t.setDaemon(true);
+ t.start();
+ }
+
+ private static void doNetIO() {
+ try {
+ Socket so = new Socket("localhost", PORT);
+ OutputStream os = so.getOutputStream();
+ os.write(new byte[BUFFER_SIZE]);
+ os.flush();
+ os.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new Error(e);
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/WispMonitorDataTest.java b/test/com/alibaba/wisp/WispMonitorDataTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..262cf2d87d887784e35eb8cfa061c098688506c7
--- /dev/null
+++ b/test/com/alibaba/wisp/WispMonitorDataTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+import com.alibaba.management.WispCounterMXBean;
+import com.alibaba.wisp.engine.WispCounter;
+
+import javax.management.MBeanServer;
+import java.io.*;
+import java.lang.management.ManagementFactory;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.*;
+
+import sun.misc.JavaLangAccess;
+import sun.misc.SharedSecrets;
+
+import java.lang.reflect.Field;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+/* @test
+ * @summary WispCounterMXBean unit test for Detail profile data using the API with the specified WispCarrier
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm/timeout=2000 -XX:+UseWisp2 -Dcom.alibaba.wisp.config=/tmp/wisp.config -Dcom.alibaba.wisp.profile=true WispMonitorDataTest
+ */
+
+public class WispMonitorDataTest {
+
+ public static void main(String[] args) throws Exception {
+ startNetServer();
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ WispCounterMXBean mbean = null;
+ try {
+ mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+ "com.alibaba.management:type=WispCounter", WispCounterMXBean.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ ExecutorService es = Executors.newFixedThreadPool(20);
+ int taskTotal = 40;
+ for (int i = 0; i < taskTotal; i++) {
+ // submit task
+ es.submit(() -> {
+ // do park/unpark
+ synchronized (WispMonitorDataTest.class) {
+ // do sleep
+ try {
+ Thread.sleep(10L);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ // do net IO
+ doNetIO();
+ });
+ }
+ Thread.sleep(1_000L);
+
+ Class> clazz = Class.forName("com.alibaba.wisp.engine.WispEngine");
+ Field field = clazz.getDeclaredField("carrierThreads");
+ field.setAccessible(true);
+ Set set = (Set) field.get(null);
+ JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+ for (Thread thread : set) {
+ WispCounter wispdata = mbean.getWispCounter(thread.getId());
+ if (wispdata != null) {
+ System.out.println("WispTask is " + thread.getId());
+ System.out.println(wispdata.getCompletedTaskCount());
+ System.out.println(wispdata.getTotalExecutionTime());
+ System.out.println(wispdata.getExecutionCount());
+ System.out.println(wispdata.getTotalEnqueueTime());
+ System.out.println(wispdata.getEnqueueCount());
+ }
+ }
+ }
+
+ private static ServerSocket ss;
+ private static final int PORT = 23000;
+ private static final int BUFFER_SIZE = 1024;
+
+ private static void startNetServer() throws IOException {
+ ss = new ServerSocket(PORT);
+ Thread t = new Thread(() -> {
+ try {
+ while (true) {
+ Socket cs = ss.accept();
+ InputStream is = cs.getInputStream();
+ int r = is.read(new byte[BUFFER_SIZE]);
+ is.close();
+ cs.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ t.setDaemon(true);
+ t.start();
+ }
+
+ private static void doNetIO() {
+ try {
+ Socket so = new Socket("localhost", PORT);
+ OutputStream os = so.getOutputStream();
+ os.write(new byte[BUFFER_SIZE]);
+ os.flush();
+ os.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new Error(e);
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/boot/UnsafeDependencyBugTest.java b/test/com/alibaba/wisp/boot/UnsafeDependencyBugTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd62715b5b9ee8d0423e10c7a6e9eb9720424ede
--- /dev/null
+++ b/test/com/alibaba/wisp/boot/UnsafeDependencyBugTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test bug fix of SharedSecrets and Unsafe class initializer circular dependency
+ * @requires os.family == "linux"
+ * @run main UnsafeDependencyBugTest 10
+ */
+
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+/**
+ * We need thousand times to reproduce the DEADLOCK. Don't spend too much time here..
+ * We already add svt test ajdk_svt/wispTest to ensure the DEADLOCK already solved.
+ */
+public class UnsafeDependencyBugTest {
+
+ public static void main(String[] args) throws Exception {
+ long start = System.currentTimeMillis();
+ int i;
+ for (i = 0; System.currentTimeMillis() - start < Integer.valueOf(args[0]) * 1000; i++) {
+ runLauncherWithWisp();
+ }
+ System.out.println("tested " + i + " times");
+ }
+
+ private static void runLauncherWithWisp() throws Exception {
+ Process p = new ProcessBuilder(System.getProperty("java.home") + "/bin/java", "-XX:+EnableCoroutine")
+ .redirectErrorStream(true)
+ .redirectOutput(new File("/dev/null"))
+ .start();
+
+ assertTrue(p.waitFor(4, TimeUnit.SECONDS));
+ }
+}
diff --git a/test/com/alibaba/wisp/bug/CancelTimerAndSleepTest.java b/test/com/alibaba/wisp/bug/CancelTimerAndSleepTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..854a4fb1322d1208218ae6965151d6c10ec06ebd
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/CancelTimerAndSleepTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test sleep
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true CancelTimerAndSleepTest
+ */
+
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.util.concurrent.TimeUnit;
+
+public class CancelTimerAndSleepTest {
+
+ public static void main(String[] args) throws Exception {
+ WispEngineAccess access = SharedSecrets.getWispEngineAccess();
+
+ access.addTimer(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(10));
+ access.cancelTimer();
+
+ long now = System.currentTimeMillis();
+ Thread.sleep(200);
+ long elapsed = System.currentTimeMillis() - now;
+ if (Math.abs(elapsed - 200) > 10)
+ throw new Error("elapsed = " + elapsed);
+ }
+}
diff --git a/test/com/alibaba/wisp/bug/Id2TaskMapLeakTest.java b/test/com/alibaba/wisp/bug/Id2TaskMapLeakTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d3aaeb7acb92ad8507bf7ab9d3d109564770863
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/Id2TaskMapLeakTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test for thread WispTask leak
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true Id2TaskMapLeakTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static jdk.testlibrary.Asserts.assertEQ;
+
+public class Id2TaskMapLeakTest {
+ public static void main(String[] args) throws Exception {
+ Field f = WispTask.class.getDeclaredField("id2Task");
+ f.setAccessible(true);
+ Map map = (Map) f.get(null);
+
+ int size0 = map.size();
+
+ AtomicInteger sizeHolder = new AtomicInteger();
+
+ new Thread(() -> {
+ WispEngine.current();
+ sizeHolder.set(map.size());
+ }).start();
+ Thread.sleep(20); // ensure thread exit;
+
+ assertEQ(size0 + 1, sizeHolder.get());
+ assertEQ(size0, map.size());
+ }
+}
diff --git a/test/com/alibaba/wisp/bug/ReleaseWispSocketAndExitTest.java b/test/com/alibaba/wisp/bug/ReleaseWispSocketAndExitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..79c5ebd4808b24de89ecbd7b182b2b2af22c95e6
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/ReleaseWispSocketAndExitTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary handle this scenario:
+ * 1. task A fetch a socket S and release it.
+ * 2. task B get the socket S and block on IO.
+ * 3. task A exit and clean S's event, now B waiting forever...
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ReleaseWispSocketAndExitTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class ReleaseWispSocketAndExitTest {
+ static byte buf[] = new byte[1000];
+
+ public static void main(String[] args) throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ CountDownLatch listen = new CountDownLatch(1);
+ CountDownLatch finish = new CountDownLatch(3);
+
+ WispEngine.dispatch(() -> {
+ try {
+ ServerSocket sso = new ServerSocket(51243);
+ listen.countDown();
+ Socket so;
+ so = sso.accept();
+ InputStream is = so.getInputStream();
+ OutputStream os = so.getOutputStream();
+ int n;
+ while ((n = is.read(buf, 0, 4)) == 4) {
+ long l = Long.valueOf(new String(buf, 0, n));
+ System.out.println("l = " + l);
+ SharedSecrets.getWispEngineAccess().sleep(l);
+ os.write(buf, 0, n);
+ }
+ } catch (Exception e) {
+ throw new Error();
+ }
+ finish.countDown();
+ });
+
+ listen.await();
+ Socket so = new Socket("127.0.0.1", 51243);
+
+ WispEngine.dispatch(() -> {
+ try {
+ InputStream is = so.getInputStream();
+ OutputStream os = so.getOutputStream();
+ os.write("0000".getBytes());
+ System.out.println("======");
+ latch.await();
+ System.out.println("======2");
+ } catch (Exception e) {
+ throw new Error();
+ }
+ finish.countDown();
+ });
+
+ WispEngine.dispatch(() -> {
+ try {
+ InputStream is = so.getInputStream();
+ OutputStream os = so.getOutputStream();
+
+ os.write("0100".getBytes());
+ System.out.println("------");
+ latch.countDown();
+ is.read(buf);
+ is.read(buf);// blocked
+ System.out.println("------2");
+
+ so.close();
+ } catch (Exception e) {
+ throw new Error();
+ }
+ finish.countDown();
+ });
+
+ finish.await(5, TimeUnit.SECONDS);
+ System.out.println("passed");
+ }
+
+}
diff --git a/test/com/alibaba/wisp/bug/ResetTaskCancelTimerBugTest.java b/test/com/alibaba/wisp/bug/ResetTaskCancelTimerBugTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad048e205a801b8b576ac3b09840b89d76815419
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/ResetTaskCancelTimerBugTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test reset task doesn't cancel the current task's timer unexpectedly.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ResetTaskCancelTimerBugTest
+ */
+
+
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+public class ResetTaskCancelTimerBugTest {
+ public static void main(String[] args) throws Exception {
+ AtomicReference executor = new AtomicReference<>();
+ AtomicBoolean submitDone = new AtomicBoolean();
+ CountDownLatch latch = new CountDownLatch(1);
+
+ new Thread(() -> {
+ executor.set(WispEngine.current());
+ while (!submitDone.get()) {}
+ // 4. go sleep, cause there's a pending external WispTask create operation,
+ // we should create the task fist.
+ // WispCarrier.runTaskInternal() -> WispTask.reset() -> WispCarrier.cancelTimer()
+ // will remove current task's timer, the sleep() could never be wakened.
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ latch.countDown();
+ }).start();
+ while (executor.get() == null) {}
+
+ // 1. create a thread(also created WispCarrier A)
+ executor.get().execute(() -> {});
+ // 2. request create WispTask in the WispCarrier A
+ submitDone.set(true);
+ // 3. telling WispCarrier A's it's time to sleep
+
+ // 5. wait sleep done. If latch.countDown() is not invoked inner 10 seconds, TEST FAILURE.
+ assertTrue(latch.await(10, TimeUnit.SECONDS));
+ }
+}
diff --git a/test/com/alibaba/wisp/bug/SelectorInitCriticalTest.java b/test/com/alibaba/wisp/bug/SelectorInitCriticalTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d1cc8a4c9bf5f3b35fea4678ffe03e241b7043d
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/SelectorInitCriticalTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test the fix to NPE issue caused by unexpected co-routine yielding on synchronized(lock) in SelectorProvider.provider() during initialization of WispCarrier
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -XX:+UseWispMonitor SelectorInitCriticalTest
+ */
+
+
+import java.lang.reflect.Field;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.concurrent.CountDownLatch;
+
+public class SelectorInitCriticalTest {
+ public static void main(String[] args) throws Exception {
+ Field f = SelectorProvider.class.getDeclaredField("lock");
+ f.setAccessible(true);
+ Object selectorProviderLock = f.get(null);
+ CountDownLatch latch = new CountDownLatch(1);
+
+ Thread t = new Thread(latch::countDown);
+
+ synchronized (selectorProviderLock) {
+ t.start();
+ // Holding selectorProviderLock for a while which will eventually blocks the initialization of t' WispCarrier
+ Thread.sleep(100);
+ }
+
+ latch.await();
+
+ }
+}
diff --git a/test/com/alibaba/wisp/bug/TestThreadStackTrace.sh b/test/com/alibaba/wisp/bug/TestThreadStackTrace.sh
new file mode 100644
index 0000000000000000000000000000000000000000..21797fb33da791cc8ceac8596f33dac02df72e67
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/TestThreadStackTrace.sh
@@ -0,0 +1,149 @@
+#!/usr/bin/env bash
+
+#
+# Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Alibaba designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+#
+# @test
+# @summary test Thread.getStackTrace() in wisp transparentAsync model
+# @requires os.family == "linux"
+# @run shell TestThreadStackTrace.sh
+#
+
+if [ "${TESTSRC}" = "" ]
+then
+ TESTSRC=${PWD}
+ echo "TESTSRC not set. Using "${TESTSRC}" as default"
+fi
+echo "TESTSRC=${TESTSRC}"
+# determine platform dependant variables
+OS=`uname -s`
+case ${OS} in
+ Linux)
+ FS=/
+ ;;
+ *)
+ exit 1
+ ;;
+esac
+
+JAVA=${TESTJAVA}${FS}bin${FS}java
+JAVAC=${TESTJAVA}${FS}bin${FS}javac
+TEST_CLASS=TmpThreadStackTrace
+TEST_SOURCE=${TEST_CLASS}.java
+
+###################################################################################
+
+
+cat > ${TESTCLASSES}${FS}$TEST_SOURCE << EOF
+import com.alibaba.wisp.engine.WispEngine;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import sun.misc.SharedSecrets;
+import java.util.concurrent.Executors;
+import java.util.concurrent.*;
+
+public class TmpThreadStackTrace {
+
+ public static Thread runningCoroutine;
+
+ public static void foo() throws Exception {
+ ExecutorService executor = Executors.newCachedThreadPool();
+ executor.execute(() -> {
+ try {
+ runningCoroutine = Thread.currentThread();
+ Thread.sleep(2_000L);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ AtomicBoolean result = new AtomicBoolean(true);
+ CountDownLatch done = new CountDownLatch(1);
+ Thread mainThread = Thread.currentThread();
+ Thread[] ts = new Thread[1];
+ ts[0] = new Thread(() -> {
+ System.out.println("in managed!");
+ try {
+ if (ts[0].getStackTrace().length == 0 || mainThread.getStackTrace().length == 0
+ || Thread.currentThread().getStackTrace().length == 0) {
+ result.set(false);
+ }
+ runningCoroutine.getStackTrace();
+ result.set(false);
+ } catch (Exception e) {
+ if (!(e instanceof UnsupportedOperationException)) {
+ result.set(false);
+ }
+ } finally {
+ done.countDown();
+ }
+ }, "test-thread");
+ ts[0].start();
+ done.await();
+ System.out.println("in main");
+ executor.shutdown();
+ if (!result.get()) {
+ throw new Error("test failure");
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ WispEngine.current().execute(() -> {
+ for (int i = 0; i < 5; i++) {
+ System.out.println(i);
+ Thread.currentThread().getStackTrace();
+ }
+ latch.countDown();
+ });
+ latch.await();
+ foo();
+ System.out.println("done");
+ System.exit(0);
+ }
+}
+EOF
+
+# Do compilation
+${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE >> /dev/null 2>&1
+if [ $? != '0' ]
+then
+ printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE}"
+ exit 1
+fi
+
+#run
+${JAVA} -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+UseWisp2 -Dcom.alibaba.wisp.carrierEngines=1 -cp ${TESTCLASSES} ${TEST_CLASS} > output.txt 2>&1
+cat output.txt
+
+function assert()
+{
+ line=`cat output.txt | grep ThreadDump | wc -l`
+ echo $line
+ if [[ $line -eq "2" ]]; then
+ echo "success"
+ else
+ echo "failure"
+ exit -1
+ fi
+}
+
+assert
diff --git a/test/com/alibaba/wisp/bug/ThreadLockTest.java b/test/com/alibaba/wisp/bug/ThreadLockTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..308fe69c162724b99030239739dfe2ffc6b482da
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/ThreadLockTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test fix of WispCarrier block on Thread.class lock
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -XX:SyncKnobs="ReportSettings=1:QMode=1" -Dcom.alibaba.wisp.transparentWispSwitch=true ThreadLockTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class ThreadLockTest {
+ public static void main(String[] args) throws Exception {
+
+ CountDownLatch done = new CountDownLatch(1);
+ AtomicReference es = new AtomicReference<>(null);
+
+ synchronized (Thread.class) {
+ new Thread(() -> {
+ es.set(WispEngine.current());
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }, "ThreadIdGeneratorLockTest").start();
+
+ Thread.sleep(100); // make sure "ThreadIdGeneratorLockTest" already sleeping
+
+ /*
+ if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
+ // Try to assume the role of responsible thread for the monitor.
+ // CONSIDER: ST vs CAS vs { if (Responsible==null) Responsible=Self }
+ Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
+ }
+ ----------------
+ if (_Responsible == Self || (SyncFlags & 1)) {
+ use timeout park
+ }
+ add a waiter, let _Responsible != Self
+ */
+ new Thread(() -> {
+ try {
+ Method m = Thread.class.getDeclaredMethod("nextThreadNum");
+ m.setAccessible(true);
+ m.invoke(null);
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ }, "waiter").start();
+ Thread.sleep(100); // make sure adding waiter is done
+
+
+ es.get().execute(() -> { // give an name "A"
+ Thread.currentThread(); // before fix, we'll hang here
+ done.countDown();
+ });
+
+ // objectMonitor::EnterI generally puts waiter to head, now _cxq is:
+ // "A" (os_park) --> "A" (wisp_park) --> "waiter"
+ // set QMode=1 to reverse the queue
+ // _Entry_list is:
+ // "waiter" --> "A" (wisp_park) --> "A" (os_park)
+ Thread.sleep(100); // still hold lock 100 ms, make sure the lsat wisp blocked
+ }
+ // release:
+ // 1. wisp unpark "waiter"
+ // 2. wisp unpark "A" (wisp_park) (just after waiter ends)
+ // now "ThreadIdGeneratorLockTest" Thread is on os_park, test failed!
+
+ done.await();
+ }
+}
diff --git a/test/com/alibaba/wisp/bug/ThreadPoolFastShutdownBugTest.java b/test/com/alibaba/wisp/bug/ThreadPoolFastShutdownBugTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..35442a45977cce5c4cbf4af083f12dd06b20fee5
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/ThreadPoolFastShutdownBugTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test shutdown a thread pool which contains non-fully-started thread
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ThreadPoolFastShutdownBugTest
+ */
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ThreadPoolFastShutdownBugTest {
+ public static void main(String[] args) {
+ ExecutorService executorService = Executors.newSingleThreadExecutor();
+ executorService.submit(new InitThread());
+ executorService.shutdown();
+ }
+
+ static class InitThread implements Runnable {
+
+ @Override
+ public void run() {
+
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/bug/WispSelectorReadyOpsTest.java b/test/com/alibaba/wisp/bug/WispSelectorReadyOpsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d45a33845fd3b72b7d61836a86ccf2b6273e7ac
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/WispSelectorReadyOpsTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary ensure nio program call SelectionKey.is{}able() and got correct result.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true WispSelectorReadyOpsTest
+ */
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+public class WispSelectorReadyOpsTest {
+ public static void main(String[] args) throws Exception {
+ Selector selector = Selector.open();
+ ServerSocketChannel sch = ServerSocketChannel.open();
+ sch.configureBlocking(false);
+ sch.bind(new InetSocketAddress(54442));
+ sch.register(selector, sch.validOps());
+
+ Socket so = new Socket("127.0.0.1", 54442);
+
+ selector.selectNow();
+ SelectionKey sk = (SelectionKey) selector.selectedKeys().toArray()[0];
+ if (!sk.isAcceptable()) {
+ throw new Error("fail");
+ }
+
+ SocketChannel sc = sch.accept();
+ sc.configureBlocking(false);
+ sc.register(selector, sc.validOps());
+
+ so.getOutputStream().write("123".getBytes());
+
+ selector.selectedKeys().clear();
+ selector.selectNow();
+ sk = (SelectionKey) selector.selectedKeys().toArray()[0];
+ if (!sk.isReadable()) {
+ throw new Error("fail");
+ }
+ }
+
+}
diff --git a/test/com/alibaba/wisp/bug/WispSocketLeakWhenConnectTimeoutTest.java b/test/com/alibaba/wisp/bug/WispSocketLeakWhenConnectTimeoutTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a5d6c61499a7f9b35fbd40ceb4aef62af96a319
--- /dev/null
+++ b/test/com/alibaba/wisp/bug/WispSocketLeakWhenConnectTimeoutTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test the fix to fd leakage when socket connect timeout
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true WispSocketLeakWhenConnectTimeoutTest
+ */
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class WispSocketLeakWhenConnectTimeoutTest {
+ public static void main(String[] args) throws IOException {
+ Socket so = new Socket();
+ boolean timeout = false;
+ try {
+ so.connect(new InetSocketAddress("www.example.com", 80), 5);
+ } catch (SocketTimeoutException e) {
+ assertTrue(so.isClosed());
+ timeout = true;
+ }
+
+ assertTrue(timeout, "SocketTimeoutException should been thrown");
+ }
+}
diff --git a/test/com/alibaba/wisp/close/WispDestroyTest.java b/test/com/alibaba/wisp/close/WispDestroyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..352f819a3422643bd4448135a6c499bd8db37807
--- /dev/null
+++ b/test/com/alibaba/wisp/close/WispDestroyTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test WispCarrier's destroy
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true WispDestroyTest
+ */
+
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.CountDownLatch;
+
+public class WispDestroyTest {
+
+ static Object e;
+
+ public static void main(String[] args) throws Exception {
+ CountDownLatch l = new CountDownLatch(1);
+
+ new Thread(() -> {
+ try {
+ Field f = WispTask.class.getDeclaredField("carrier");
+ f.setAccessible(true);
+ e = f.get(SharedSecrets.getJavaLangAccess().getWispTask(Thread.currentThread()));
+ l.countDown();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }).start();
+
+ l.await();
+
+ Thread.sleep(1000); // ensure Thread.exit() executed
+
+
+ Field terminated = e.getClass().getDeclaredField("terminated");
+ terminated.setAccessible(true);
+ if (!terminated.getBoolean(e)) throw new Error("resource leak!");
+ }
+}
diff --git a/test/com/alibaba/wisp/env/CtxClassLoaderIsolateTest.java b/test/com/alibaba/wisp/env/CtxClassLoaderIsolateTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..683ca5622c61d5ee588e9c28725c00a5d49bf5c5
--- /dev/null
+++ b/test/com/alibaba/wisp/env/CtxClassLoaderIsolateTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Verify the context class loader isolation per co-routine
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true CtxClassLoaderIsolateTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class CtxClassLoaderIsolateTest {
+ public static void main(String[] args) throws Exception {
+ ClassLoader loader0 = Thread.currentThread().getContextClassLoader();
+ WispEngine.dispatch(() -> Thread.currentThread().setContextClassLoader(new ClassLoader() {
+ @Override
+ public Class> loadClass(String name) throws ClassNotFoundException {
+ return super.loadClass(name);
+ }
+ }));
+
+ assertTrue(Thread.currentThread().getContextClassLoader() == loader0);
+ }
+}
diff --git a/test/com/alibaba/wisp/io/BlockingAccept2Test.java b/test/com/alibaba/wisp/io/BlockingAccept2Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..05adaabcb37ea01728fc45f7f1436d1cc0d2d8d2
--- /dev/null
+++ b/test/com/alibaba/wisp/io/BlockingAccept2Test.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test blocking accept
+ * @requires os.family == "linux"
+ * @run main/othervm -Dcom.alibaba.wisp.carrierEngines=1 -XX:+UseWisp2 BlockingAccept2Test
+ */
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class BlockingAccept2Test {
+ public static void main(String[] args) throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ CountDownLatch latch2 = new CountDownLatch(1);
+ Thread t = new Thread(() -> {
+ try {
+ latch.await(1, TimeUnit.SECONDS);
+ Thread.sleep(200);
+ Socket s = new Socket();
+ s.connect(new InetSocketAddress(12388));
+ latch2.await(1, TimeUnit.SECONDS);
+ s.close();
+ Thread.sleep(200);
+ s = new Socket();
+ s.connect(new InetSocketAddress(12388));
+ } catch (Exception e) {
+ }
+ });
+ t.start();
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(new InetSocketAddress(12388));
+ latch.countDown();
+ ssc.accept();
+ latch2.countDown();
+ ssc.accept();
+ }
+}
diff --git a/test/com/alibaba/wisp/io/BlockingAcceptTest.java b/test/com/alibaba/wisp/io/BlockingAcceptTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6291ff9efb33054c9a93932a57b5deecd18a58c
--- /dev/null
+++ b/test/com/alibaba/wisp/io/BlockingAcceptTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test blocking accept
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:ActiveProcessorCount=4 -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -XX:+UseWispMonitor BlockingAcceptTest
+ * @run main/othervm -XX:ActiveProcessorCount=4 -XX:+UseWisp2 BlockingAcceptTest
+ */
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class BlockingAcceptTest {
+ public static void main(String[] args) throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ Thread t = new Thread(() -> {
+ try {
+ latch.await(1, TimeUnit.SECONDS);
+ Thread.sleep(200);
+ Socket s = new Socket();
+ s.connect(new InetSocketAddress(12388));
+ } catch (Exception e) {
+ }
+ });
+ t.start();
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(new InetSocketAddress(12388));
+ latch.countDown();
+ ssc.accept();
+ }
+}
diff --git a/test/com/alibaba/wisp/io/CreateFdOnDemandTest.java b/test/com/alibaba/wisp/io/CreateFdOnDemandTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..29f6239a35af18b8a3b7e67c50ff142224d5e0a8
--- /dev/null
+++ b/test/com/alibaba/wisp/io/CreateFdOnDemandTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test fix of unconnected Socket fd leak.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true CreateFdOnDemandTest
+ */
+
+import java.io.File;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import static jdk.testlibrary.Asserts.assertEQ;
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class CreateFdOnDemandTest {
+ public static void main(String[] args) throws Exception {
+
+ assertEQ(countFd(), countFd());
+ Socket so = new Socket();
+ so.setReuseAddress(true);
+ so.close();
+ ServerSocket sso = new ServerSocket();
+ sso.setReuseAddress(true);
+ sso.close();
+ DatagramSocket ds = new DatagramSocket(null);
+ ds.setReuseAddress(true);
+ ds.close();
+
+
+ final int nfd0 = countFd();
+ so = new Socket();
+ assertEQ(countFd(), nfd0);
+ sso = new ServerSocket();
+ assertEQ(countFd(), nfd0);
+ ds = new DatagramSocket(null);
+ assertTrue(WispEngine.transparentWispSwitch() && countFd() == nfd0); // if -Dcom.alibaba.wisp.transparentWispSwitch=false, fail
+
+ so.setReuseAddress(true);
+ assertEQ(countFd(), nfd0 + 1);
+ sso.setReuseAddress(true);
+ assertEQ(countFd(), nfd0 + 2);
+ ds.setReuseAddress(true);
+ assertEQ(countFd(), nfd0 + 3);
+
+ so.close();
+ assertEQ(countFd(), nfd0 + 2);
+ sso.close();
+ assertEQ(countFd(), nfd0 + 1);
+ ds.close();
+ assertEQ(countFd(), nfd0);
+ }
+
+ private static int countFd() {
+ File f = new File("/proc/self/fd");
+ return f.list().length;
+ }
+}
diff --git a/test/com/alibaba/wisp/io/DatagramSocketTest.java b/test/com/alibaba/wisp/io/DatagramSocketTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..572ca8a79d84bcc207ee571e2c0a349fc54f8771
--- /dev/null
+++ b/test/com/alibaba/wisp/io/DatagramSocketTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test WispCarrier's DatagramSocket, InitialDirContext use dup socket to query dns.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true DatagramSocketTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import javax.naming.directory.InitialDirContext;
+import java.io.IOException;
+import java.net.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static jdk.testlibrary.Asserts.*;
+
+public class DatagramSocketTest {
+
+ static CountDownLatch latch = new CountDownLatch(10);
+
+ public static void main(String[] args) throws Exception {
+ for (int i = 0; i < 10; i++) {
+ WispEngine.current().execute(DatagramSocketTest::foo);
+ }
+
+ latch.await(5, TimeUnit.SECONDS);
+ testSendAndReceive();
+ }
+
+ static public void foo() {
+ try {
+ InitialDirContext dirCtx = new InitialDirContext();
+ System.out.println(dirCtx.getAttributes("dns:/www.tmall.com"));
+ } catch (Throwable e) {
+ throw new Error("query dns error");
+ }
+ latch.countDown();
+ }
+
+ static public void testSendAndReceive() throws Exception {
+ CountDownLatch count = new CountDownLatch(1);
+ InetAddress host = InetAddress.getByName("localhost");
+ int port = 9527;
+ DatagramSocket so = new DatagramSocket(port);
+ so.setSoTimeout(1_000);
+ final int loop = 1024;
+ Thread receiver = new Thread(() -> {
+ int received = 0;
+ try {
+ byte[] buf = new byte[1024 * 32];
+ DatagramPacket dp = new DatagramPacket(buf, buf.length);
+ count.countDown();
+ for (int i = 0; i < loop; i++) {
+ received++;
+ so.receive(dp);
+ }
+ } catch (SocketTimeoutException e) {
+ e.printStackTrace();
+ System.out.println("received packets: " + received);
+ // We at least received 64 packets before timeout
+ assertTrue(received > 64);
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ });
+ receiver.start();
+ count.await();
+ for (int i = 0; i < loop; i++) {
+ byte[] buf = new byte[1024 * 32];
+ DatagramPacket dp = new DatagramPacket(buf, buf.length, host, port);
+ so.send(dp);
+ }
+ receiver.join();
+ }
+}
diff --git a/test/com/alibaba/wisp/io/GlobalPollerTest.java b/test/com/alibaba/wisp/io/GlobalPollerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..443d7284b7745d60d32fbd6adf807e008e73fc98
--- /dev/null
+++ b/test/com/alibaba/wisp/io/GlobalPollerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test for Global Poller
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.transparentAsync=true GlobalPollerTest
+*/
+
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+import sun.nio.ch.SelChImpl;
+
+import java.lang.reflect.Field;
+import java.net.Socket;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.Properties;
+
+import static jdk.testlibrary.Asserts.assertNotNull;
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class GlobalPollerTest {
+ private static WispEngineAccess access = SharedSecrets.getWispEngineAccess();
+
+ static Properties p;
+ static String socketAddr;
+ static {
+ p = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+ );
+ socketAddr = (String)p.get("test.wisp.socketAddress");
+ if (socketAddr == null) {
+ socketAddr = "www.example.com";
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+
+
+ Socket so = new Socket(socketAddr, 80);
+ so.getOutputStream().write("NOP\n\r\n\r".getBytes());
+ // now server returns the data..
+ // so is readable
+ // current task is interested in read event.
+ SocketChannel ch = so.getChannel();
+ access.registerEvent(ch, SelectionKey.OP_READ);
+
+ Class> clazz = Class.forName("com.alibaba.wisp.engine.WispEventPump$Pool");
+ Field pumps = clazz.getDeclaredField("pumps");
+ pumps.setAccessible(true);
+ Object[] a = (Object[]) pumps.get(clazz.getEnumConstants()[0]);
+ WispTask[] fd2TaskLow = null;
+ int fd = ((SelChImpl) ch).getFDVal();
+ for (Object pump : a) {
+ Field f = Class.forName("com.alibaba.wisp.engine.WispEventPump").getDeclaredField("fd2ReadTaskLow");
+ f.setAccessible(true);
+ WispTask[] map = (WispTask[]) f.get(pump);
+ if (map[fd] != null) {
+ fd2TaskLow = map;
+ }
+ }
+ assertNotNull(fd2TaskLow);
+
+ access.park(-1);
+
+ assertTrue(fd2TaskLow[fd] == null);
+
+ so.close();
+ }
+}
diff --git a/test/com/alibaba/wisp/io/ReuseUdpSocektBufTest.java b/test/com/alibaba/wisp/io/ReuseUdpSocektBufTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..136870fb96afe787f18d38d5bf9a8de53e987e45
--- /dev/null
+++ b/test/com/alibaba/wisp/io/ReuseUdpSocektBufTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test reuse WispUdpSocket buffer
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ReuseUdpSocektBufTest
+ */
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+public class ReuseUdpSocektBufTest {
+
+ static String msgs[] = {"Hello World", "Java", "Good Bye"};
+ static int port;
+
+ static boolean success = true;
+
+ static class ServerThread extends Thread{
+ DatagramSocket ds;
+ public ServerThread() {
+ try {
+ ds = new DatagramSocket();
+ port = ds.getLocalPort();
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ public void run() {
+ byte b[] = new byte[100];
+ DatagramPacket dp = new DatagramPacket(b,b.length);
+ while (true) {
+ try {
+ ds.receive(dp);
+ String reply = new String(dp.getData(), dp.getOffset(), dp.getLength());
+ ds.send(new DatagramPacket(reply.getBytes(),reply.length(),
+ dp.getAddress(),dp.getPort()));
+ if (reply.equals(msgs[msgs.length-1])) {
+ break;
+ }
+ } catch (Exception e) {
+ success = false;
+ }
+ }
+ ds.close();
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+ ServerThread st = new ServerThread();
+ st.start();
+ DatagramSocket ds = new DatagramSocket();
+ byte b[] = new byte[100];
+ DatagramPacket dp = new DatagramPacket(b,b.length);
+ for (int i = 0; i < msgs.length; i++) {
+ ds.send(new DatagramPacket(msgs[i].getBytes(),msgs[i].length(),
+ InetAddress.getLocalHost(),
+ port));
+ ds.receive(dp);
+ if (!msgs[i].equals(new String(dp.getData(), dp.getOffset(), dp.getLength()))) {
+ success = false;
+ }
+ }
+ ds.close();
+ assertTrue(success);
+ System.out.println("Test Passed!!!");
+ }
+}
diff --git a/test/com/alibaba/wisp/io/ShareFdTest.java b/test/com/alibaba/wisp/io/ShareFdTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4afb2d6091f2d0f14ea1205c24f0bae740918b1f
--- /dev/null
+++ b/test/com/alibaba/wisp/io/ShareFdTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test support fd use acorss coroutines
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ShareFdTest
+ */
+
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class ShareFdTest {
+ private static boolean success = true;
+ private static ServerSocket serverSocket = null;
+
+ public static void main(String[] args) {
+ WispEngineAccess wispEngineAccess = SharedSecrets.getWispEngineAccess();
+ assert (wispEngineAccess.enableSocketLock());
+ ShareFdTest shareFdTest = new ShareFdTest();
+ shareFdTest.testAccept();
+ assert success;
+ }
+
+ void testAccept() {
+ try {
+ serverSocket = new ServerSocket();
+ serverSocket.bind(new InetSocketAddress(6402));
+
+ Thread t1 = new TestThread();
+ Thread t2 = new TestThread();
+ t1.start();
+ t2.start();
+
+ Socket s = new Socket();
+ s.connect(new InetSocketAddress(6402));
+
+ Socket s1 = new Socket();
+ s1.connect(new InetSocketAddress(6402));
+ t1.join();
+ t2.join();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ success = false;
+ }
+ assertTrue(success);
+ }
+
+ class TestThread extends Thread {
+ @Override
+ public void run() {
+ blockOnAccept(serverSocket);
+ }
+ }
+
+ static void blockOnAccept(ServerSocket serverSocket) {
+ try {
+ serverSocket.accept();
+ } catch (Exception e) {
+ e.printStackTrace();
+ success = false;
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/io/SocketTest.java b/test/com/alibaba/wisp/io/SocketTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e4fd1991f9e0be3e5c01a62e6404ef759f7e68d
--- /dev/null
+++ b/test/com/alibaba/wisp/io/SocketTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test WispEngine's Socket
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true SocketTest
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+public class SocketTest {
+
+ public static void main(String[] args) throws IOException {
+ System.out.println(mkSocketPair()); // test accept() and connect()
+ testData();
+ testBlock();
+ testCreation();
+ }
+
+ static private void testCreation() throws IOException {
+ int expectionCnt = 0;
+ try {
+ new Socket((Proxy) null);
+ } catch (Exception e) {
+ expectionCnt++;
+ }
+ try {
+ new Socket(Proxy.NO_PROXY);
+ } catch (Exception e) {
+ expectionCnt++;
+ }
+ assertTrue(expectionCnt == 2);
+ new SocketWrapper();
+ assertTrue(expectionCnt == 2);
+ }
+
+ static class SocketWrapper extends Socket {
+ SocketWrapper() throws SocketException {
+ super((SocketImpl)null);
+ }
+ }
+
+ static private void testBlock() throws IOException {
+ List sop = mkSocketPair();
+ new Thread(() -> {
+ try {
+ Socket so = sop.get(0);
+ Thread.sleep(100);
+ so.getOutputStream().write(new byte[2]);
+
+ so.close();
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }).start();
+
+ Socket so = sop.get(1);
+
+ long now = System.currentTimeMillis();
+ if (2 != so.getInputStream().read(new byte[10])) {
+ throw new Error("read error");
+ }
+ if (Math.abs(System.currentTimeMillis() - now - 100) > 5)
+ throw new Error("not wake as expected");
+ }
+
+ static private void testData() throws IOException {
+ List sop = mkSocketPair();
+
+ new Thread(() -> {
+ try {
+ Socket so = sop.get(0);
+ OutputStream os = so.getOutputStream();
+ byte buf[] = new byte[4];
+ ByteBuffer bb = ByteBuffer.wrap(buf);
+ for (int i = 0; i < 10; i++) {
+ bb.clear();
+ bb.putInt(i);
+ os.write(buf);
+ }
+ so.close();
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }).start();
+ Socket so = sop.get(1);
+ InputStream is = so.getInputStream();
+ byte buf[] = new byte[4];
+ ByteBuffer bb = ByteBuffer.wrap(buf);
+ for (int i = 0; true; i++) {
+ bb.clear();
+ if (4 != is.read(buf)) {
+ if (i == 10) {
+ so.close();
+ break; // ok here
+ } else {
+ throw new Error("read error");
+ }
+ }
+ if (bb.getInt() != i)
+ throw new Error("data error");
+ }
+
+ }
+
+ static private List mkSocketPair() throws IOException {
+ ServerSocket ss = new ServerSocket(13000);
+ Socket so = new Socket("localhost", 13000);
+ Socket so1 = ss.accept();
+ ss.close();
+
+ return Arrays.asList(so, so1);
+ }
+}
diff --git a/test/com/alibaba/wisp/io/WispSocketCloseTest.java b/test/com/alibaba/wisp/io/WispSocketCloseTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..115857d14f91af8c2eb0819cda18fd81129ef8a2
--- /dev/null
+++ b/test/com/alibaba/wisp/io/WispSocketCloseTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test close will wake up blocking wispTask
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true WispSocketCloseTest
+ */
+
+import java.io.IOException;
+import java.net.*;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+public class WispSocketCloseTest {
+
+ class Reaper extends Thread {
+ Socket s;
+ int timeout;
+
+ Reaper(Socket s, int timeout) {
+ this.s = s;
+ this.timeout = timeout;
+ }
+
+ public void run() {
+ try {
+ Thread.sleep(timeout);
+ s.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ WispSocketCloseTest() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
+ ss.setSoTimeout(1000);
+
+ InetAddress ia = InetAddress.getLocalHost();
+ InetSocketAddress isa =
+ new InetSocketAddress(ia, ss.getLocalPort());
+
+ // client establishes the connection
+ Socket s1 = new Socket();
+ s1.connect(isa);
+
+ // receive the connection
+ Socket s2 = ss.accept();
+
+ // schedule reaper to close the socket in 5 seconds
+ Reaper r = new Reaper(s2, 5000);
+ r.start();
+
+ boolean readTimedOut = false;
+ try {
+ s2.getInputStream().read();
+ } catch (IOException e) {
+ assertTrue (e instanceof SocketException);
+ assertTrue ("Socket is closed".equals(e.getMessage()));
+ }
+
+ s1.close();
+ ss.close();
+
+ if (readTimedOut) {
+ throw new Exception("Unexpected SocketTimeoutException throw!");
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+ new WispSocketCloseTest();
+ }
+}
diff --git a/test/com/alibaba/wisp/lock/AQSTest.java b/test/com/alibaba/wisp/lock/AQSTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..13c25c5b4f906ca7828fe50974f10941efcb17b6
--- /dev/null
+++ b/test/com/alibaba/wisp/lock/AQSTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test AQS: CountDownLatch is implement by AQS
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true AQSTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+import java.util.concurrent.CountDownLatch;
+
+public class AQSTest {
+ static CountDownLatch cd = new CountDownLatch(1);
+ static CountDownLatch cd2 = new CountDownLatch(1);
+ public static void main(String[] args) {
+ WispEngine.dispatch(() -> {
+ long start = System.currentTimeMillis();
+ try {
+ cd.await();
+ assertInterval(start, 100, 5);
+ } catch (InterruptedException e) {
+ throw new Error();
+ }
+ });
+ WispEngine.dispatch(() -> {
+ long start = System.currentTimeMillis();
+ try {
+ cd2.await();
+ assertInterval(start, 200, 5);
+ } catch (InterruptedException e) {
+ throw new Error();
+ }
+ });
+
+
+ SharedSecrets.getWispEngineAccess().sleep(100);
+ cd.countDown();
+ SharedSecrets.getWispEngineAccess().sleep(100);
+ cd2.countDown();
+ SharedSecrets.getWispEngineAccess().sleep(5);
+ }
+
+ public static void assertInterval(long start, int diff, int bias) {
+ if (Math.abs(System.currentTimeMillis() - start - diff) > bias)
+ throw new Error("not wakeup expected");
+ }
+}
diff --git a/test/com/alibaba/wisp/lock/ElisionSpinTest.java b/test/com/alibaba/wisp/lock/ElisionSpinTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..335f1b74fe7629d25d4f9524695a6aeccd4702c9
--- /dev/null
+++ b/test/com/alibaba/wisp/lock/ElisionSpinTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test elision spin
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.carrierEngines=1 ElisionSpinTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static jdk.testlibrary.Asserts.assertFalse;
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class ElisionSpinTest {
+ public static void main(String[] args) {
+ assertFalse(SharedSecrets.getWispEngineAccess().hasMoreTasks());
+
+ ReentrantLock lock = new ReentrantLock();
+ Condition cond = lock.newCondition();
+
+ WispEngine.dispatch(() -> {
+ lock.lock();
+ try {
+ cond.awaitUninterruptibly();
+ } finally {
+ lock.unlock();
+ }
+ });
+
+ lock.lock();
+ try {
+ cond.signal();
+ } finally {
+ lock.unlock();
+ }
+
+ assertTrue(SharedSecrets.getWispEngineAccess().hasMoreTasks());
+ }
+}
diff --git a/test/com/alibaba/wisp/lock/LockTest.java b/test/com/alibaba/wisp/lock/LockTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..23f9652558808c60339773ed7138691cdf637eff
--- /dev/null
+++ b/test/com/alibaba/wisp/lock/LockTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test ReentrantLock in coroutine environment
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true LockTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class LockTest {
+ static Lock lock = new ReentrantLock();
+ static Condition cond = lock.newCondition();
+
+ static CountDownLatch latch = new CountDownLatch(2);
+
+ public static void main(String[] args) throws Exception {
+ WispEngine.dispatch(LockTest::p1);
+ WispEngine.dispatch(LockTest::p2);
+
+ latch.await(2, TimeUnit.SECONDS);
+ }
+
+ static void assertInterval(long start, int diff, int bias) {
+ if (Math.abs(System.currentTimeMillis() - start - diff) > bias)
+ throw new Error("not wakeup expected");
+ }
+
+ private static void p1() {
+ lock.lock();
+ SharedSecrets.getWispEngineAccess().sleep(100);
+ try {
+ long start = System.currentTimeMillis();
+ cond.await();
+ assertInterval(start, 100, 5);
+
+ } catch (InterruptedException e) {
+ throw new Error();
+ } finally {
+ lock.unlock();
+ }
+ latch.countDown();
+ }
+
+ private static void p2() {
+ long start = System.currentTimeMillis();
+ lock.lock();
+ try {
+ assertInterval(start, 100, 5);
+ SharedSecrets.getWispEngineAccess().sleep(100);
+ cond.signal();
+ } finally {
+ lock.unlock();
+ }
+ latch.countDown();
+ }
+
+
+}
diff --git a/test/com/alibaba/wisp/lock/ParkNanoTest.java b/test/com/alibaba/wisp/lock/ParkNanoTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9495b8b260afa3afabad2f5cfa393ee09d53621d
--- /dev/null
+++ b/test/com/alibaba/wisp/lock/ParkNanoTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test park nanos
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ParkNanoTest
+ */
+
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ParkNanoTest {
+ public static void main(String[] args) throws Exception {
+ doTest(400_000, 300_000);
+ doTest(800_000, 500_000);
+ }
+
+ private static void doTest(long wait, long expected) throws Exception {
+ CountDownLatch l = new CountDownLatch(1);
+ long start = System.nanoTime();
+ l.await(wait, TimeUnit.NANOSECONDS);
+ long diff = System.nanoTime() - start;
+
+ if (diff < expected)
+ throw new Error("wake up too early!");
+ }
+}
diff --git a/test/com/alibaba/wisp/lock/UnsafeParkTest.java b/test/com/alibaba/wisp/lock/UnsafeParkTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..527865fa33362c9f5fad024006960d954c5a20fe
--- /dev/null
+++ b/test/com/alibaba/wisp/lock/UnsafeParkTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test to verify we can do proper wisp scheduling while calling on Unsafe.park()
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true UnsafeParkTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+public class UnsafeParkTest {
+ public static void main(String[] args) throws Exception {
+ Field f = Unsafe.class.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ Unsafe unsafe = (Unsafe) f.get(null);
+
+ AtomicLong awake = new AtomicLong();
+
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ awake.set(System.currentTimeMillis());
+ });
+
+ long start = System.currentTimeMillis();
+
+ unsafe.park(false, 1);
+ unsafe.park(false, TimeUnit.MILLISECONDS.toNanos(500));
+
+ assertTrue(Math.abs(awake.get() - start - 300) < 100,
+ "awake should be set before unsafe.park expired " + awake.get() + " " + start);
+ }
+}
diff --git a/test/com/alibaba/wisp/monitor/C2SyncMethodTest.java b/test/com/alibaba/wisp/monitor/C2SyncMethodTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..129fe75df5cde017704770e218ec3e24f4f8bc55
--- /dev/null
+++ b/test/com/alibaba/wisp/monitor/C2SyncMethodTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test to run a compiled/synchronized method with wisp enabled.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true C2SyncMethodTest
+ */
+public class C2SyncMethodTest {
+ public synchronized static void main(String[] args) {
+ for (int i = 0; i < 1000000; i++) {
+ foo();
+ }
+ }
+
+ static volatile int n = 0;
+
+ synchronized static void foo() {
+ n++;
+ }
+}
diff --git a/test/com/alibaba/wisp/monitor/FinalizerTest.java b/test/com/alibaba/wisp/monitor/FinalizerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6fd784f9a6d2df34f0eb9746fe334aee1679579
--- /dev/null
+++ b/test/com/alibaba/wisp/monitor/FinalizerTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test unpark in a finalizer thread.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true FinalizerTest
+ */
+
+public class FinalizerTest {
+ static final Foo lock = new Foo();
+ public static void main(String[] args) throws Exception {
+ new Foo();
+ new Thread(() -> {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.gc();
+ System.runFinalization();
+ }, "call-System.gc()").start();
+ synchronized (lock) {
+ lock.wait();
+ }
+ System.out.println(Thread.currentThread().getName() + ": wait done");
+ }
+
+ static class Foo {
+ @Override
+ protected void finalize() throws Throwable {
+ synchronized (lock) {
+ lock.notify();
+ }
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/monitor/JNICriticalTest.java b/test/com/alibaba/wisp/monitor/JNICriticalTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bbbde339d818a5d7eadf6991f313e215e94ea67
--- /dev/null
+++ b/test/com/alibaba/wisp/monitor/JNICriticalTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test unpark in JNI critical case
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true JNICriticalTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.IntStream;
+import java.util.zip.Deflater;
+
+public class JNICriticalTest {
+ public static void main(String[] args) throws Exception {
+ CountDownLatch latch = new CountDownLatch(16);
+ AtomicInteger id = new AtomicInteger();
+ ExecutorService es = Executors.newCachedThreadPool(r -> {
+ Thread t = new Thread(r);
+ t.setName("JNICriticalTest" + id.getAndIncrement());
+ return t;
+ });
+ IntStream.range(0, 4).forEach(ign -> es.execute(() -> {
+ Deflater d = new Deflater();
+ AtomicInteger n = new AtomicInteger();
+ for (int i = 0; i < 4; i++) {
+ WispEngine.dispatch(() -> {
+ while (n.get() < 1_000_000) {
+ jniCritical(d);
+ if (n.incrementAndGet() % 100000 == 0) {
+ System.out.println(SharedSecrets.getJavaLangAccess().currentThread0().getName() + "/" + n.get() / 1000 +"k");
+ }
+ }
+ latch.countDown();
+ });
+ }
+ }));
+ latch.await();
+ }
+
+
+ private static void jniCritical(Deflater d) {
+ d.reset();
+ d.setInput(bs);
+ d.finish();
+ byte[] out = new byte[4096 * 4];
+
+ d.deflate(out); // Enter the JNI critical block here.
+ }
+
+ static byte[] bs = new byte[12];
+}
diff --git a/test/com/alibaba/wisp/monitor/LazyUnparkBugTest.java b/test/com/alibaba/wisp/monitor/LazyUnparkBugTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7173946a5a4eb4095aff6b4382d6d897c9bd165a
--- /dev/null
+++ b/test/com/alibaba/wisp/monitor/LazyUnparkBugTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary T12212948
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true LazyUnparkBugTest
+ */
+
+public class LazyUnparkBugTest {
+ private static volatile Object thunk = null;
+
+ public static void test() throws Exception {
+ thunk = null;
+ Thread t1 = new Thread(() -> {
+ try {
+ synchronized (LazyUnparkBugTest.class) {
+ Thread.sleep(1_000L);
+ }
+ Object o;
+ do {
+ o = thunk;
+ } while (o == null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+
+ Thread t2 = new Thread(() -> {
+ try {
+ Thread.sleep(5_0L);
+ synchronized (LazyUnparkBugTest.class) {
+ System.out.println("in t2");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ thunk = new Object();
+ });
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+ }
+
+ public static void main(String[] args) throws Exception {
+ long begin = System.currentTimeMillis();
+ test();
+ long end = System.currentTimeMillis();
+ System.out.println("cost : " + (end - begin) + " ms");
+ if ((end - begin) > 2000) {
+ throw new Error("this is bug " + (end - begin));
+ }
+ }
+
+}
diff --git a/test/com/alibaba/wisp/monitor/PassTokenTest.java b/test/com/alibaba/wisp/monitor/PassTokenTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4257627557916b121a11a054f4d66b531309d286
--- /dev/null
+++ b/test/com/alibaba/wisp/monitor/PassTokenTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test object lock with coroutine
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.schedule.policy=PULL PassTokenTest
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.schedule.policy=PUSH PassTokenTest
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -DcheckStealEnable=true PassTokenTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class PassTokenTest {
+ private final static boolean needCheckStealEnable = Boolean.getBoolean("checkStealEnable");
+ final static Runner[] runners = new Runner[8];
+ static boolean JUC;
+ static final int N = 40000;
+
+ public static void main(String[] args) throws Exception {
+ JUC = true;
+ System.out.println("JUC");
+ doTest();
+ JUC = false;
+ System.out.println("ObjectMonitor");
+ doTest();
+ }
+
+ private static void doTest() {
+ for (int i = 0; i < runners.length; i++) {
+ runners[i] = new Runner(i);
+ }
+ List plans = new ArrayList<>(Arrays.asList(
+ () -> { // only coroutine
+ for (Runner runner1 : runners) {
+ WispEngine.dispatch(runner1);
+ }
+ },
+ () -> { // only thread
+ int n = 0;
+ for (Runner runner : runners) {
+ new Thread(runner, "MP-THREAD-RUNNER-" + n++).start();
+ }
+ },
+ () -> { //mixed
+ int n = 0;
+ for (int i = 0; i < runners.length; i += 2) {
+ final int ci = i;
+ new Thread(() -> {
+ for (int j = ci; j < ci + 2 && j < runners.length; j++) {
+ WispEngine.dispatch(runners[j]);
+ }
+ }, "MP-MIX-RUNNER-" + n++).start();
+ }
+ }));
+ Collections.shuffle(plans);
+
+ plans.forEach(plan -> {
+ finishLatch = new CountDownLatch(runners.length);
+ current = 0;
+ long start = System.currentTimeMillis();
+ plan.run(); // create runners
+ try {
+ finishLatch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ System.out.println("elapsed = " + (System.currentTimeMillis() - start) + "ms");
+ });
+
+ System.out.println("-----------");
+ }
+
+
+ static int current = 0;
+ static final Lock lock = new ReentrantLock();
+ static final Condition cond = lock.newCondition();
+ static CountDownLatch finishLatch;
+
+ static class Runner implements Runnable {
+
+ private final int ord;
+
+ public Runner(int ord) {
+ this.ord = ord;
+ }
+
+ @Override
+ public void run() {
+ WispTask task = SharedSecrets.getWispEngineAccess().getCurrentTask();
+
+ while (current < N) {
+ if (JUC) {
+ lock.lock();
+ try {
+ while (current % runners.length != ord) {
+ try {
+ cond.await();
+ checkStealEnable(task);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ if (++current % 10000 == 0) // pass the token
+ System.out.println(SharedSecrets.getJavaLangAccess().currentThread0().getName() + "\t" + current);
+ } finally {
+ lock.unlock();
+ }
+ } else {
+ synchronized (lock) {
+ while (current % runners.length != ord) {
+ try {
+ lock.wait();
+ checkStealEnable(task);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ if (++current % 10000 == 0) // pass the token
+ System.out.println(SharedSecrets.getJavaLangAccess().currentThread0().getName() + "\t" + current);
+ }
+ }
+
+ if (JUC) {
+ lock.lock();
+ try {
+ cond.signalAll();
+ } finally {
+ lock.unlock();
+ }
+ } else {
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+ }
+
+ finishLatch.countDown();
+ }
+
+ static void checkStealEnable(WispTask task) {
+ if (!needCheckStealEnable) {
+ return;
+ }
+ try {
+ Field resumeEntryField = task.getClass().getDeclaredField("resumeEntry");
+ resumeEntryField.setAccessible(true);
+ final Object resumeEntry = resumeEntryField.get(task);
+ if (resumeEntry == null) {
+ return;
+ }
+ Field stealEnableField = resumeEntry.getClass().getDeclaredField("stealEnable");
+ stealEnableField.setAccessible(true);
+ assertTrue(stealEnableField.getBoolean(resumeEntry));
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp/monitor/SynchronizedTest.java b/test/com/alibaba/wisp/monitor/SynchronizedTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a542011cac1d54b7518b758bf58c08c1c72b0bcb
--- /dev/null
+++ b/test/com/alibaba/wisp/monitor/SynchronizedTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Basic test for java primitive lock(synchronized)
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true SynchronizedTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+public class SynchronizedTest {
+ public static void main(String[] args) {
+
+ SynchronizedTest s = new SynchronizedTest();
+ WispEngine.dispatch(s::foo);
+ WispEngine.dispatch(s::bar);
+ }
+
+ private synchronized void foo() {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private synchronized void bar() {
+ }
+}
diff --git a/test/com/alibaba/wisp/monitor/WispExitTest.java b/test/com/alibaba/wisp/monitor/WispExitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3adfcadc84cdc9d90335ef3c646f18b9403c57bb
--- /dev/null
+++ b/test/com/alibaba/wisp/monitor/WispExitTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Ensure we can exit vm when -XX:+UseWispMonitor
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true WispExitTest
+ */
+public class WispExitTest {
+ public static void main(String[] args) throws Exception {
+
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/DaemonTest.java b/test/com/alibaba/wisp/thread/DaemonTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a326c7684d1fd74894aa117be77939b191a04729
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/DaemonTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+import static jdk.testlibrary.Asserts.*;
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test thread as wisp still keep the daemon semantic
+ * @requires os.family == "linux"
+ * @run main DaemonTest
+ */
+public class DaemonTest {
+
+ private static final String SHUTDOWN_MSG = "[Run ShutdownHook]";
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 0) {
+ driver(true); // test daemon will not prevent shutdown
+ driver(false); // test non-daemon will prevent shutdown
+ } else {
+ assert Thread.currentThread().getName().equals("main");
+ boolean daemon = Boolean.valueOf(args[0]);
+
+ // start a non-daemon to cover the `--nonDaemonCount == 0` branch
+ Thread thread = new Thread(() -> {/**/});
+ thread.setDaemon(false);
+ thread.start();
+
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println(SHUTDOWN_MSG)));
+ thread = new Thread(() -> {
+ System.out.println("thread started..");
+ if (!daemon) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ thread.setDaemon(daemon);
+ thread.start();
+ Thread.sleep(1000);
+ }
+ }
+
+ private static void driver(boolean daemon) throws Exception {
+ // we can not use jdk.testlibrary.ProcessTools here, because we need to analyse stdout of a unfinished process
+ Process process = new ProcessBuilder(System.getProperty("java.home") + "/bin/java",
+ "-XX:+UseWisp2", "-cp", System.getProperty("java.class.path"), DaemonTest.class.getName(), Boolean.toString(daemon)).start();
+ Thread.sleep(2000);
+ byte[] buffer = new byte[1024];
+ int n = process.getInputStream().read(buffer);
+ String s = new String(buffer, 0, n);
+ assertEQ(daemon, s.contains(SHUTDOWN_MSG));
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/DaemonThreadGroupTest.java b/test/com/alibaba/wisp/thread/DaemonThreadGroupTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfbe390b6731c4742d6a4e4e9dac9ab044599027
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/DaemonThreadGroupTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test Daemon Thread Group implementation
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.useCarrierAsPoller=false DaemonThreadGroupTest
+*/
+
+
+import java.lang.reflect.Field;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+/**
+ * test the Daemon Thread Group implementation
+ */
+public class DaemonThreadGroupTest {
+ public static void main(String... arg) throws Exception {
+ Field f = Class.forName("com.alibaba.wisp.engine.WispEngine").getDeclaredField("unparkDispatcher");
+ f.setAccessible(true);
+ Thread t = (Thread) f.get(null);
+
+ f = Class.forName("com.alibaba.wisp.engine.WispEngine").getDeclaredField("DAEMON_THREAD_GROUP");
+ f.setAccessible(true);
+ ThreadGroup threadGroup = (ThreadGroup) f.get(null);
+
+ System.out.println(threadGroup.getName());
+
+ assertTrue(t.getThreadGroup() == threadGroup, "the thread isn't in daemonThreadGroup");
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/DisableThreadAsWispAtRuntimeTest.java b/test/com/alibaba/wisp/thread/DisableThreadAsWispAtRuntimeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..91f40479465364b41f6cd4b8d3336952ff921e4d
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/DisableThreadAsWispAtRuntimeTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary this feature is not supported in wisp2, just check compatibility
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true DisableThreadAsWispAtRuntimeTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.lang.reflect.Field;
+
+import static jdk.testlibrary.Asserts.assertEQ;
+
+public class DisableThreadAsWispAtRuntimeTest {
+
+
+ public static void main(String[] args) throws Exception {
+ switchShift(true);
+ switchShift(false);
+ }
+
+ private static void switchShift(boolean val) {
+ try {
+ Class> wispClazz = Class.forName("com.alibaba.wisp.engine.WispEngine");
+ Field field = wispClazz.getDeclaredField("shiftThreadModel");
+ field.setAccessible(true);
+ field.setBoolean(null /*static field*/, val);
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ assertEQ(WispEngine.enableThreadAsWisp(), val);
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/EngineExecutorTest.java b/test/com/alibaba/wisp/thread/EngineExecutorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd4442ce96e68ed534197821402f18ee1a2a330d
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/EngineExecutorTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test submit task to engine.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true EngineExecutorTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class EngineExecutorTest {
+ public static void main(String[] args) throws Exception {
+ testExecutor();
+ }
+
+ static AtomicReference engine = new AtomicReference<>();
+ private static void testExecutor() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ Thread t = new Thread(() -> {
+ engine.set(WispEngine.current());
+ latch.countDown();
+ while (true) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ t.start();
+ latch.await();
+ WispEngine e = engine.get();
+ CountDownLatch latch1 = new CountDownLatch(100);
+ for (int i = 0; i < 100; i++) {
+ e.execute(latch1::countDown);
+ }
+ assertTrue(latch1.await(1, TimeUnit.SECONDS));
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/InterruptTest.java b/test/com/alibaba/wisp/thread/InterruptTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..16ed42b6891b06a495a929dfc62fe04d6f0eaa52
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/InterruptTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test thread.interrupt() of wispTask
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true InterruptTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.CountDownLatch;
+
+public class InterruptTest {
+ public static void main(String[] args) throws Exception {
+ Lock lock = new ReentrantLock();
+ Condition dummy = lock.newCondition();
+ Condition finish = lock.newCondition();
+ Condition threadSet = lock.newCondition();
+ CountDownLatch finishLatch = new CountDownLatch(1);
+
+ AtomicBoolean interrupted = new AtomicBoolean(false);
+ AtomicReference thrd = new AtomicReference<>();
+
+ WispEngine.dispatch(() -> {
+ thrd.set(Thread.currentThread());
+ lock.lock();
+ finishLatch.countDown();
+ threadSet.signal();
+ try {
+ try {
+ dummy.await(1, TimeUnit.SECONDS);
+ throw new Error("Exception not happened");
+ } catch (InterruptedException e) {
+ interrupted.set(true);
+ }
+ } finally {
+ finish.signal();
+ lock.unlock();
+ }
+ });
+
+ finishLatch.await();
+ lock.lock();
+ try {
+ if (thrd.get() == null && !threadSet.await(1, TimeUnit.SECONDS))
+ throw new Error("wait threadSet");
+ } finally {
+ lock.unlock();
+ }
+
+ if (thrd.get() == null)
+ throw new Error("thread not set");
+
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ thrd.get().interrupt();
+
+ lock.lock();
+ try {
+ if (!finish.await(1, TimeUnit.SECONDS))
+ throw new Error("wait finish");
+ } finally {
+ lock.unlock();
+ }
+
+ if (!interrupted.get())
+ throw new Error("InterruptedException not happened");
+
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/InterruptedSleepTest.java b/test/com/alibaba/wisp/thread/InterruptedSleepTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1deb7eb47a9fb3649323b023413b66ce86e92e7d
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/InterruptedSleepTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test InterruptedException was thrown by sleep()
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true InterruptedSleepTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import static jdk.testlibrary.Asserts.assertFalse;
+import static jdk.testlibrary.Asserts.assertLessThan;
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class InterruptedSleepTest {
+ public static void main(String[] args) {
+ Thread mainCoro = Thread.currentThread();
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ mainCoro.interrupt();
+ });
+ long start = System.currentTimeMillis();
+ boolean ie = false;
+ try {
+ Thread.sleep(1000L);
+ } catch (InterruptedException e) {
+ ie = true;
+ }
+ assertLessThan((int) (System.currentTimeMillis() - start), 1000);
+ assertTrue(ie);
+ assertFalse(mainCoro.isInterrupted());
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/IsAliveTest.java b/test/com/alibaba/wisp/thread/IsAliveTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..827b06b2078fff0f2c5328524cc43e8fa9ebe635
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/IsAliveTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test thread.isAlive() of wispTask
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true IsAliveTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static jdk.testlibrary.Asserts.assertFalse;
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+public class IsAliveTest {
+ public static void main(String[] args) throws Exception {
+ AtomicBoolean isAlive = new AtomicBoolean();
+ AtomicReference t = new AtomicReference<>();
+ final CountDownLatch cond = new CountDownLatch(1);
+
+ WispEngine.dispatch(() -> {
+ t.set(Thread.currentThread());
+ isAlive.set(t.get().isAlive());
+ cond.countDown();
+ });
+ try {
+ cond.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ assertTrue(isAlive.get());
+ assertFalse(t.get().isAlive());
+ }
+}
diff --git a/test/com/alibaba/wisp/thread/PreemptTest.java b/test/com/alibaba/wisp/thread/PreemptTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ece050c355183188b843b3ee54cfbfc03cd950a
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/PreemptTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test wisp time slice preempt
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.carrierEngines=1 PreemptTest
+
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class PreemptTest {
+ public static void main(String[] args) throws Exception {
+ doTest(PreemptTest::simpleLoop);
+ }
+
+ private static void doTest(Runnable r) throws Exception {
+ WispEngine.dispatch(r);
+ CountDownLatch latch = new CountDownLatch(1);
+ WispEngine.dispatch(latch::countDown);
+ assertTrue(latch.await(5, TimeUnit.SECONDS));
+ }
+
+ private static void complexLoop() {
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new Error(e);
+ }
+
+ while (true) {
+ md.update("welcome to the wisp world!".getBytes());
+ n = md.digest()[0];
+ }
+ }
+
+ private static void simpleLoop() {
+ int x;
+ do {
+ x = n;
+ } while (x == n);
+ }
+
+ // TODO: handle safepoint consumed by state switch
+
+ volatile static int n;
+}
diff --git a/test/com/alibaba/wisp/thread/ThrowErrorTest.java b/test/com/alibaba/wisp/thread/ThrowErrorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2402eab260e2e4fe185d4af8a8e72e8503deb75a
--- /dev/null
+++ b/test/com/alibaba/wisp/thread/ThrowErrorTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test coroutine throw Error
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true ThrowErrorTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class ThrowErrorTest {
+ public static void main(String[] args) {
+ WispEngine.dispatch(() -> {
+ throw new Error();
+ });
+
+ boolean[] executed = new boolean[]{false};
+
+ WispEngine.dispatch(() -> executed[0] = true);
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ assertTrue(executed[0]);
+ }
+}
diff --git a/test/com/alibaba/wisp/timer/OverflowTest.java b/test/com/alibaba/wisp/timer/OverflowTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..63e4741e7ef3bf94275dbf18ea78b11c0139ec41
--- /dev/null
+++ b/test/com/alibaba/wisp/timer/OverflowTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test timer implementation
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine OverflowTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+
+/**
+ * test the time out implementation
+ */
+public class OverflowTest {
+ public static void main(String... arg) throws Exception {
+
+ WispEngineAccess access = SharedSecrets.getWispEngineAccess();
+
+ AtomicReference task1 = new AtomicReference<>();
+ AtomicBoolean doUnpark = new AtomicBoolean(false);
+ AtomicBoolean hasError = new AtomicBoolean(false);
+
+ WispEngine.dispatch(() -> {
+ task1.set(access.getCurrentTask());
+ access.park(Long.MAX_VALUE);
+ // if timeout is negative(< now()), this task is selected in doSchedule
+ // and park returns immediately
+ hasError.set(!doUnpark.get()); // should not reach here before doing unpark
+ });
+
+ access.sleep(100); // switch task
+ // let task exit
+ doUnpark.set(true);
+ access.unpark(task1.get());
+ assertTrue(!hasError.get(), "hasError.get() should be false.");
+ }
+}
diff --git a/test/com/alibaba/wisp/timer/PriorityQueueSortTest.java b/test/com/alibaba/wisp/timer/PriorityQueueSortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb7276ba50ea8236a5d04eea634a94de9c6657f6
--- /dev/null
+++ b/test/com/alibaba/wisp/timer/PriorityQueueSortTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Test TimeOut.Queue's offer and remove function, make sure it's consistent with the behavior of the jdk's priority queue
+ * @requires os.family == "linux"
+ * @run main/othervm PriorityQueueSortTest
+ */
+
+import com.alibaba.wisp.engine.TimeOut;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class PriorityQueueSortTest {
+
+ static Class> classQ;
+ static Class> classT;
+
+ static Method poll = null;
+ static Method offer = null;
+
+ static TimeOut ILLEGAL_FLAG = new TimeOut(null, 1, false);
+
+ static class MyComparator implements Comparator {
+ public int compare(TimeOut x, TimeOut y) {
+ return Long.compare(getDeadNano(x), getDeadNano(y));
+ }
+ }
+
+ static Long getDeadNano(TimeOut t) {
+ try {
+ Field deadline = TimeOut.class.getDeclaredField("deadlineNano");
+ deadline.setAccessible(true);
+ return (Long) deadline.get(t);
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ static Object getTimerQueue() {
+ try {
+ classQ = Class.forName("com.alibaba.wisp.engine.TimeOut$TimerManager$Queue");
+ classT = Class.forName("com.alibaba.wisp.engine.TimeOut$TimerManager");
+ Constructor c1 = classQ.getDeclaredConstructor();
+ c1.setAccessible(true);
+ Constructor c2 = classT.getDeclaredConstructor();
+ c2.setAccessible(true);
+ poll = classQ.getDeclaredMethod("poll");
+ poll.setAccessible(true);
+ offer = classQ.getDeclaredMethod("offer", TimeOut.class);
+ offer.setAccessible(true);
+ return c1.newInstance();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ static boolean add(Object pq, TimeOut timeOut) {
+ try {
+ offer.invoke(pq, timeOut);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ static TimeOut poll(Object pq) {
+ try {
+ return (TimeOut)poll.invoke(pq);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return ILLEGAL_FLAG;
+ }
+ }
+
+ public static void main(String[] args) {
+ int n = 10000;
+
+ List sorted = new ArrayList<>(n);
+ for (int i = 0; i < n; i++)
+ sorted.add(new Long(i));
+ List shuffled = new ArrayList<>(sorted);
+ Collections.shuffle(shuffled);
+
+ Object pq = getTimerQueue();
+
+
+ for (Iterator i = shuffled.iterator(); i.hasNext(); )
+ add(pq, new TimeOut(null, i.next(), false));
+
+ List recons = new ArrayList<>();
+
+ while (true) {
+ TimeOut t = poll(pq);
+ if (t == null) {
+ break;
+ }
+ recons.add(getDeadNano(t));
+ }
+ assertTrue(recons.equals(sorted), "Sort failed");
+
+ for (Long val : recons) {
+ add(pq, new TimeOut(null, val, false));
+ }
+ recons.clear();
+ while(true){
+ TimeOut timeOut = poll(pq);
+ if (timeOut == null) {
+ break;
+ }
+ if(getDeadNano(timeOut) % 2 == 1) {
+ recons.add(getDeadNano(timeOut));
+ }
+ }
+
+ Collections.sort(recons);
+
+ for (Iterator i = sorted.iterator(); i.hasNext(); )
+ if ((i.next().intValue() % 2) != 1)
+ i.remove();
+
+ assertTrue(recons.equals(sorted), "Odd Sort failed");
+ }
+}
diff --git a/test/com/alibaba/wisp/timer/SleepRPCTest.java b/test/com/alibaba/wisp/timer/SleepRPCTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4c38f3bdc22834d3840ed1d4f14ce6ec4b43a3c
--- /dev/null
+++ b/test/com/alibaba/wisp/timer/SleepRPCTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test use sleep in RPC senorina
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true SleepRPCTest
+ * @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.highPrecisionTimer=true SleepRPCTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class SleepRPCTest {
+ public static void main(String[] args) {
+
+ List> rpcs = IntStream.range(0, 50).mapToObj(i -> {
+ AtomicBoolean done = new AtomicBoolean(false);
+ FutureTask ft = new FutureTask<>(() -> {
+ for (int n = 0; !done.get() && n < 40; n++) {
+ Thread.sleep(5);
+ } // 200 ms timeout
+ return done.get();
+ });
+ WispEngine.dispatch(ft);
+ WispEngine.dispatch(new FutureTask<>(() -> {
+ Thread.sleep(new Random().nextInt(100) + 1);
+ done.set(true);
+ return 0;
+ }));
+
+ return ft;
+ }).collect(Collectors.toList());
+
+ assertTrue(rpcs.stream().allMatch(ft -> {
+ try {
+ return ft.get(1, TimeUnit.SECONDS);
+ } catch (Throwable e) {
+ return false;
+ }
+ }));
+ }
+}
diff --git a/test/com/alibaba/wisp/timer/SleepTest.java b/test/com/alibaba/wisp/timer/SleepTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..33e15bf2a8ae6ca7b050b2aabdf995c2e65cfd13
--- /dev/null
+++ b/test/com/alibaba/wisp/timer/SleepTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test sleep
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true SleepTest
+ * @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.highPrecisionTimer=true SleepTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class SleepTest {
+ public static void main(String[] args) {
+ assertTrue(IntStream.range(0, 100).parallel().allMatch(ms -> {
+ long start = System.currentTimeMillis();
+ FutureTask ft = new FutureTask<>(() -> {
+ Thread.sleep(ms);
+ return 0;
+ });
+ WispEngine.dispatch(ft);
+ try {
+ ft.get(200, TimeUnit.MILLISECONDS);
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+
+ long interval = System.currentTimeMillis() - start;
+
+ if (Math.abs(interval - ms) < 100) {
+ return true;
+ } else {
+ System.out.println("ms = " + ms);
+ System.out.println("interval = " + interval);
+ return false;
+ }
+ }));
+ }
+}
diff --git a/test/com/alibaba/wisp/timer/TimerTest.java b/test/com/alibaba/wisp/timer/TimerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..42b0de9b5ed96f1bca6fdfe0ccd6894c83b40b70
--- /dev/null
+++ b/test/com/alibaba/wisp/timer/TimerTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test timer implement
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine TimerTest
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.highPrecisionTimer=true TimerTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * test the time out implement
+ */
+public class TimerTest {
+ public static void main(String... arg) throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ WispEngine.dispatch(() -> {
+ long ts = System.currentTimeMillis();
+ for (int i = 0; i < 10; i++) {
+ SharedSecrets.getWispEngineAccess().sleep(100);
+ long now = System.currentTimeMillis();
+ if (Math.abs(now - ts - 100) > 10)
+ throw new Error();
+ ts = now;
+ }
+ latch.countDown();
+ });
+ latch.await(5, TimeUnit.SECONDS);
+ }
+}
diff --git a/test/com/alibaba/wisp2/AdjustCarrierTest.java b/test/com/alibaba/wisp2/AdjustCarrierTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..241d89424dde03bfaad7767ab0f1251777c7391e
--- /dev/null
+++ b/test/com/alibaba/wisp2/AdjustCarrierTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test for adjusting carrier number at runtime
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.growCarrierTickUs=200000 AdjustCarrierTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class AdjustCarrierTest {
+ public static void main(String[] args) throws Exception {
+ Thread.currentThread().setName("Wisp-Sysmon");
+ Class> claz = Class.forName("com.alibaba.wisp.engine.WispScheduler");
+ Method method = claz.getDeclaredMethod("checkAndGrowWorkers", int.class);
+ method.setAccessible(true);
+ ExecutorService g = WispEngine.createEngine(4, Thread::new);
+
+ CountDownLatch latch = new CountDownLatch(100);
+ CountDownLatch grow = new CountDownLatch(1);
+
+ for (int i = 0; i < 50; i++) {
+ g.execute(() -> {
+ try {
+ grow.await();
+ latch.countDown();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ Field scheduler = Class.forName("com.alibaba.wisp.engine.WispEngine").getDeclaredField("scheduler");
+ scheduler.setAccessible(true);
+ method.invoke(scheduler.get(g), 100);
+ grow.countDown();
+
+ for (int i = 0; i < 50; i++) {
+ g.execute(latch::countDown);
+ }
+
+ latch.await();
+ Field f = claz.getDeclaredField("workers");
+ f.setAccessible(true);
+ System.out.println(f.get(scheduler.get(g)).getClass().toString());
+ assertTrue(((Object[]) (f.get(scheduler.get(g)))).length == 100);
+ Field name = Class.forName("com.alibaba.wisp.engine.WispSysmon").getDeclaredField("WISP_SYSMON_NAME");
+ name.setAccessible(true);
+ assertTrue(name.get(null).equals("Wisp-Sysmon"));
+ }
+}
diff --git a/test/com/alibaba/wisp2/AllThreadAsWispTest.java b/test/com/alibaba/wisp2/AllThreadAsWispTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..45d526d44a8da13404c65cbef99130c029e0c55d
--- /dev/null
+++ b/test/com/alibaba/wisp2/AllThreadAsWispTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary convert all thread to wisp
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor -Dcom.alibaba.wisp.enableThreadAsWisp=true -Dcom.alibaba.wisp.allThreadAsWisp=true AllThreadAsWispTest
+ */
+
+import sun.misc.SharedSecrets;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class AllThreadAsWispTest {
+ public static void main(String[] args) throws Exception {
+ CountDownLatch done = new CountDownLatch(60);
+
+ Runnable r = () -> {
+ if (SharedSecrets.getJavaLangAccess().currentThread0() != Thread.currentThread()) {
+ done.countDown();
+ }
+ };
+
+ for (int i = 0; i < 10; i++) {
+ Executors.newSingleThreadExecutor().submit(r);
+ Executors.newWorkStealingPool().submit(r);
+ Executors.newScheduledThreadPool(100).submit(r);
+ new Thread(r).start();
+ new Timer().schedule(new TimerTask() {
+ @Override
+ public void run() {
+ r.run();
+ }
+ }, 0);
+ new Thread() {
+ @Override
+ public void run() {
+ r.run();
+ }
+ }.start();
+ }
+
+ assertTrue(done.await(10, TimeUnit.SECONDS));
+ }
+}
diff --git a/test/com/alibaba/wisp2/CarrierAsPollerTest.java b/test/com/alibaba/wisp2/CarrierAsPollerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..be9922c563da3ed7fe35aeabebd5b02329abed6e
--- /dev/null
+++ b/test/com/alibaba/wisp2/CarrierAsPollerTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary verify carrier is doing epoll instead of poller when useCarrierAsPoller is enabled
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.useCarrierAsPoller=true CarrierAsPollerTest
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.useCarrierAsPoller=false CarrierAsPollerTest
+ */
+
+
+import java.lang.reflect.Field;
+
+import static jdk.testlibrary.Asserts.*;
+
+public class CarrierAsPollerTest {
+ public static void main(String[] args) throws Exception {
+ new Thread(() -> {}).start(); // if we're owner..let another carrier become owner
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() - start < 200) {
+ // wait acquire
+ }
+
+ Class> clazz = Class.forName("com.alibaba.wisp.engine.WispEventPump$Pool");
+ Field pumps = clazz.getDeclaredField("pumps");
+ pumps.setAccessible(true);
+ Object[] a = (Object[]) pumps.get(clazz.getEnumConstants()[0]);
+ Field ownerField = Class.forName("com.alibaba.wisp.engine.WispEventPump").getDeclaredField("owner");
+ ownerField.setAccessible(true);
+ Object owner = ownerField.get(a[0]);
+ if (!Boolean.getBoolean("com.alibaba.wisp.useCarrierAsPoller")) {
+ assertNull(owner);
+ return;
+ }
+
+ assertNotNull(owner);
+ Field threadField = owner.getClass().getDeclaredField("thread");
+ threadField.setAccessible(true);
+ Thread thread = (Thread) threadField.get(owner);
+ System.out.println(thread.getName());
+ assertTrue(thread.getName().startsWith("Wisp-Root-Worker"));
+ }
+}
diff --git a/test/com/alibaba/wisp2/CtxClassLoaderInheritanceTest.java b/test/com/alibaba/wisp2/CtxClassLoaderInheritanceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3830d96c087962f7a95eb8b0fdf49e2aa8c54c6
--- /dev/null
+++ b/test/com/alibaba/wisp2/CtxClassLoaderInheritanceTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test context ClassLoader inherit.
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor -Dcom.alibaba.wisp.enableThreadAsWisp=true -Dcom.alibaba.wisp.allThreadAsWisp=true CtxClassLoaderInheritanceTest
+ */
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static jdk.testlibrary.Asserts.assertEQ;
+
+public class CtxClassLoaderInheritanceTest {
+ public static void main(String[] args) throws Exception {
+ ClassLoader cl = new ClassLoader() {
+ };
+
+ Thread.currentThread().setContextClassLoader(cl);
+ ClassLoader[] childCtxCl = new ClassLoader[1];
+ CountDownLatch done = new CountDownLatch(1);
+ new Thread(() -> {
+ childCtxCl[0] = Thread.currentThread().getContextClassLoader();
+ done.countDown();
+ }).start();
+
+ done.await(1, TimeUnit.SECONDS);
+ assertEQ(cl, childCtxCl[0]);
+ }
+}
diff --git a/test/com/alibaba/wisp2/DispatchTest.java b/test/com/alibaba/wisp2/DispatchTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..97a8d5787e0670111e1de1692e59246725d7b701
--- /dev/null
+++ b/test/com/alibaba/wisp2/DispatchTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary basic wisp2
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor DispatchTest
+ */
+
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+
+public class DispatchTest {
+ public static void main(String[] args) throws Exception {
+ WispEngine.dispatch(() -> {
+ for (int i = 0; i < 9999999; i++) {
+ try {
+ Thread.sleep(100);
+ System.out.println(i + ": " + SharedSecrets.getJavaLangAccess().currentThread0());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ System.out.println("DispatchTest.main");
+ Thread.sleep(1000);
+ }
+}
diff --git a/test/com/alibaba/wisp2/EpollWakeupPerfTest.java b/test/com/alibaba/wisp2/EpollWakeupPerfTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1cfc88aa99e337f346f3f904388795b38356db74
--- /dev/null
+++ b/test/com/alibaba/wisp2/EpollWakeupPerfTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test selector.wakeup() performance
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+UseWisp2 EpollWakeupPerfTest
+ */
+
+import java.nio.channels.Selector;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class EpollWakeupPerfTest {
+ public static void main(String[] args) throws Exception {
+ Selector selector = Selector.open();
+ AtomicLong wakenedTs = new AtomicLong();
+ CyclicBarrier barrier = new CyclicBarrier(2);
+
+ Thread io = new Thread(() -> {
+ try {
+ while (true) {
+ barrier.await();
+ selector.select();
+ wakenedTs.lazySet(System.nanoTime());
+ synchronized (lock) {
+ lock.notify();
+ }
+ }
+
+ } catch (Throwable t) {
+ }
+ }, "IO thread");
+
+ io.start();
+
+ Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
+ System.out.println("tested " + k + " times, " +
+ "average latency=" + m + "ns");
+ synchronized (lock) {
+ m = k = 0;
+ }
+ }, 1, 1, TimeUnit.SECONDS);
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() - start < 3_000) {
+ wakenedTs.set(0);
+ selector.selectNow(); // reset
+ barrier.await(); // start...
+ new CountDownLatch(1).await(100, TimeUnit.MICROSECONDS); // ensure select()
+ long wakeupTs = System.nanoTime();
+ selector.wakeup();
+
+ synchronized (lock) {
+ while (wakenedTs.get() == 0) {
+ lock.wait();
+ }
+ }
+ long latency = wakenedTs.get() - wakeupTs;
+ if (latency > 0) {
+ synchronized (lock) {
+ m += k++ == 0 ? latency : (latency - m) / k;
+ }
+ }
+ }
+ }
+
+ private static long m, k;
+ private final static Object lock = new Object();
+}
diff --git a/test/com/alibaba/wisp2/HandOffTest.java b/test/com/alibaba/wisp2/HandOffTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bddca16d88e0a16d684cafec4529e5bef8ea12a7
--- /dev/null
+++ b/test/com/alibaba/wisp2/HandOffTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test long running or blocking syscall task could be retaken
+ * @requires os.family == "linux"
+ * @run main/othervm -Dcom.alibaba.wisp.carrierEngines=1 -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -Dcom.alibaba.wisp.enableHandOff=true -Dcom.alibaba.wisp.handoffPolicy=ADAPTIVE -Dcom.alibaba.wisp.sysmonTickUs=100000 HandOffTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+import sun.misc.SharedSecrets;
+import sun.misc.WispEngineAccess;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.InetSocketAddress;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class HandOffTest {
+ private static WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
+
+ static Properties p;
+ static String socketAddr;
+ static {
+ p = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+ );
+ socketAddr = (String)p.get("test.wisp.socketAddress");
+ if (socketAddr == null) {
+ socketAddr = "www.example.com";
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ CountDownLatch cl = new CountDownLatch(10);
+ for (int i = 0; i < 10; i++) {
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ cl.countDown();
+ });
+ }
+
+ AtomicBoolean blockingFinish = new AtomicBoolean(false);
+ SocketChannel ch[] = new SocketChannel[1];
+
+ WispEngine.dispatch(() -> {
+ try {
+ ch[0] = SocketChannel.open(new InetSocketAddress(socketAddr, 80));
+ ch[0].read(ByteBuffer.allocate(4096));
+ blockingFinish.set(true);
+ } catch (IOException e) {
+ if (! (e instanceof ClosedChannelException)) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ AtomicInteger integer = new AtomicInteger(-2);
+ // test we won't lose wisptasks;
+ CountDownLatch latch = new CountDownLatch(1);
+ WispEngine.dispatch(() ->{
+ try {
+ latch.await();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ integer.incrementAndGet();
+ });
+
+
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(999999999);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ integer.set(-99);
+ });
+
+
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(5000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ integer.incrementAndGet();
+ });
+
+ assertTrue(cl.await(5, TimeUnit.SECONDS));
+ assertTrue(!blockingFinish.get());
+
+ latch.countDown();
+ Thread.sleep(100);
+ while (integer.get() != 0) {
+ // System.out.println("spin....");
+ }
+
+ ch[0].close();
+ // wait until hand off carrier die
+ // TODO: enable handoff exit
+// Field field = WispEngine.class.getDeclaredField("carrierThreads");
+// field.setAccessible(true);
+// Set set = (Set)field.get(null);
+// Thread.sleep(200);
+// assertTrue(set.size() == 1);
+ }
+}
diff --git a/test/com/alibaba/wisp2/HandOffWakeUpTest.java b/test/com/alibaba/wisp2/HandOffWakeUpTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ef4b074944cda968eeda53ab54dacd92469fe43
--- /dev/null
+++ b/test/com/alibaba/wisp2/HandOffWakeUpTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test long running or blocking syscall task could be retaken
+ * @requires os.family == "linux"
+ * @run main/othervm -Dcom.alibaba.wisp.carrierEngines=1 -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -Dcom.alibaba.wisp.enableHandOff=true -Dcom.alibaba.wisp.sysmonTickUs=100000 HandOffWakeUpTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SocketChannel;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class HandOffWakeUpTest {
+
+ static Properties p;
+ static String socketAddr;
+ static {
+ p = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+ );
+ socketAddr = (String)p.get("test.wisp.socketAddress");
+ if (socketAddr == null) {
+ socketAddr = "www.example.com";
+ }
+ }
+
+ public static void main(String[] args) throws Exception{
+
+ boolean[] booleans = new boolean[1];
+ booleans[0] = true;
+
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(9999999);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ booleans[0] = false;
+ });
+
+ AtomicBoolean blockingFinish = new AtomicBoolean(false);
+
+ SocketChannel ch[] = new SocketChannel[1];
+
+ WispEngine.dispatch(() -> {
+ try {
+ ch[0] = SocketChannel.open(new InetSocketAddress(socketAddr, 80));
+ ch[0].read(ByteBuffer.allocate(4096));
+ blockingFinish.set(true);
+ } catch (IOException e) {
+ if (! (e instanceof ClosedChannelException)) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ Thread.sleep(2000);
+ ch[0].close();
+ if (booleans[0] != true) {
+ throw new Error("waken up unexpectedly");
+ }
+ }
+}
diff --git a/test/com/alibaba/wisp2/HandOffWithStealTest.java b/test/com/alibaba/wisp2/HandOffWithStealTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..608ea6091b32a99b320291d2084f7536bedb3a40
--- /dev/null
+++ b/test/com/alibaba/wisp2/HandOffWithStealTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test long running or blocking syscall task could be retaken
+ * @requires os.family == "linux"
+ * @run main/othervm -Dcom.alibaba.wisp.carrierEngines=1 -XX:+UseWisp2 -Dcom.alibaba.wisp.handoffPolicy=ADAPTIVE HandOffWithStealTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class HandOffWithStealTest {
+ public static void main(String[] args) throws Exception {
+ final int N = 100;
+ CountDownLatch cl = new CountDownLatch(N);
+ for (int i = 0; i < N; i++) {
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ cl.countDown();
+ });
+ }
+
+ AtomicBoolean blockingFinish = new AtomicBoolean(false);
+
+ WispEngine.dispatch(() -> {
+ try {
+ String[] cmdA = { "/bin/sh", "-c", " sleep 200"};
+ Process process = Runtime.getRuntime().exec(cmdA);
+ process.waitFor();
+ blockingFinish.set(true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+
+ assertTrue(cl.await(3, TimeUnit.SECONDS) && !blockingFinish.get());
+ }
+}
diff --git a/test/com/alibaba/wisp2/MassiveIOTest.java b/test/com/alibaba/wisp2/MassiveIOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bace9e45afd504e746c319327f4644aae814d0e2
--- /dev/null
+++ b/test/com/alibaba/wisp2/MassiveIOTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test massive IO
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+UseWisp2 MassiveIOTest
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.pollerShardingSize=0 MassiveIOTest
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.pollerShardingSize=1000 MassiveIOTest
+ */
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class MassiveIOTest {
+ private static final Executor es = Executors.newCachedThreadPool();
+ public static void main(String[] args) throws Exception {
+ ServerSocket server = new ServerSocket(0);
+ CompletableFuture.runAsync(() -> echoServer(server), es);
+ IntStream.range(0, Math.max(1, Runtime.getRuntime().availableProcessors() / 2))
+ .mapToObj(i -> CompletableFuture.runAsync(() -> client(server.getLocalPort()), es))
+ .collect(Collectors.toList())
+ .forEach(CompletableFuture::join);
+ }
+ private static void client(int serverPort) {
+ try {
+ Socket so = new Socket("localhost", serverPort);
+ byte[] buffer = new byte[100];
+ InputStream is = so.getInputStream();
+ OutputStream os = so.getOutputStream();
+ for (int i = 0; i < 100000; i++) {
+ os.write(buffer);
+ is.read(buffer);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ private static void echoServer(ServerSocket server) {
+ while (true) {
+ try {
+ Socket client = server.accept();
+ CompletableFuture.runAsync(() -> echoHandler(client), es);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ private static void echoHandler(Socket client) {
+ System.out.println("Start serving " + client);
+ byte[] buffer = new byte[1024];
+ try {
+ InputStream is = client.getInputStream();
+ OutputStream os = client.getOutputStream();
+ while (true) {
+ os.write(buffer, 0, is.read(buffer));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/com/alibaba/wisp2/MonolithicPollTest.java b/test/com/alibaba/wisp2/MonolithicPollTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2db277caaba86d2447dd3c4547ef309c75ab4a34
--- /dev/null
+++ b/test/com/alibaba/wisp2/MonolithicPollTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary verify epollArray is set for Selector.select()
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.monolithicPoll=true MonolithicPollTest
+ * @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.monolithicPoll=false MonolithicPollTest
+ */
+
+import com.alibaba.wisp.engine.WispTask;
+import sun.misc.SharedSecrets;
+
+import java.lang.reflect.Field;
+import java.nio.channels.Selector;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static jdk.testlibrary.Asserts.assertEQ;
+
+public class MonolithicPollTest {
+ public static void main(String[] args) throws Exception {
+ AtomicReference task = new AtomicReference<>();
+ Executors.newSingleThreadExecutor().submit(() -> {
+ task.set(SharedSecrets.getWispEngineAccess().getCurrentTask());
+ Selector.open().select();
+ return null;
+ });
+
+ Thread.sleep(200);
+
+ while (task.get() == null) {
+ }
+
+ Boolean nz = Executors.newSingleThreadExecutor().submit(() -> {
+ Field arrayField = WispTask.class.getDeclaredField("epollArray");
+ arrayField.setAccessible(true);
+ long array = arrayField.getLong(task.get());
+ return array != 0;
+ }).get();
+
+ assertEQ(nz, Boolean.getBoolean("com.alibaba.wisp.monolithicPoll"));
+ }
+}
diff --git a/test/com/alibaba/wisp2/NioBlockingAcceptTest.java b/test/com/alibaba/wisp2/NioBlockingAcceptTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7da918dc30aca61c2c61eee9d7cfc5870a10a9af
--- /dev/null
+++ b/test/com/alibaba/wisp2/NioBlockingAcceptTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test nio blocking accept
+ * @requires os.family == "linux"
+ * @run main/othervm -Dcom.alibaba.wisp.carrierEngines=1 -XX:ActiveProcessorCount=1 -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor -Dcom.alibaba.wisp.enableThreadAsWisp=true -Dcom.alibaba.wisp.allThreadAsWisp=true NioBlockingAcceptTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.ServerSocketChannel;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class NioBlockingAcceptTest {
+ public static void main(String[] args) throws Exception {
+ WispEngine.dispatch(() -> {
+ try {
+ final ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(new InetSocketAddress(0));
+ ssc.accept();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ final CountDownLatch latch = new CountDownLatch(1);
+ WispEngine.dispatch(latch::countDown);
+
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+ }
+}
diff --git a/test/com/alibaba/wisp2/ProfileWithHandOffTest.java b/test/com/alibaba/wisp2/ProfileWithHandOffTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1842f113476676749a053db6c83b74c03a929846
--- /dev/null
+++ b/test/com/alibaba/wisp2/ProfileWithHandOffTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test after long running or blocking syscall task could be retaken, the new carrier thread can be profiled.
+ * @requires os.family == "linux"
+ * @run main/othervm -Dcom.alibaba.wisp.carrierEngines=1 -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -Dcom.alibaba.wisp.enableHandOff=true -Dcom.alibaba.wisp.handoffPolicy=ADAPTIVE -Dcom.alibaba.wisp.enablePerfLog=true -Dcom.alibaba.wisp.logTimeInternalMillis=1000 ProfileWithHandOffTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.management.WispCounterMXBean;
+import sun.misc.SharedSecrets;
+
+import javax.management.MBeanServer;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class ProfileWithHandOffTest {
+ public static void main(String[] args) throws Exception {
+ CountDownLatch cl = new CountDownLatch(10);
+ AtomicInteger cnt = new AtomicInteger();
+ for (int i = 0; i < 10; i++) {
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(1000);
+ cnt.incrementAndGet();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ cl.countDown();
+ });
+ }
+
+ WispEngine.dispatch(() -> {
+ try {
+ for(int j = 0; j < 30; j++) {
+ int i = System.in.read();
+ System.out.println("your input: " + i);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ WispCounterMXBean mbean = null;
+ try {
+ mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+ "com.alibaba.management:type=WispCounter", WispCounterMXBean.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println(mbean.getRunningStates());
+ System.out.println(mbean.getQueueLength());
+ System.out.println(mbean.getNumberOfRunningTasks());
+ assertTrue(cl.await(5, TimeUnit.SECONDS));
+
+ System.out.println(mbean.getCreateTaskCount());
+ System.out.println(mbean.getCompleteTaskCount());
+ }
+}
diff --git a/test/com/alibaba/wisp2/ProfileWithHandOffTest2.java b/test/com/alibaba/wisp2/ProfileWithHandOffTest2.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9de11cadb4b2090bbbc189aad401ba0ae422226
--- /dev/null
+++ b/test/com/alibaba/wisp2/ProfileWithHandOffTest2.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test after long running or blocking syscall task could be retaken, the new carrier thread can be profiled.
+ * @requires os.family == "linux"
+ * @run main/othervm -Dcom.alibaba.wisp.carrierEngines=1 -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -Dcom.alibaba.wisp.enableHandOff=true -Dcom.alibaba.wisp.handoffPolicy=ADAPTIVE -Dcom.alibaba.wisp.sysmonTickUs=100000 -Dcom.alibaba.wisp.enablePerfLog=true -Dcom.alibaba.wisp.logTimeInternalMillis=1000 ProfileWithHandOffTest2
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+import com.alibaba.management.WispCounterMXBean;
+import sun.misc.SharedSecrets;
+
+import javax.management.MBeanServer;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class ProfileWithHandOffTest2 {
+
+ static Properties p;
+ static String socketAddr;
+ static {
+ p = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ }
+ );
+ socketAddr = (String)p.get("test.wisp.socketAddress");
+ if (socketAddr == null) {
+ socketAddr = "www.example.com";
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ CountDownLatch cl = new CountDownLatch(10);
+ for (int i = 0; i < 10; i++) {
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ cl.countDown();
+ });
+ }
+
+ AtomicBoolean blockingFinish = new AtomicBoolean(false);
+
+ WispEngine.dispatch(() -> {
+ try {
+ SocketChannel ch = SocketChannel.open(new InetSocketAddress(socketAddr, 80));
+ ch.read(ByteBuffer.allocate(4096));
+ blockingFinish.set(true);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ WispCounterMXBean mbean = null;
+ try {
+ mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+ "com.alibaba.management:type=WispCounter", WispCounterMXBean.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ System.out.println(mbean.getRunningStates());
+ System.out.println(mbean.getQueueLength());
+ System.out.println(mbean.getNumberOfRunningTasks());
+ System.out.println(mbean.getCreateTaskCount());
+
+ assertTrue(cl.await(5, TimeUnit.SECONDS));
+ assertTrue(!blockingFinish.get());
+ System.out.println(mbean.getNumberOfRunningTasks());
+ System.out.println(mbean.getCreateTaskCount());
+ System.out.println(mbean.getCompleteTaskCount());
+ }
+}
diff --git a/test/com/alibaba/wisp2/RemoveWispParentTest.java b/test/com/alibaba/wisp2/RemoveWispParentTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4da20a60633cd57fc21d06fc4b8e876b357874cd
--- /dev/null
+++ b/test/com/alibaba/wisp2/RemoveWispParentTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test a WispTask will not block when it created a new one and didn't yield to its parent.
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+UseWisp2 RemoveWispParentTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class RemoveWispParentTest {
+ static CountDownLatch latch = new CountDownLatch(3);
+
+ // mainThreadCreateWisp create a new wisp task in main thread, check whether
+ // main thread will be blocked.
+ static void mainThreadCreateWisp() {
+ WispEngine.dispatch(() -> {
+ latch.countDown();
+ });
+ }
+
+ // wispTaskCreateWisp create a new wisp task in wispTask, check whether
+ // creater wispTask will be blocked.
+ static void wispTaskCreateWisp() {
+ WispEngine.dispatch(() -> {
+ new Thread(() -> {
+ latch.countDown();
+ }).start();
+ latch.countDown();
+ });
+ }
+
+ public static void main(String[] args) throws Exception {
+ mainThreadCreateWisp();
+ wispTaskCreateWisp();
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+ }
+}
\ No newline at end of file
diff --git a/test/com/alibaba/wisp2/ReuseWispTaskAfterThreadJoinTest.java b/test/com/alibaba/wisp2/ReuseWispTaskAfterThreadJoinTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f519094fdec860a621574d9365e0b92cb11963b
--- /dev/null
+++ b/test/com/alibaba/wisp2/ReuseWispTaskAfterThreadJoinTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test wisp task reusing after thread.join()
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor -Dcom.alibaba.wisp.enableThreadAsWisp=true -Dcom.alibaba.wisp.allThreadAsWisp=true ReuseWispTaskAfterThreadJoinTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+public class ReuseWispTaskAfterThreadJoinTest {
+ public static void main(String[] args) throws Exception {
+ Thread t = new Thread(() -> {
+
+
+ });
+ t.start();
+ t.join();
+ // really exited.
+ // reuse the wispTask
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(200000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ Thread.sleep(1000);
+ t.join();
+ }
+}
diff --git a/test/com/alibaba/wisp2/ThreadAsWispBlackListTest.java b/test/com/alibaba/wisp2/ThreadAsWispBlackListTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6104f99492c406c86f452b5300f0db8575fca2d
--- /dev/null
+++ b/test/com/alibaba/wisp2/ThreadAsWispBlackListTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test all thread as wisp black list
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+UseWisp2 ThreadAsWispBlackListTest
+ */
+
+import sun.misc.SharedSecrets;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.FutureTask;
+
+import static jdk.testlibrary.Asserts.assertFalse;
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class ThreadAsWispBlackListTest {
+ public static void main(String[] args) throws Exception {
+ assertFalse(Executors.newSingleThreadExecutor().submit(ThreadAsWispBlackListTest::isRealThread).get());
+ byClass();
+ byPackage();
+ byName();
+ testCommonPool();
+ testMultiEntry();
+ wildcardTest();
+ }
+
+ private static void byPackage() throws Exception {
+ setBlackList("package:java.util.concurrent");
+ assertTrue(Executors.newSingleThreadExecutor().submit(ThreadAsWispBlackListTest::isRealThread).get());
+ }
+
+ private static void byClass() throws Exception {
+ FutureTask future = new FutureTask<>(ThreadAsWispBlackListTest::isRealThread);
+ class T1 extends Thread {
+ @Override
+ public void run() {
+ future.run();
+ }
+ }
+ setBlackList("class:" + T1.class.getName());
+ new T1().start();
+ assertTrue(future.get());
+ }
+
+ private static void byName() throws Exception {
+ wildcardTest1("n1111", "n1111");
+ }
+
+ private static void wildcardTest() throws Exception {
+ wildcardTest1("a-*", "a-1");
+ wildcardTest1("a-*", "a-2");
+ wildcardTest1("a-*", "a-4999");
+ wildcardTest1("a-*", "a-abc");
+
+ wildcardTest1("a-*-b", "a-1-b");
+ wildcardTest1("a-*-b", "a-2-b");
+ wildcardTest1("a-*-b", "a-4999-b");
+ wildcardTest1("a-*-b", "a-abc-b");
+
+ wildcardTest1("a-*z", "a-1-bz");
+ wildcardTest1("a-*z", "a-2-bz");
+ wildcardTest1("a-*z", "a-4999-bz");
+ wildcardTest1("a-*z", "a-abc-bz");
+
+ wildcardTest1("*z", "a-1-bz");
+ wildcardTest1("*z", "a-2-bz");
+ wildcardTest1("*z", "a-4999-bz");
+ wildcardTest1("*z", "a-abc-bz");
+
+ wildcardTest1("?z", "zz");
+ wildcardTest1("a?z", "agz");
+ wildcardTest1("a?", "a1");
+ }
+
+ private static void wildcardTest1(String pattern, String name) throws Exception {
+ setBlackList("name:" + pattern);
+ FutureTask future = new FutureTask<>(ThreadAsWispBlackListTest::isRealThread);
+ new Thread(future, name).start();
+ assertTrue(future.get());
+ }
+
+ private static void testCommonPool() throws Exception {
+ setBlackList("name:ForkJoinPool.commonPool-worker-*");
+ FutureTask future = new FutureTask<>(ThreadAsWispBlackListTest::isRealThread);
+ ForkJoinPool.commonPool().execute(future);
+ assertTrue(future.get());
+ }
+
+ private static void testMultiEntry() throws Exception {
+ setBlackList("name:m1111;name:m2222");
+ FutureTask future = new FutureTask<>(ThreadAsWispBlackListTest::isRealThread);
+ new Thread(future, "m1111").start();
+ assertTrue(future.get());
+ future = new FutureTask<>(ThreadAsWispBlackListTest::isRealThread);
+ new Thread(future, "m2222").start();
+ assertTrue(future.get());
+ }
+
+ private static boolean isRealThread() {
+ return SharedSecrets.getJavaLangAccess().currentThread0() == Thread.currentThread();
+ }
+
+ private static void setBlackList(String list) throws Exception {
+ System.setProperty("com.alibaba.wisp.threadAsWisp.black", list);
+ Method m = Class.forName("com.alibaba.wisp.engine.WispConfiguration").getDeclaredMethod("loadBizConfig");
+ m.setAccessible(true);
+ m.invoke(null);
+ }
+}
diff --git a/test/com/alibaba/wisp2/ThreadJoinTest.java b/test/com/alibaba/wisp2/ThreadJoinTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..005a73a74a89c786cd4b0d1fadf04493a1dd7fac
--- /dev/null
+++ b/test/com/alibaba/wisp2/ThreadJoinTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary test thread.join()
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor -Dcom.alibaba.wisp.enableThreadAsWisp=true -Dcom.alibaba.wisp.allThreadAsWisp=true ThreadJoinTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+public class ThreadJoinTest {
+ public static void main(String[] args) throws Exception {
+ Thread t = new Thread(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ t.start();
+ t.join();
+
+ t = new Thread(() -> {
+
+ });
+ t.start();
+ Thread.sleep(1000);
+ WispEngine.dispatch(() -> {
+ try {
+ Thread.sleep(200000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ Thread.sleep(1000);
+ t.join();
+ }
+}
diff --git a/test/com/alibaba/wisp2/TimedWaitTest.java b/test/com/alibaba/wisp2/TimedWaitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..eed65ea0b9848021193070b5208ac61c3f520172
--- /dev/null
+++ b/test/com/alibaba/wisp2/TimedWaitTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary test timed Jvm park
+ * @requires os.family == "linux"
+ * @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 TimedWaitTest
+ */
+
+import com.alibaba.wisp.engine.WispEngine;
+
+import java.util.concurrent.CountDownLatch;
+
+public class TimedWaitTest {
+ public static void main(String[] args) throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(4);
+ for (int i = 0; i < 4; i++) {
+ int id = i;
+ WispEngine.dispatch(() -> {
+ final Object lock = new Object();
+ synchronized (lock) {
+ try {
+ lock.wait(1);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ latch.countDown();
+ });
+ }
+ latch.await();
+ }
+}
diff --git a/test/com/alibaba/wisp2/Wisp2GroupTest.java b/test/com/alibaba/wisp2/Wisp2GroupTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..472541aa19ef56b3931d61fba8e5e8e8c64ef1a8
--- /dev/null
+++ b/test/com/alibaba/wisp2/Wisp2GroupTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2020 Alibaba Group Holding Limited. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Alibaba designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @test
+ * @summary Test WispCounter removing during the shutdown of Wisp2Group
+ * @requires os.family == "linux"
+ * @library /lib/testlibrary
+ * @run main/othervm -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor -Dcom.alibaba.wisp.enableHandOff=false Wisp2GroupTest
+ */
+
+import com.alibaba.management.WispCounterMXBean;
+import com.alibaba.wisp.engine.WispEngine;
+
+import javax.management.MBeanServer;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static jdk.testlibrary.Asserts.assertTrue;
+
+public class Wisp2GroupTest {
+ static WispMultiThreadExecutor executor;
+ static WispCounterMXBean mbean;
+
+ public static void main(String[] args) throws Exception {
+
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ try {
+ mbean = ManagementFactory.newPlatformMXBeanProxy(mbs,
+ "com.alibaba.management:type=WispCounter", WispCounterMXBean.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ testWisp2Group();
+ }
+
+ private static void testWisp2Group() throws Exception {
+ executor = new WispMultiThreadExecutor(4, new ThreadFactory() {
+ AtomicInteger seq = new AtomicInteger();
+
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r, "Wisp2-Group-Test-Carrier-" + seq.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ }
+ });
+ Thread.sleep(500);
+ for (int j = 0; j < 10; ++j) {
+ executor.execute(RUN_COMPILED_BUSY_LOOP);
+ }
+ Thread.sleep(500);
+ List