提交 5b210cf7 编写于 作者: Y yunyao.zxl 提交者: zhengxiaolinX

[Wisp] Add Wisp

Summary: Add JDK code of the Wisp implementation

Test Plan: all Wisp tests

Reviewed-by: yuleil, shiyuexw, sanhong

Issue: https://github.com/alibaba/dragonwell8/issues/113
上级 44c71bc8
...@@ -264,6 +264,11 @@ ifndef OPENJDK ...@@ -264,6 +264,11 @@ ifndef OPENJDK
$(wildcard $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS_API_DIR)/classes) $(wildcard $(JDK_TOPDIR)/src/closed/$(OPENJDK_TARGET_OS_API_DIR)/classes)
endif endif
LINUX_SRC_DIRS :=
ifeq ($(OPENJDK_TARGET_OS), linux)
LINUX_SRC_DIRS += $(JDK_TOPDIR)/src/linux/classes
endif
MACOSX_SRC_DIRS := MACOSX_SRC_DIRS :=
ifeq ($(OPENJDK_TARGET_OS), macosx) ifeq ($(OPENJDK_TARGET_OS), macosx)
MACOSX_SRC_DIRS += $(JDK_TOPDIR)/src/macosx/classes MACOSX_SRC_DIRS += $(JDK_TOPDIR)/src/macosx/classes
...@@ -328,6 +333,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JDK,\ ...@@ -328,6 +333,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JDK,\
SRC:=$(JDK_TOPDIR)/src/share/classes \ SRC:=$(JDK_TOPDIR)/src/share/classes \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes \ $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/classes \
$(MACOSX_SRC_DIRS) \ $(MACOSX_SRC_DIRS) \
$(LINUX_SRC_DIRS) \
$(AIX_SRC_DIRS) \ $(AIX_SRC_DIRS) \
$(JDK_OUTPUTDIR)/gensrc \ $(JDK_OUTPUTDIR)/gensrc \
$(JDK_OUTPUTDIR)/gensrc_no_srczip \ $(JDK_OUTPUTDIR)/gensrc_no_srczip \
......
...@@ -562,7 +562,8 @@ EXPORTED_PRIVATE_PKGS = com.oracle.net \ ...@@ -562,7 +562,8 @@ EXPORTED_PRIVATE_PKGS = com.oracle.net \
com.alibaba.management \ com.alibaba.management \
com.alibaba.jvm.gc \ com.alibaba.jvm.gc \
com.alibaba.rcm \ com.alibaba.rcm \
com.alibaba.tenant com.alibaba.tenant \
com.alibaba.wisp.engine \
$(IMAGES_OUTPUTDIR)/symbols/_the.symbols: $(IMAGES_OUTPUTDIR)/lib/rt.jar $(IMAGES_OUTPUTDIR)/symbols/_the.symbols: $(IMAGES_OUTPUTDIR)/lib/rt.jar
$(RM) -r $(IMAGES_OUTPUTDIR)/symbols/META-INF/sym $(RM) -r $(IMAGES_OUTPUTDIR)/symbols/META-INF/sym
......
...@@ -2565,4 +2565,7 @@ com/alibaba/tenant/TenantException ...@@ -2565,4 +2565,7 @@ com/alibaba/tenant/TenantException
com/alibaba/tenant/TenantState com/alibaba/tenant/TenantState
com/alibaba/tenant/TenantGlobals com/alibaba/tenant/TenantGlobals
com/alibaba/tenant/TenantContainerFactory com/alibaba/tenant/TenantContainerFactory
com/dyn/Coroutine
com/alibaba/wisp/engine/WispEngine
com/alibaba/wisp/engine/WispSysmon
# eea35d9d56e0006e # eea35d9d56e0006e
\ No newline at end of file
...@@ -144,6 +144,7 @@ LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/l ...@@ -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/jwarmup \
$(JDK_TOPDIR)/src/share/native/com/alibaba/jvm/gc \ $(JDK_TOPDIR)/src/share/native/com/alibaba/jvm/gc \
$(JDK_TOPDIR)/src/share/native/com/alibaba/tenant \ $(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/misc \
$(JDK_TOPDIR)/src/share/native/sun/reflect \ $(JDK_TOPDIR)/src/share/native/sun/reflect \
$(JDK_TOPDIR)/src/share/native/java/util \ $(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 ...@@ -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/common \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/util $(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) ifeq ($(OPENJDK_TARGET_OS), windows)
LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/util/locale/provider LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/util/locale/provider
else ifeq ($(OPENJDK_TARGET_OS), macosx) else ifeq ($(OPENJDK_TARGET_OS), macosx)
......
...@@ -221,6 +221,10 @@ SUNWprivate_1.1 { ...@@ -221,6 +221,10 @@ SUNWprivate_1.1 {
Java_com_alibaba_jwarmup_JWarmUp_registerNatives; Java_com_alibaba_jwarmup_JWarmUp_registerNatives;
Java_com_alibaba_tenant_TenantGlobals_getTenantFlags; Java_com_alibaba_tenant_TenantGlobals_getTenantFlags;
Java_com_alibaba_jvm_gc_ElasticHeapMXBeanImpl_registerNatives; 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_fillInStackTrace;
Java_java_lang_Throwable_getStackTraceDepth; Java_java_lang_Throwable_getStackTraceDepth;
Java_java_lang_Throwable_getStackTraceElement; Java_java_lang_Throwable_getStackTraceElement;
......
...@@ -13,6 +13,10 @@ text: .text%Java_java_lang_Thread_registerNatives; ...@@ -13,6 +13,10 @@ text: .text%Java_java_lang_Thread_registerNatives;
text: .text%Java_com_alibaba_tenant_TenantGlobals_getTenantFlags; text: .text%Java_com_alibaba_tenant_TenantGlobals_getTenantFlags;
text: .text%Java_com_alibaba_jwarmup_JWarmUp_registerNatives; text: .text%Java_com_alibaba_jwarmup_JWarmUp_registerNatives;
text: .text%Java_com_alibaba_jvm_gc_ElasticHeapMXBeanImpl_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_getStackAccessControlContext;
text: .text%Java_java_security_AccessController_getInheritedAccessControlContext; text: .text%Java_java_security_AccessController_getInheritedAccessControlContext;
text: .text%Java_java_lang_ClassLoader_registerNatives; text: .text%Java_java_lang_ClassLoader_registerNatives;
......
...@@ -49,6 +49,7 @@ SUNWprivate_1.1 { ...@@ -49,6 +49,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_EPoll_epollCreate; Java_sun_nio_ch_EPoll_epollCreate;
Java_sun_nio_ch_EPoll_epollCtl; Java_sun_nio_ch_EPoll_epollCtl;
Java_sun_nio_ch_EPoll_epollWait; Java_sun_nio_ch_EPoll_epollWait;
Java_sun_nio_ch_EPoll_errnoENOENT;
Java_sun_nio_ch_EPollPort_close0; Java_sun_nio_ch_EPollPort_close0;
Java_sun_nio_ch_EPollPort_drain1; Java_sun_nio_ch_EPollPort_drain1;
Java_sun_nio_ch_EPollPort_interrupt; Java_sun_nio_ch_EPollPort_interrupt;
......
/*
* 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) {
}
}
/*
* 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);
}
}
/*
* 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.
* <p/>
* 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:
* <p>
* 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():
* <p>
* 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
}
/*
* 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<TimeOut> 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;
}
}
/*
* 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.
*
* <p> 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<WispCarrier> {
private static final AtomicIntegerFieldUpdater<WispEngine> TASK_COUNT_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(WispEngine.class, "runningTaskCount");
/**
* The user can only can only get thread-specific carrier by calling this method.
* <p>
* 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<WispTask> 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.
* <p>
* 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(...)}
* <p>
* Used for implementing socket io
* <pre>
* while (!ch.read(buf) == 0) { // 0 indicate IO not ready, not EOF..
* registerEvent(ch, OP_READ);
* schedule();
* }
* // read is done here
* <pre/>
*/
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());
}
}
/*
* 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<String> THREAD_AS_WISP_BLACKLIST;
static {
Properties p = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Properties>() {
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<String> 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<Properties>() {
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<String> getThreadAsWispBlacklist() {
ensureBizConfigLoaded();
assert THREAD_AS_WISP_BLACKLIST != null;
return THREAD_AS_WISP_BLACKLIST;
}
}
/*
* 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);
}
}
/*
* 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<Long, WispCounter> managedEngineCounters;
static {
if (!WispEngine.transparentWispSwitch()) {
managedEngineCounters = new HashMap<>();
} else {
managedEngineCounters = new ConcurrentHashMap<>(100);
}
}
@Override
public List<Boolean> getRunningStates() {
return aggregate(WispCounter::getRunningState);
}
@Override
public List<Long> getSwitchCount() {
return aggregate(WispCounter::getSwitchCount);
}
@Override
public List<Long> getWaitTimeTotal() {
return aggregate(WispCounter::getWaitTimeTotal);
}
@Override
public List<Long> getRunningTimeTotal() {
return aggregate(WispCounter::getRunningTimeTotal);
}
@Override
public List<Long> getCompleteTaskCount() {
return aggregate(WispCounter::getCompletedTaskCount);
}
@Override
public List<Long> getCreateTaskCount() {
return aggregate(WispCounter::getCreateTaskCount);
}
@Override
public List<Long> getParkCount() {
return aggregate(WispCounter::getParkCount);
}
@Override
public List<Long> getUnparkCount() {
return aggregate(WispCounter::getUnparkCount);
}
@Override
public List<Long> getLazyUnparkCount() {
return aggregate(w -> 0L);
}
@Override
public List<Long> getUnparkInterruptSelectorCount() {
return aggregate(WispCounter::getUnparkInterruptSelectorCount);
}
@Override
public List<Long> getSelectableIOCount() {
return aggregate(WispCounter::getSelectableIOCount);
}
@Override
public List<Long> getTimeOutCount() {
return aggregate(WispCounter::getTimeOutCount);
}
@Override
public List<Long> getEventLoopCount() {
return aggregate(WispCounter::getEventLoopCount);
}
@Override
public List<Long> getQueueLength() {
return aggregate(WispCounter::getCurrentTaskQueueLength);
}
@Override
public List<Long> getNumberOfRunningTasks() {
return aggregate(WispCounter::getCurrentRunningTaskCount);
}
@Override
public List<Long> getTotalEnqueueTime() {
return aggregate(WispCounter::getTotalEnqueueTime);
}
@Override
public List<Long> getEnqueueCount() {
return aggregate(WispCounter::getEnqueueCount);
}
@Override
public List<Long> getTotalExecutionTime() {
return aggregate(WispCounter::getTotalExecutionTime);
}
@Override
public List<Long> getExecutionCount() {
return aggregate(WispCounter::getExecutionCount);
}
@Override
public List<Long> getTotalWaitSocketIOTime() {
return aggregate(WispCounter::getTotalWaitSocketIOTime);
}
@Override
public List<Long> getWaitSocketIOCount() {
return aggregate(WispCounter::getWaitSocketIOCount);
}
@Override
public List<Long> getTotalBlockingTime() {
return aggregate(WispCounter::getTotalBlockingTime);
}
/**
* @param id WispCarrier id
* @return WispCounter
*/
@Override
public WispCounter getWispCounter(long id) {
return WispEngine.getWispCounter(id);
}
private <T> List<T> aggregate(Function<WispCounter, T> getter) {
List<T> result = new ArrayList<>(managedEngineCounters.size());
for (Entry<Long, WispCounter> 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();
}
}
/*
* 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.
* <p>
* WispEngine represents a group of {@link WispCarrier}, which can steal
* tasks from each other to achieve work-stealing.
* <p>
* {@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.
* <p>
* 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<WispEngine, Boolean> 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<Thread> 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<Thread>() {
@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<Object> status, Object INTERRUPTED) throws IOException {
return WispEventPump.Pool.INSTANCE.epollWaitForWisp(epfd, pollArray, arraySize, timeout, status, INTERRUPTED);
}
@Override
public void interruptEpoll(AtomicReference<Object> 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<WispCarrier> carrierEngines;
final Queue<WispTask> 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
* <p>
* 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> T runInCritical(Supplier<T> 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<Runnable> 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<WispTask> 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<WispTask> getRunningTasks() {
assert WispTask.SHUTDOWN_TASK_NAME.equals(WispCarrier.current().current.getName());
WispCarrier carrier = WispCarrier.current();
ArrayList<WispTask> 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<Long> getWispCarrierIds() {
List<Long> 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);
}
/*
* 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<Object> status,
final Object INTERRUPTED) throws IOException {
return pumps[hash(epfd) & mask].epollWaitForWisp(epfd, pollArray, arraySize, timeout, status, INTERRUPTED);
}
void interruptEpoll(AtomicReference<Object> 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<Integer, WispTask> 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<Integer, WispTask> 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<Integer, WispTask> 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<Object> 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<Object> 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<WispEventPump, WispScheduler.Worker> OWNER_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(WispEventPump.class, WispScheduler.Worker.class, "owner");
private final static AtomicIntegerFieldUpdater<WispEventPump> WAKEUP_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(WispEventPump.class, "wakeupCount");
}
/*
* 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<Long, WispPerfCounter> 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<Long, WispPerfCounter> 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<WispCounter, Long> timeFunc, Function<WispCounter, Long> 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);
}
}
}
/*
* 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<StealAwareRunnable> 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<Worker> LENGTH_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(Worker.class, "queueLength");
private static final UnsafeAccess UA = SharedSecrets.getUnsafeAccess();
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
}
/*
* 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<WispCarrier> 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<WispCarrier> 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<WispCarrier> 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();
}
/*
* 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}
* <p>
* Create {@link WispTask} via {@link WispEngine#dispatch(Runnable)} (Callable, String)} to make
* blocking IO operation in {@link WispTask}s to become concurrent.
* <p>
* 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.
* <p>
* A {@link WispTask}'s exit will wake up the waiting parent.
*/
public class WispTask implements Comparable<WispTask> {
private final static AtomicInteger idGenerator = new AtomicInteger();
static final Map<Integer, WispTask> 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<WispTask> 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..
* <p>
* {@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.
* <p>
* 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<WispTask> 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<WispTask> 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<WispTask, WispCarrier> CARRIER_UPDATER;
private static final AtomicIntegerFieldUpdater<WispTask> JVM_PARK_UPDATER;
private static final AtomicIntegerFieldUpdater<WispTask> JDK_PARK_UPDATER;
private static final AtomicIntegerFieldUpdater<WispTask> INTERRUPTED_UPDATER;
private static final AtomicIntegerFieldUpdater<WispTask> NATIVE_INTERRUPTED_UPDATER;
private static final AtomicIntegerFieldUpdater<WispTask> STEAL_LOCK_UPDATER;
private static final AtomicLongFieldUpdater<WispTask> EPOLL_ARRAY_UPDATER;
private static final AtomicIntegerFieldUpdater<WispTask> 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();
}
}
/*
* 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.
* <p>
* 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();
}
package sun.nio.ch;
public class IOEvent {
public static Class<?> eventClass() {
return EPollPort.class;
}
}
\ No newline at end of file
/*
* 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;
}
}
/*
* 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<InputStream>() {
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<OutputStream>() {
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<Boolean> name, boolean value)
throws SocketException {
try {
getChannelImpl().setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private void setIntOption(SocketOption<Integer> name, int value)
throws SocketException {
try {
getChannelImpl().setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
try {
return getChannelImpl().getOption(name);
} catch (IOException x) {
Net.translateToSocketException(x);
return false; // keep compiler happy
}
}
private int getIntOption(SocketOption<Integer> 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;
}
}
/*
* 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();
}
}
}
/*
* 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<Boolean> name, boolean value)
throws SocketException {
try {
getChannelImpl().setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private void setIntOption(SocketOption<Integer> name, int value)
throws SocketException {
try {
getChannelImpl().setOption(name, value);
} catch (IOException x) {
Net.translateToSocketException(x);
}
}
private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
try {
return getChannelImpl().getOption(name);
} catch (IOException x) {
Net.translateToSocketException(x);
return false; // keep compiler happy
}
}
private int getIntOption(SocketOption<Integer> 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;
}
}
/*
* 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));
}
/*
* 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));
}
/*
* 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));
}
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as * 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 * particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code. * by Oracle in the LICENSE file that accompanied this code.
* *
...@@ -17,14 +17,10 @@ ...@@ -17,14 +17,10 @@
* You should have received a copy of the GNU General Public License version * 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, * 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * 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<InT, OutT> {
public OutT run(AsymCoroutine<? extends InT, ? super OutT> coroutine, InT value);
} }
/*
* 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<Boolean> getRunningStates() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getSwitchCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getWaitTimeTotal() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getRunningTimeTotal() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getCompleteTaskCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getCreateTaskCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getParkCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getUnparkCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getLazyUnparkCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getUnparkInterruptSelectorCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getSelectableIOCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTimeOutCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getEventLoopCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getQueueLength() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getNumberOfRunningTasks() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalEnqueueTime() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getEnqueueCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalExecutionTime() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getExecutionCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalWaitSocketIOTime() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getWaitSocketIOCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalBlockingTime() {
throw new UnsupportedOperationException();
}
@Override
public WispCounter getWispCounter(long id) {
throw new UnsupportedOperationException();
}
@Override
public ObjectName getObjectName() {
throw new UnsupportedOperationException();
}
}
/*
* 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<Object> status, Object INTERRUPTED) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void interruptEpoll(AtomicReference<Object> 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();
}
});
}
}
/*
* 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();
}
}
/*
* 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();
}
}
package sun.nio.ch;
public class IOEvent {
public static Class<?> eventClass() {
return IOEventRegister.class;
}
}
\ No newline at end of file
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
/*
* 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();
}
}
/*
* 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();
}
}
/*
* 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 {
}
/*
* 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();
}
}
/*
* 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<Boolean> getRunningStates();
/**
* @return list of managed wisp worker switch count
*/
List<Long> getSwitchCount();
/**
* @return list of managed wisp worker wait time total, unit ns
*/
List<Long> getWaitTimeTotal();
/**
* @return list of managed wisp worker running time total, unit ns
*/
List<Long> getRunningTimeTotal();
/**
* @return list of managed wisp worker complete task count
*/
List<Long> getCompleteTaskCount();
/**
* @return list of managed wisp worker create task count
*/
List<Long> getCreateTaskCount();
/**
* @return list of managed wisp worker park count
*/
List<Long> getParkCount();
/**
* @return list of managed wisp worker unpark count
*/
List<Long> 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<Long> getLazyUnparkCount();
/**
* @return list of managed wisp worker unpark interrupt selector count
*/
List<Long> getUnparkInterruptSelectorCount();
/**
* @return list of managed wisp worker do IO count
*/
List<Long> getSelectableIOCount();
/**
* @return list of managed wisp worker timeout count
*/
List<Long> getTimeOutCount();
/**
* @return list of managed wisp worker do event loop count
*/
List<Long> getEventLoopCount();
/**
* @return list of managed wisp worker task queue length
*/
List<Long> getQueueLength();
/**
* @return list of number of running tasks from managed wisp workers
*/
List<Long> getNumberOfRunningTasks();
/**
* @return list of total blocking time in nanos from managed wisp workers
*/
List<Long> getTotalBlockingTime();
/**
* @return list of total execution time in nanos from managed wisp workers
*/
List<Long> getTotalExecutionTime();
/**
* @return list of execution count from managed wisp workers
*/
List<Long> getExecutionCount();
/**
* @return list of total enqueue time in nanos from managed wisp workers
*/
List<Long> getTotalEnqueueTime();
/**
* @return list of enqueue count from managed wisp workers
*/
List<Long> getEnqueueCount();
/**
* @return list of total wait socket io time in nanos from managed wisp workers
*/
List<Long> getTotalWaitSocketIOTime();
/**
* @return list of wait socket io event count from managed wisp workers
*/
List<Long> getWaitSocketIOCount();
/**
* @param id WispEngine id
* @return WispCounter data
*/
WispCounter getWispCounter(long id);
}
...@@ -37,6 +37,9 @@ package com.sun.demo.jvmti.hprof; ...@@ -37,6 +37,9 @@ package com.sun.demo.jvmti.hprof;
* for more details. * for more details.
*/ */
import sun.misc.JavaLangAccess;
import sun.misc.SharedSecrets;
public class Tracker { public class Tracker {
/* Master switch that activates calls to native functions. */ /* Master switch that activates calls to native functions. */
...@@ -57,7 +60,7 @@ public class Tracker { ...@@ -57,7 +60,7 @@ public class Tracker {
if (obj == null) { if (obj == null) {
throw new IllegalArgumentException("Null object."); throw new IllegalArgumentException("Null object.");
} }
nativeObjectInit(Thread.currentThread(), obj); nativeObjectInit(SharedSecrets.getJavaLangAccess().currentThread0(), obj);
} }
} }
...@@ -73,7 +76,7 @@ public class Tracker { ...@@ -73,7 +76,7 @@ public class Tracker {
if (obj == null) { if (obj == null) {
throw new IllegalArgumentException("Null object."); throw new IllegalArgumentException("Null object.");
} }
nativeNewArray(Thread.currentThread(), obj); nativeNewArray(SharedSecrets.getJavaLangAccess().currentThread0(), obj);
} }
} }
...@@ -96,7 +99,11 @@ public class Tracker { ...@@ -96,7 +99,11 @@ public class Tracker {
throw new IllegalArgumentException("Negative method index"); 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 { ...@@ -117,7 +124,7 @@ public class Tracker {
throw new IllegalArgumentException("Negative method index"); throw new IllegalArgumentException("Negative method index");
} }
nativeReturnSite(Thread.currentThread(), cnum, mnum); nativeReturnSite(SharedSecrets.getJavaLangAccess().currentThread0(), cnum, mnum);
} }
} }
......
/*
* 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()}.
* <p>
* 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.
* <p>
* An implementation of a simple AsymCoroutine that always returns the average of all its previous inputs might look like this:
* <p>
* <hr>
* <blockquote>
*
* <pre>
* class Average extends AsymCoroutine&lt;Integer, Integer&gt; {
* public Integer run(Integer value) {
* int sum = value;
* int count = 1;
* while (true) {
* sum += ret(sum / count++);
* }
* }
* }
* </pre>
*
* </blockquote>
* <hr>
* <p>
* This AsymCoroutine can be invoked either by reading and writing the {@link #output} and {@link #input} fields and invoking the
* {@link #call()} method:
* <p>
* <blockquote>
*
* <pre>
* Average avg = new Average();
* avg.input = 10;
* avg.call();
* System.out.println(avg.output);
* </pre>
*
* </blockquote>
* <p>
* Another way to invoke this AsymCoroutine is by using the shortcut {@link #call(Object)} methods:
* <p>
* <blockquote>
*
* <pre>
* Average avg = new Average();
* System.out.println(avg.call(10));
* </pre>
*
* </blockquote>
* <p>
*
* @author Lukas Stadler
*
* @param <InT>
* input type of this AsymCoroutine, Void if no input value is expected
* @param <OutT>
* output type of this AsymCoroutine, Void if no output is produced
*/
public class AsymCoroutine<InT, OutT> extends CoroutineBase implements Iterable<OutT> {
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<OutT> implements Iterator<OutT> {
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<OutT> iterator() {
return new Iter<OutT>(this);
}
protected final void run() {
output = run(input);
}
}
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
package java.dyn; 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 * 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. * the next coroutine whenever yield is called.
...@@ -66,10 +68,14 @@ package java.dyn; ...@@ -66,10 +68,14 @@ package java.dyn;
* @author Lukas Stadler * @author Lukas Stadler
*/ */
public class Coroutine extends CoroutineBase { public class Coroutine extends CoroutineBase {
private final Runnable target; public enum StealResult {
SUCCESS,
FAIL_BY_CONTENTION,
FAIL_BY_STATUS,
FAIL_BY_NATIVE_FRAME
}
Coroutine next; private final Runnable target;
Coroutine last;
public Coroutine() { public Coroutine() {
this.target = null; this.target = null;
...@@ -92,24 +98,44 @@ public class Coroutine extends CoroutineBase { ...@@ -92,24 +98,44 @@ public class Coroutine extends CoroutineBase {
} }
// creates the initial coroutine for a new thread // creates the initial coroutine for a new thread
Coroutine(CoroutineSupport threadSupport, long data) { Coroutine(CoroutineSupport threadSupport, long nativeCoroutine) {
super(threadSupport, data); super(threadSupport, nativeCoroutine);
this.target = null; this.target = null;
} }
public static void yieldTo(Coroutine target) {
SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().symmetricYieldTo(target);
}
/** /**
* Yields execution to the next coroutine in the current threads coroutine queue. * 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 yield() { public static void unsafeYieldTo(Coroutine target) {
Thread.currentThread().getCoroutineSupport().symmetricYield(); SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().unsafeSymmetricYieldTo(target);
} }
public static void yieldTo(Coroutine target) { /**
Thread.currentThread().getCoroutineSupport().symmetricYieldTo(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() { public void stop() {
Thread.currentThread().getCoroutineSupport().symmetricStopCoroutine(this); SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().symmetricStopCoroutine(this);
}
public void setWispTask(int id, Object task, Object engine) {
setWispTask(nativeCoroutine, id, task, engine);
} }
protected void run() { protected void run() {
...@@ -118,4 +144,16 @@ public class Coroutine extends CoroutineBase { ...@@ -118,4 +144,16 @@ public class Coroutine extends CoroutineBase {
target.run(); 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
...@@ -25,36 +25,38 @@ ...@@ -25,36 +25,38 @@
package java.dyn; package java.dyn;
public abstract class CoroutineBase { import sun.misc.SharedSecrets;
transient long data;
transient CoroutineLocal.CoroutineLocalMap coroutineLocals = null; public abstract class CoroutineBase {
transient long nativeCoroutine;
boolean finished = false; boolean finished = false;
boolean needsUnlock = false;
transient CoroutineSupport threadSupport; transient CoroutineSupport threadSupport;
CoroutineBase() { CoroutineBase() {
Thread thread = Thread.currentThread(); Thread thread = SharedSecrets.getJavaLangAccess().currentThread0();
assert thread.getCoroutineSupport() != null; assert thread.getCoroutineSupport() != null;
this.threadSupport = thread.getCoroutineSupport(); this.threadSupport = thread.getCoroutineSupport();
} }
// creates the initial coroutine for a new thread // creates the initial coroutine for a new thread
CoroutineBase(CoroutineSupport threadSupport, long data) { CoroutineBase(CoroutineSupport threadSupport, long nativeCoroutine) {
this.threadSupport = threadSupport; this.threadSupport = threadSupport;
this.data = data; this.nativeCoroutine = nativeCoroutine;
} }
protected abstract void run(); protected abstract void run();
@SuppressWarnings({ "unused" }) @SuppressWarnings({"unused"})
private final void startInternal() { private final void startInternal() {
assert threadSupport.getThread() == Thread.currentThread(); assert threadSupport.getThread() == SharedSecrets.getJavaLangAccess().currentThread0();
try { try {
if (CoroutineSupport.DEBUG) { // When we symmetricYieldTo a newly created coroutine,
System.out.println("starting coroutine " + this); // we'll expect the new coroutine release lock as soon as possible
} threadSupport.beforeResume(this);
run(); run();
} catch (Throwable t) { } catch (Throwable t) {
if (!(t instanceof CoroutineExitException)) { if (!(t instanceof CoroutineExitException)) {
...@@ -62,14 +64,12 @@ public abstract class CoroutineBase { ...@@ -62,14 +64,12 @@ public abstract class CoroutineBase {
} }
} finally { } finally {
finished = true; finished = true;
// use Thread.currentThread().getCoroutineSupport() because we might have been migrated to another thread! // threadSupport is fixed by steal()
if (this instanceof Coroutine) { threadSupport.beforeResume(this);
Thread.currentThread().getCoroutineSupport().terminateCoroutine();
} else { threadSupport.terminateCoroutine();
Thread.currentThread().getCoroutineSupport().terminateCallable();
}
} }
assert threadSupport.getThread() == Thread.currentThread(); assert threadSupport.getThread() == SharedSecrets.getJavaLangAccess().currentThread0();
} }
/** /**
...@@ -81,14 +81,13 @@ public abstract class CoroutineBase { ...@@ -81,14 +81,13 @@ public abstract class CoroutineBase {
/** /**
* @return the thread that this coroutine is associated with * @return the thread that this coroutine is associated with
* @throws NullPointerException * @throws NullPointerException if the coroutine has been terminated
* if the coroutine has terminated
*/ */
public Thread getThread() { public Thread getThread() {
return threadSupport.getThread(); return threadSupport.getThread();
} }
public static CoroutineBase current() { public static CoroutineBase current() {
return Thread.currentThread().getCoroutineSupport().getCurrent(); return SharedSecrets.getJavaLangAccess().currentThread0().getCoroutineSupport().getCurrent();
} }
} }
/*
* 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<T> {
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 <tt>initialValue</tt>
* 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<CoroutineLocal> {
/** 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: <tt>log2(n)</tt> cells are scanned, unless a stale entry is found, in which case
* <tt>log2(table.length)-1</tt> 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);
}
}
}
}
...@@ -25,24 +25,35 @@ ...@@ -25,24 +25,35 @@
package java.dyn; package java.dyn;
import com.alibaba.wisp.engine.WispTask;
import sun.misc.Contended;
import sun.misc.SharedSecrets;
import sun.reflect.generics.reflectiveObjects.NotImplementedException; import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
@Contended
public class CoroutineSupport { 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(); 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 // The thread that this CoroutineSupport belongs to. There's only one CoroutineSupport per Thread
private final Thread thread; private final Thread thread;
// The initial coroutine of the Thread // The initial coroutine of the Thread
private final Coroutine threadCoroutine; private final Coroutine threadCoroutine;
// The currently executing, symmetric or asymmetric coroutine // The currently executing coroutine
CoroutineBase currentCoroutine; private Coroutine currentCoroutine;
// The anchor of the doubly-linked ring of coroutines
Coroutine scheduledCoroutines; 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 { static {
registerNatives(); registerNatives();
...@@ -52,12 +63,11 @@ public class CoroutineSupport { ...@@ -52,12 +63,11 @@ public class CoroutineSupport {
if (thread.getCoroutineSupport() != null) { if (thread.getCoroutineSupport() != null) {
throw new IllegalArgumentException("Cannot instantiate CoroutineThreadSupport for existing Thread"); throw new IllegalArgumentException("Cannot instantiate CoroutineThreadSupport for existing Thread");
} }
id = idGen.incrementAndGet();
this.thread = thread; this.thread = thread;
threadCoroutine = new Coroutine(this, getThreadCoroutine()); threadCoroutine = new Coroutine(this, getNativeThreadCoroutine());
threadCoroutine.next = threadCoroutine; markThreadCoroutine(threadCoroutine.nativeCoroutine, threadCoroutine);
threadCoroutine.last = threadCoroutine;
currentCoroutine = threadCoroutine; currentCoroutine = threadCoroutine;
scheduledCoroutines = threadCoroutine;
} }
public Coroutine threadCoroutine() { public Coroutine threadCoroutine() {
...@@ -65,46 +75,34 @@ public class CoroutineSupport { ...@@ -65,46 +75,34 @@ public class CoroutineSupport {
} }
void addCoroutine(Coroutine coroutine, long stacksize) { void addCoroutine(Coroutine coroutine, long stacksize) {
assert scheduledCoroutines != null;
assert currentCoroutine != null; assert currentCoroutine != null;
lock();
coroutine.data = createCoroutine(coroutine, stacksize); try {
if (DEBUG) { coroutine.nativeCoroutine = createCoroutine(coroutine, stacksize);
System.out.println("add Coroutine " + coroutine + ", data" + coroutine.data); } finally {
} unlock();
// 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() { Thread getThread() {
return thread; return thread;
} }
public static void checkAndThrowException(Coroutine coroutine) {
checkAndThrowException0(coroutine.nativeCoroutine);
}
public void drain() { public void drain() {
if (Thread.currentThread() != thread) { if (Thread.currentThread() != thread) {
throw new IllegalArgumentException("Cannot drain another threads CoroutineThreadSupport"); throw new IllegalArgumentException("Cannot drain another threads CoroutineThreadSupport");
} }
if (DEBUG) { lock();
System.out.println("draining");
}
try { try {
// drain all scheduled coroutines // drain all coroutines
while (scheduledCoroutines.next != scheduledCoroutines) { Coroutine next = null;
symmetricExitInternal(scheduledCoroutines.next); while ((next = getNextCoroutine(currentCoroutine.nativeCoroutine)) != currentCoroutine) {
symmetricExitInternal(next);
} }
CoroutineBase coro; CoroutineBase coro;
...@@ -114,176 +112,207 @@ public class CoroutineSupport { ...@@ -114,176 +112,207 @@ public class CoroutineSupport {
} }
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); 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;
} }
void symmetricYield() { public void symmetricYieldTo(Coroutine target) {
if (scheduledCoroutines != currentCoroutine) { lock();
throw new IllegalThreadStateException("Cannot call yield from within an asymmetric coroutine"); if (target.threadSupport != this) {
} unlock();
assert currentCoroutine instanceof Coroutine;
if (TRACE) {
System.out.println("locking for symmetric yield...");
}
Coroutine next = scheduledCoroutines.next;
if (next == scheduledCoroutines) {
return; return;
} }
moveCoroutine(currentCoroutine.nativeCoroutine, target.nativeCoroutine);
if (TRACE) { unlockLater(target);
System.out.println("symmetric yield to " + next); unsafeSymmetricYieldTo(target);
} }
final Coroutine current = scheduledCoroutines;
scheduledCoroutines = next;
currentCoroutine = next;
switchTo(current, next); public void symmetricStopCoroutine(Coroutine target) {
Coroutine current;
lock();
try {
if (target.threadSupport != this) {
unlock();
return;
} }
current = currentCoroutine;
public void symmetricYieldTo(Coroutine target) { currentCoroutine = target;
if (scheduledCoroutines != currentCoroutine) { moveCoroutine(current.nativeCoroutine, target.nativeCoroutine);
throw new IllegalThreadStateException("Cannot call yield from within an asymmetric coroutine"); } finally {
unlock();
}
switchToAndExit(current, target);
} }
assert currentCoroutine instanceof Coroutine;
moveCoroutine(scheduledCoroutines, target);
final Coroutine current = scheduledCoroutines;
scheduledCoroutines = target;
currentCoroutine = target;
switchTo(current, target); /**
} * switch to coroutine and throw Exception in coroutine
*/
void symmetricExitInternal(Coroutine coroutine) {
assert currentCoroutine != coroutine;
assert coroutine.threadSupport == this;
private void moveCoroutine(Coroutine a, Coroutine position) { if (!testDisposableAndTryReleaseStack(coroutine.nativeCoroutine)) {
// remove a from the ring moveCoroutine(currentCoroutine.nativeCoroutine, coroutine.nativeCoroutine);
a.last.next = a.next;
a.next.last = a.last;
// ... and insert at the new position final Coroutine current = currentCoroutine;
a.next = position.next; currentCoroutine = coroutine;
a.last = position; switchToAndExit(current, coroutine);
a.next.last = a; beforeResume(current);
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; * terminate current coroutine and yield forward
currentCoroutine = target; */
void terminateCoroutine() {
assert currentCoroutine != threadCoroutine : "cannot exit thread coroutine";
assert currentCoroutine != getNextCoroutine(currentCoroutine.nativeCoroutine) : "last coroutine shouldn't call coroutineexit";
switchToAndExit(current, target); lock();
} Coroutine old = currentCoroutine;
Coroutine forward = getNextCoroutine(old.nativeCoroutine);
currentCoroutine = forward;
void symmetricExitInternal(Coroutine coroutine) { unlockLater(forward);
if (scheduledCoroutines != currentCoroutine) { switchToAndTerminate(old, forward);
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; * Steal coroutine from it's carrier thread to current thread.
coroutine.next.last = coroutine.last; *
* @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 (!isDisposable(coroutine.data)) { if (source == target) {
// and insert it before the current coroutine return Coroutine.StealResult.SUCCESS;
coroutine.last = scheduledCoroutines.last; }
coroutine.next = scheduledCoroutines;
coroutine.last.next = coroutine;
scheduledCoroutines.last = coroutine;
final Coroutine current = scheduledCoroutines; if (source.id < target.id) { // prevent dead lock
scheduledCoroutines = coroutine; if (!source.lockInternal(failOnContention)) {
currentCoroutine = coroutine; return Coroutine.StealResult.FAIL_BY_CONTENTION;
switchToAndExit(current, coroutine); }
target.lock();
} else {
target.lock();
if (!source.lockInternal(failOnContention)) {
target.unlock();
return Coroutine.StealResult.FAIL_BY_CONTENTION;
} }
} }
void asymmetricCall(AsymCoroutine<?, ?> target) { try {
if (target.threadSupport != this) { if (source.terminated || coroutine.finished ||
throw new IllegalArgumentException("Cannot activate a coroutine that belongs to another thread"); coroutine.threadSupport != source || // already been stolen
source.currentCoroutine == coroutine) {
return Coroutine.StealResult.FAIL_BY_STATUS;
} }
if (target.caller != null) { if (!stealCoroutine(coroutine.nativeCoroutine)) { // native frame
throw new IllegalArgumentException("Coroutine already in use"); return Coroutine.StealResult.FAIL_BY_NATIVE_FRAME;
} }
if (target.data == 0) { coroutine.threadSupport = target;
throw new IllegalArgumentException("Target coroutine has already finished"); } finally {
source.unlock();
target.unlock();
} }
if (TRACE) {
System.out.println("yieldCall " + target + " (" + target.data + ")"); return Coroutine.StealResult.SUCCESS;
} }
final CoroutineBase current = currentCoroutine; /**
target.caller = current; * Can not be stolen while executing this, because lock is held
currentCoroutine = target; */
switchTo(target.caller, target); void beforeResume(CoroutineBase source) {
if (source.needsUnlock) {
source.needsUnlock = false;
source.threadSupport.unlock();
}
} }
void asymmetricReturn(final AsymCoroutine<?, ?> current) { private void unlockLater(CoroutineBase next) {
if (current != currentCoroutine) { if (CHECK_LOCK && next.needsUnlock) {
throw new IllegalThreadStateException("cannot return from non-current fiber"); throw new InternalError("pending unlock");
} }
final CoroutineBase caller = current.caller; next.needsUnlock = true;
if (TRACE) {
System.out.println("yieldReturn " + caller + " (" + caller.data + ")");
} }
current.caller = null; private void lock() {
currentCoroutine = caller; boolean success = lockInternal(false);
switchTo(current, currentCoroutine); assert success;
} }
void asymmetricReturnAndTerminate(final AsymCoroutine<?, ?> current) { private boolean lockInternal(boolean tryingLock) {
if (current != currentCoroutine) { final Thread th = SharedSecrets.getJavaLangAccess().currentThread0();
throw new IllegalThreadStateException("cannot return from non-current fiber"); 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;
} }
final CoroutineBase caller = current.caller;
if (TRACE) {
System.out.println("yieldReturn " + caller + " (" + caller.data + ")");
} }
current.caller = null;
currentCoroutine = caller;
switchToAndTerminate(current, currentCoroutine);
} }
void terminateCoroutine() { private void unlock() {
assert currentCoroutine == scheduledCoroutines; if (CHECK_LOCK && SharedSecrets.getJavaLangAccess().currentThread0() != lockOwner) {
assert currentCoroutine != threadCoroutine : "cannot exit thread coroutine"; throw new InternalError("unlock from non-owner thread");
assert scheduledCoroutines != scheduledCoroutines.next : "last coroutine shouldn't call coroutineexit"; }
if (lockRecursive > 0) {
Coroutine old = scheduledCoroutines; lockRecursive--;
Coroutine forward = old.next; } else {
currentCoroutine = forward; LOCK_UPDATER.lazySet(this, null);
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() { private static final AtomicReferenceFieldUpdater<CoroutineSupport, Thread> LOCK_UPDATER;
assert currentCoroutine != scheduledCoroutines;
assert currentCoroutine instanceof AsymCoroutine<?, ?>;
if (DEBUG) { static {
System.out.println("to be terminated: " + currentCoroutine); LOCK_UPDATER = AtomicReferenceFieldUpdater.newUpdater(CoroutineSupport.class, Thread.class, "lockOwner");
}
asymmetricReturnAndTerminate((AsymCoroutine<?, ?>) currentCoroutine);
} }
public boolean isCurrent(CoroutineBase coroutine) { public boolean isCurrent(CoroutineBase coroutine) {
...@@ -294,20 +323,58 @@ public class CoroutineSupport { ...@@ -294,20 +323,58 @@ public class CoroutineSupport {
return currentCoroutine; return currentCoroutine;
} }
private static native void registerNatives(); private static native void registerNatives();
private static native long getThreadCoroutine(); 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 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 switchToAndTerminate(CoroutineBase current, CoroutineBase target);
private static native void switchToAndExit(CoroutineBase current, CoroutineBase target); private static native boolean testDisposableAndTryReleaseStack(long coroutine);
private static native boolean isDisposable(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(); 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);
} }
...@@ -1773,7 +1773,7 @@ class SecurityManager { ...@@ -1773,7 +1773,7 @@ class SecurityManager {
* @see java.lang.ThreadGroup * @see java.lang.ThreadGroup
*/ */
public ThreadGroup getThreadGroup() { public ThreadGroup getThreadGroup() {
return Thread.currentThread().getThreadGroup(); return Thread.currentThread0().getThreadGroup();
} }
} }
...@@ -34,12 +34,14 @@ import java.util.StringTokenizer; ...@@ -34,12 +34,14 @@ import java.util.StringTokenizer;
import java.util.Map; import java.util.Map;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.AllPermission;
import java.nio.channels.Channel; import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider; import java.nio.channels.spi.SelectorProvider;
import com.alibaba.rcm.internal.AbstractResourceContainer; import com.alibaba.rcm.internal.AbstractResourceContainer;
import com.alibaba.tenant.TenantContainer; import com.alibaba.tenant.TenantContainer;
import com.alibaba.tenant.TenantGlobals; import com.alibaba.tenant.TenantGlobals;
import com.alibaba.wisp.engine.WispEngine;
import com.alibaba.wisp.engine.WispTask;
import sun.misc.VM; import sun.misc.VM;
import sun.nio.ch.Interruptible; import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive; import sun.reflect.CallerSensitive;
...@@ -1318,6 +1320,44 @@ public final class System { ...@@ -1318,6 +1320,44 @@ public final class System {
public AbstractResourceContainer getInheritedResourceContainer(Thread thread) { public AbstractResourceContainer getInheritedResourceContainer(Thread thread) {
return thread.inheritedResourceContainer; 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();
}
}); });
} }
} }
...@@ -39,6 +39,9 @@ import java.util.concurrent.ConcurrentMap; ...@@ -39,6 +39,9 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
import com.alibaba.rcm.internal.AbstractResourceContainer; import com.alibaba.rcm.internal.AbstractResourceContainer;
import sun.misc.VM; import sun.misc.VM;
import com.alibaba.wisp.engine.*;
import sun.misc.SharedSecrets;
import sun.misc.WispEngineAccess;
import sun.nio.ch.Interruptible; import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive; import sun.reflect.CallerSensitive;
import sun.reflect.Reflection; import sun.reflect.Reflection;
...@@ -277,22 +280,58 @@ class Thread implements Runnable { ...@@ -277,22 +280,58 @@ class Thread implements Runnable {
private CoroutineSupport coroutineSupport; private CoroutineSupport coroutineSupport;
WispTask wispTask;
volatile boolean wispIsAlive;
// wispTask is set by carrier thread async, so we need additional flag
public CoroutineSupport getCoroutineSupport() { public CoroutineSupport getCoroutineSupport() {
if (coroutineSupport != null) {
return coroutineSupport; return coroutineSupport;
} }
Thread t = currentThread0();
return t == this ? null : t.getCoroutineSupport();
}
private void initializeCoroutineSupport() { private void initializeCoroutineSupport() {
if (sun.misc.VM.isEnableCoroutine()) { if (coroutineSupport == null) {
coroutineSupport = new CoroutineSupport(this); 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 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. * @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 * A hint to the scheduler that the current thread is willing to yield
...@@ -310,7 +349,15 @@ class Thread implements Runnable { ...@@ -310,7 +349,15 @@ class Thread implements Runnable {
* concurrency control constructs such as the ones in the * concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package. * {@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 * Causes the currently executing thread to sleep (temporarily cease
...@@ -329,7 +376,22 @@ class Thread implements Runnable { ...@@ -329,7 +376,22 @@ class Thread implements Runnable {
* <i>interrupted status</i> of the current thread is * <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown. * 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 * Causes the currently executing thread to sleep (temporarily cease
...@@ -754,7 +816,10 @@ class Thread implements Runnable { ...@@ -754,7 +816,10 @@ class Thread implements Runnable {
boolean started = false; boolean started = false;
try { try {
if (!(WEA != null && WispEngine.enableThreadAsWisp() &&
WEA.tryStartThreadAsWisp(this, target))) {
start0(); start0();
}
started = true; started = true;
} finally { } finally {
try { try {
...@@ -793,11 +858,7 @@ class Thread implements Runnable { ...@@ -793,11 +858,7 @@ class Thread implements Runnable {
* This method is called by the system to give a Thread * This method is called by the system to give a Thread
* a chance to clean up before it actually exits. * a chance to clean up before it actually exits.
*/ */
private void exit() { void exit() {
if (sun.misc.VM.isEnableCoroutine() && (coroutineSupport != null)) {
coroutineSupport.drain();
}
if (group != null) { if (group != null) {
group.threadTerminated(this); group.threadTerminated(this);
group = null; group = null;
...@@ -959,19 +1020,30 @@ class Thread implements Runnable { ...@@ -959,19 +1020,30 @@ class Thread implements Runnable {
* @spec JSR-51 * @spec JSR-51
*/ */
public void interrupt() { public void interrupt() {
if (this != Thread.currentThread())
if (this != Thread.currentThread()) {
checkAccess(); checkAccess();
}
synchronized (blockerLock) { synchronized (blockerLock) {
Interruptible b = blocker; Interruptible b = blocker;
if (b != null) { if (b != null) {
if (WEA != null && wispTask != null) {
WEA.interrupt(wispTask);
} else {
interrupt0(); // Just to set the interrupt flag interrupt0(); // Just to set the interrupt flag
}
b.interrupt(this); b.interrupt(this);
return; return;
} }
} }
if (WEA != null && wispTask != null) {
WEA.interrupt(wispTask);
} else {
interrupt0(); interrupt0();
} }
}
/** /**
* Tests whether the current thread has been interrupted. The * Tests whether the current thread has been interrupted. The
...@@ -991,7 +1063,14 @@ class Thread implements Runnable { ...@@ -991,7 +1063,14 @@ class Thread implements Runnable {
* @revised 6.0 * @revised 6.0
*/ */
public static boolean interrupted() { 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 { ...@@ -1008,6 +1087,9 @@ class Thread implements Runnable {
* @revised 6.0 * @revised 6.0
*/ */
public boolean isInterrupted() { public boolean isInterrupted() {
if (WEA != null && wispTask != null) {
return WEA.testInterruptedAndClear(wispTask, false);
}
return isInterrupted(false); return isInterrupted(false);
} }
...@@ -1047,7 +1129,14 @@ class Thread implements Runnable { ...@@ -1047,7 +1129,14 @@ class Thread implements Runnable {
* @return <code>true</code> if this thread is alive; * @return <code>true</code> if this thread is alive;
* <code>false</code> otherwise. * <code>false</code> 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. * Suspends this thread.
...@@ -1581,7 +1670,29 @@ class Thread implements Runnable { ...@@ -1581,7 +1670,29 @@ class Thread implements Runnable {
* @since 1.5 * @since 1.5
*/ */
public StackTraceElement[] getStackTrace() { 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 // check for getStackTrace permission
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
...@@ -1864,6 +1975,11 @@ class Thread implements Runnable { ...@@ -1864,6 +1975,11 @@ class Thread implements Runnable {
return sun.misc.VM.toThreadState(threadStatus); return sun.misc.VM.toThreadState(threadStatus);
} }
/**
* @return if this thread is still executing the same JNI code
*/
native boolean isInSameNative();
// Added in JSR-166 // Added in JSR-166
/** /**
...@@ -2094,4 +2210,15 @@ class Thread implements Runnable { ...@@ -2094,4 +2210,15 @@ class Thread implements Runnable {
private native void resume0(); private native void resume0();
private native void interrupt0(); private native void interrupt0();
private native void setNativeName(String name); 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();
}
} }
...@@ -37,6 +37,7 @@ import javax.management.ObjectName; ...@@ -37,6 +37,7 @@ import javax.management.ObjectName;
import com.alibaba.management.TenantContainerMXBean; import com.alibaba.management.TenantContainerMXBean;
import com.alibaba.management.ElasticHeapMXBean; import com.alibaba.management.ElasticHeapMXBean;
import com.alibaba.management.WispCounterMXBean;
import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.HotSpotDiagnosticMXBean;
import com.sun.management.UnixOperatingSystemMXBean; import com.sun.management.UnixOperatingSystemMXBean;
...@@ -303,6 +304,19 @@ enum PlatformComponent { ...@@ -303,6 +304,19 @@ enum PlatformComponent {
public List<ElasticHeapMXBean> getMXBeans() { public List<ElasticHeapMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getElasticHeapMXBean()); return Collections.singletonList(ManagementFactoryHelper.getElasticHeapMXBean());
} }
}),
/**
* Wisp Counter.
*/
WISP_COUNTER(
"com.alibaba.management.WispCounterMXBean",
"com.alibaba.management", "WispCounter", defaultKeyProperties(),
true, // singleton
new MXBeanFetcher<WispCounterMXBean>() {
public List<WispCounterMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getWispCounterMXBean());
}
}); });
......
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
package java.net; 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.io.IOException;
import java.nio.channels.DatagramChannel; import java.nio.channels.DatagramChannel;
import java.security.AccessController; import java.security.AccessController;
...@@ -65,6 +70,13 @@ import java.security.PrivilegedExceptionAction; ...@@ -65,6 +70,13 @@ import java.security.PrivilegedExceptionAction;
*/ */
public public
class DatagramSocket implements java.io.Closeable { class DatagramSocket implements java.io.Closeable {
/**
* If WispEngine.transparentWispSwitch(), proxy all
* socket request to this impl.
*/
private WispUdpSocketImpl asyncImpl;
/** /**
* Various states of this socket. * Various states of this socket.
*/ */
...@@ -235,8 +247,12 @@ class DatagramSocket implements java.io.Closeable { ...@@ -235,8 +247,12 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public DatagramSocket(SocketAddress bindaddr) throws SocketException { public DatagramSocket(SocketAddress bindaddr) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl = new WispUdpSocketImpl(this);
} else {
// create a datagram socket. // create a datagram socket.
createImpl(); createImpl();
}
if (bindaddr != null) { if (bindaddr != null) {
try { try {
bind(bindaddr); bind(bindaddr);
...@@ -322,6 +338,8 @@ class DatagramSocket implements java.io.Closeable { ...@@ -322,6 +338,8 @@ class DatagramSocket implements java.io.Closeable {
static Class<?> implClass = null; static Class<?> implClass = null;
void createImpl() throws SocketException { void createImpl() throws SocketException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (impl == null) { if (impl == null) {
if (factory != null) { if (factory != null) {
impl = factory.createDatagramSocketImpl(); impl = factory.createDatagramSocketImpl();
...@@ -349,6 +367,8 @@ class DatagramSocket implements java.io.Closeable { ...@@ -349,6 +367,8 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
DatagramSocketImpl getImpl() throws SocketException { DatagramSocketImpl getImpl() throws SocketException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (!created) if (!created)
createImpl(); createImpl();
return impl; return impl;
...@@ -378,6 +398,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -378,6 +398,10 @@ class DatagramSocket implements java.io.Closeable {
addr = new InetSocketAddress(0); addr = new InetSocketAddress(0);
if (!(addr instanceof InetSocketAddress)) if (!(addr instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type!"); throw new IllegalArgumentException("Unsupported address type!");
if (WispEngine.transparentWispSwitch()) {
asyncImpl.bind(addr);
return;
}
InetSocketAddress epoint = (InetSocketAddress) addr; InetSocketAddress epoint = (InetSocketAddress) addr;
if (epoint.isUnresolved()) if (epoint.isUnresolved())
throw new SocketException("Unresolved address"); throw new SocketException("Unresolved address");
...@@ -454,6 +478,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -454,6 +478,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #disconnect * @see #disconnect
*/ */
public void connect(InetAddress address, int port) { public void connect(InetAddress address, int port) {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.connect(address, port);
return;
}
try { try {
connectInternal(address, port); connectInternal(address, port);
} catch (SocketException se) { } catch (SocketException se) {
...@@ -484,6 +512,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -484,6 +512,10 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public void connect(SocketAddress addr) throws SocketException { public void connect(SocketAddress addr) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.connect(addr);
return;
}
if (addr == null) if (addr == null)
throw new IllegalArgumentException("Address can't be null"); throw new IllegalArgumentException("Address can't be null");
if (!(addr instanceof InetSocketAddress)) if (!(addr instanceof InetSocketAddress))
...@@ -501,6 +533,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -501,6 +533,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #connect * @see #connect
*/ */
public void disconnect() { public void disconnect() {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.disconnect();
return;
}
synchronized (this) { synchronized (this) {
if (isClosed()) if (isClosed())
return; return;
...@@ -525,6 +561,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -525,6 +561,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public boolean isBound() { public boolean isBound() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.isBound();
}
return bound; return bound;
} }
...@@ -539,6 +578,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -539,6 +578,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public boolean isConnected() { public boolean isConnected() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.isConnected();
}
return connectState != ST_NOT_CONNECTED; return connectState != ST_NOT_CONNECTED;
} }
...@@ -553,6 +595,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -553,6 +595,9 @@ class DatagramSocket implements java.io.Closeable {
* @return the address to which this socket is connected. * @return the address to which this socket is connected.
*/ */
public InetAddress getInetAddress() { public InetAddress getInetAddress() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getInetAddress();
}
return connectedAddress; return connectedAddress;
} }
...@@ -567,6 +612,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -567,6 +612,9 @@ class DatagramSocket implements java.io.Closeable {
* @return the port number to which this socket is connected. * @return the port number to which this socket is connected.
*/ */
public int getPort() { public int getPort() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getPort();
}
return connectedPort; return connectedPort;
} }
...@@ -652,6 +700,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -652,6 +700,10 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public void send(DatagramPacket p) throws IOException { public void send(DatagramPacket p) throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.send(p);
return;
}
InetAddress packetAddress = null; InetAddress packetAddress = null;
synchronized (p) { synchronized (p) {
if (isClosed()) if (isClosed())
...@@ -726,6 +778,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -726,6 +778,10 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public synchronized void receive(DatagramPacket p) throws IOException { public synchronized void receive(DatagramPacket p) throws IOException {
if (WispEngine.transparentWispSwitch()) {
p.length = asyncImpl.receive(p, p.bufLength);
return;
}
synchronized (p) { synchronized (p) {
if (!isBound()) if (!isBound())
bind(new InetSocketAddress(0)); bind(new InetSocketAddress(0));
...@@ -845,6 +901,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -845,6 +901,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.1 * @since 1.1
*/ */
public InetAddress getLocalAddress() { public InetAddress getLocalAddress() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getLocalAddress();
}
if (isClosed()) if (isClosed())
return null; return null;
InetAddress in = null; InetAddress in = null;
...@@ -872,6 +931,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -872,6 +931,9 @@ class DatagramSocket implements java.io.Closeable {
{@code 0} if it is not bound yet. {@code 0} if it is not bound yet.
*/ */
public int getLocalPort() { public int getLocalPort() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getLocalPort();
}
if (isClosed()) if (isClosed())
return -1; return -1;
try { try {
...@@ -897,6 +959,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -897,6 +959,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #getSoTimeout() * @see #getSoTimeout()
*/ */
public synchronized void setSoTimeout(int timeout) throws SocketException { public synchronized void setSoTimeout(int timeout) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setSoTimeout(timeout);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
...@@ -912,6 +978,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -912,6 +978,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setSoTimeout(int) * @see #setSoTimeout(int)
*/ */
public synchronized int getSoTimeout() throws SocketException { public synchronized int getSoTimeout() throws SocketException {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getSoTimeout();
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (getImpl() == null) if (getImpl() == null)
...@@ -956,6 +1025,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -956,6 +1025,10 @@ class DatagramSocket implements java.io.Closeable {
*/ */
public synchronized void setSendBufferSize(int size) public synchronized void setSendBufferSize(int size)
throws SocketException{ throws SocketException{
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setSendBufferSize(size);
return;
}
if (!(size > 0)) { if (!(size > 0)) {
throw new IllegalArgumentException("negative send size"); throw new IllegalArgumentException("negative send size");
} }
...@@ -974,6 +1047,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -974,6 +1047,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setSendBufferSize * @see #setSendBufferSize
*/ */
public synchronized int getSendBufferSize() throws SocketException { public synchronized int getSendBufferSize() throws SocketException {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getSendBufferSize();
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
int result = 0; int result = 0;
...@@ -1014,6 +1090,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1014,6 +1090,10 @@ class DatagramSocket implements java.io.Closeable {
*/ */
public synchronized void setReceiveBufferSize(int size) public synchronized void setReceiveBufferSize(int size)
throws SocketException{ throws SocketException{
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setReceiveBufferSize(size);
return;
}
if (size <= 0) { if (size <= 0) {
throw new IllegalArgumentException("invalid receive size"); throw new IllegalArgumentException("invalid receive size");
} }
...@@ -1032,6 +1112,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1032,6 +1112,9 @@ class DatagramSocket implements java.io.Closeable {
*/ */
public synchronized int getReceiveBufferSize() public synchronized int getReceiveBufferSize()
throws SocketException{ throws SocketException{
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getReceiveBufferSize();
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
int result = 0; int result = 0;
...@@ -1077,6 +1160,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1077,6 +1160,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #isClosed() * @see #isClosed()
*/ */
public synchronized void setReuseAddress(boolean on) throws SocketException { public synchronized void setReuseAddress(boolean on) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setReuseAddress(on);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
// Integer instead of Boolean for compatibility with older DatagramSocketImpl // Integer instead of Boolean for compatibility with older DatagramSocketImpl
...@@ -1096,6 +1183,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1096,6 +1183,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setReuseAddress(boolean) * @see #setReuseAddress(boolean)
*/ */
public synchronized boolean getReuseAddress() throws SocketException { public synchronized boolean getReuseAddress() throws SocketException {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getReuseAddress();
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR); Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);
...@@ -1120,6 +1210,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1120,6 +1210,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #getBroadcast() * @see #getBroadcast()
*/ */
public synchronized void setBroadcast(boolean on) throws SocketException { public synchronized void setBroadcast(boolean on) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setBroadcast(on);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on)); getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on));
...@@ -1134,6 +1228,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1134,6 +1228,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setBroadcast(boolean) * @see #setBroadcast(boolean)
*/ */
public synchronized boolean getBroadcast() throws SocketException { public synchronized boolean getBroadcast() throws SocketException {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getBroadcast();
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue(); return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue();
...@@ -1177,6 +1274,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1177,6 +1274,10 @@ class DatagramSocket implements java.io.Closeable {
* @see #getTrafficClass * @see #getTrafficClass
*/ */
public synchronized void setTrafficClass(int tc) throws SocketException { public synchronized void setTrafficClass(int tc) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setTrafficClass(tc);
return;
}
if (tc < 0 || tc > 255) if (tc < 0 || tc > 255)
throw new IllegalArgumentException("tc is not in range 0 -- 255"); throw new IllegalArgumentException("tc is not in range 0 -- 255");
...@@ -1209,6 +1310,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1209,6 +1310,9 @@ class DatagramSocket implements java.io.Closeable {
* @see #setTrafficClass(int) * @see #setTrafficClass(int)
*/ */
public synchronized int getTrafficClass() throws SocketException { public synchronized int getTrafficClass() throws SocketException {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getTrafficClass();
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue(); return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue();
...@@ -1227,6 +1331,10 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1227,6 +1331,10 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public void close() { public void close() {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.close();
return;
}
synchronized(closeLock) { synchronized(closeLock) {
if (isClosed()) if (isClosed())
return; return;
...@@ -1242,6 +1350,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1242,6 +1350,9 @@ class DatagramSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public boolean isClosed() { public boolean isClosed() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.isClosed();
}
synchronized(closeLock) { synchronized(closeLock) {
return closed; return closed;
} }
...@@ -1262,6 +1373,9 @@ class DatagramSocket implements java.io.Closeable { ...@@ -1262,6 +1373,9 @@ class DatagramSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public DatagramChannel getChannel() { public DatagramChannel getChannel() {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getChannel();
}
return null; return null;
} }
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
package java.net; package java.net;
import com.alibaba.wisp.engine.WispEngine;
import sun.nio.ch.WispServerSocketImpl;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.ServerSocketChannel;
...@@ -52,6 +55,8 @@ import sun.security.util.SecurityConstants; ...@@ -52,6 +55,8 @@ import sun.security.util.SecurityConstants;
*/ */
public public
class ServerSocket implements java.io.Closeable { class ServerSocket implements java.io.Closeable {
private WispServerSocketImpl asyncImpl;
/** /**
* Various states of this socket. * Various states of this socket.
*/ */
...@@ -80,6 +85,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -80,6 +85,9 @@ class ServerSocket implements java.io.Closeable {
*/ */
ServerSocket(SocketImpl impl) { ServerSocket(SocketImpl impl) {
checkPermission(); checkPermission();
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
this.impl = impl; this.impl = impl;
impl.setServerSocket(this); impl.setServerSocket(this);
} }
...@@ -99,6 +107,10 @@ class ServerSocket implements java.io.Closeable { ...@@ -99,6 +107,10 @@ class ServerSocket implements java.io.Closeable {
* @revised 1.4 * @revised 1.4
*/ */
public ServerSocket() throws IOException { public ServerSocket() throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl = new WispServerSocketImpl();
return;
}
setImpl(); setImpl();
} }
...@@ -242,7 +254,12 @@ class ServerSocket implements java.io.Closeable { ...@@ -242,7 +254,12 @@ class ServerSocket implements java.io.Closeable {
* @since JDK1.1 * @since JDK1.1
*/ */
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException { public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl = new WispServerSocketImpl();
} else {
setImpl(); setImpl();
}
if (port < 0 || port > 0xFFFF) if (port < 0 || port > 0xFFFF)
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Port value out of range: " + port); "Port value out of range: " + port);
...@@ -268,12 +285,18 @@ class ServerSocket implements java.io.Closeable { ...@@ -268,12 +285,18 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
SocketImpl getImpl() throws SocketException { SocketImpl getImpl() throws SocketException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (!created) if (!created)
createImpl(); createImpl();
return impl; return impl;
} }
private void checkOldImpl() { private void checkOldImpl() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (impl == null) if (impl == null)
return; return;
// SocketImpl.connect() is a protected method, therefore we need to use // SocketImpl.connect() is a protected method, therefore we need to use
...@@ -294,6 +317,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -294,6 +317,9 @@ class ServerSocket implements java.io.Closeable {
} }
private void setImpl() { private void setImpl() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (factory != null) { if (factory != null) {
impl = factory.createSocketImpl(); impl = factory.createSocketImpl();
checkOldImpl(); checkOldImpl();
...@@ -313,6 +339,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -313,6 +339,9 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
void createImpl() throws SocketException { void createImpl() throws SocketException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (impl == null) if (impl == null)
setImpl(); setImpl();
try { try {
...@@ -341,6 +370,10 @@ class ServerSocket implements java.io.Closeable { ...@@ -341,6 +370,10 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public void bind(SocketAddress endpoint) throws IOException { public void bind(SocketAddress endpoint) throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.bind(endpoint);
return;
}
bind(endpoint, 50); bind(endpoint, 50);
} }
...@@ -370,6 +403,10 @@ class ServerSocket implements java.io.Closeable { ...@@ -370,6 +403,10 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public void bind(SocketAddress endpoint, int backlog) throws IOException { public void bind(SocketAddress endpoint, int backlog) throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.bind(endpoint, backlog);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!oldImpl && isBound()) if (!oldImpl && isBound())
...@@ -418,6 +455,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -418,6 +455,9 @@ class ServerSocket implements java.io.Closeable {
* @see SecurityManager#checkConnect * @see SecurityManager#checkConnect
*/ */
public InetAddress getInetAddress() { public InetAddress getInetAddress() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getInetAddress();
if (!isBound()) if (!isBound())
return null; return null;
try { try {
...@@ -447,6 +487,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -447,6 +487,9 @@ class ServerSocket implements java.io.Closeable {
* -1 if the socket is not bound yet. * -1 if the socket is not bound yet.
*/ */
public int getLocalPort() { public int getLocalPort() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getLocalPort();
if (!isBound()) if (!isBound())
return -1; return -1;
try { try {
...@@ -524,6 +567,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -524,6 +567,9 @@ class ServerSocket implements java.io.Closeable {
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!isBound()) if (!isBound())
throw new SocketException("Socket is not bound yet"); throw new SocketException("Socket is not bound yet");
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.accept();
}
Socket s = new Socket((SocketImpl) null); Socket s = new Socket((SocketImpl) null);
implAccept(s); implAccept(s);
return s; return s;
...@@ -546,6 +592,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -546,6 +592,9 @@ class ServerSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
protected final void implAccept(Socket s) throws IOException { protected final void implAccept(Socket s) throws IOException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
SocketImpl si = null; SocketImpl si = null;
try { try {
if (s.impl == null) if (s.impl == null)
...@@ -593,6 +642,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -593,6 +642,9 @@ class ServerSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public void close() throws IOException { public void close() throws IOException {
if (WispEngine.transparentWispSwitch())
asyncImpl.close();
synchronized(closeLock) { synchronized(closeLock) {
if (isClosed()) if (isClosed())
return; return;
...@@ -619,6 +671,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -619,6 +671,9 @@ class ServerSocket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public ServerSocketChannel getChannel() { public ServerSocketChannel getChannel() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getChannel();
return null; return null;
} }
...@@ -629,6 +684,8 @@ class ServerSocket implements java.io.Closeable { ...@@ -629,6 +684,8 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public boolean isBound() { public boolean isBound() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.isBound();
// Before 1.3 ServerSockets were always bound during creation // Before 1.3 ServerSockets were always bound during creation
return bound || oldImpl; return bound || oldImpl;
} }
...@@ -640,6 +697,8 @@ class ServerSocket implements java.io.Closeable { ...@@ -640,6 +697,8 @@ class ServerSocket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public boolean isClosed() { public boolean isClosed() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.isClosed();
synchronized(closeLock) { synchronized(closeLock) {
return closed; return closed;
} }
...@@ -662,6 +721,10 @@ class ServerSocket implements java.io.Closeable { ...@@ -662,6 +721,10 @@ class ServerSocket implements java.io.Closeable {
* @see #getSoTimeout() * @see #getSoTimeout()
*/ */
public synchronized void setSoTimeout(int timeout) throws SocketException { public synchronized void setSoTimeout(int timeout) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setSoTimeout(timeout);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
...@@ -676,6 +739,8 @@ class ServerSocket implements java.io.Closeable { ...@@ -676,6 +739,8 @@ class ServerSocket implements java.io.Closeable {
* @see #setSoTimeout(int) * @see #setSoTimeout(int)
*/ */
public synchronized int getSoTimeout() throws IOException { public synchronized int getSoTimeout() throws IOException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getSoTimeout();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
...@@ -724,6 +789,10 @@ class ServerSocket implements java.io.Closeable { ...@@ -724,6 +789,10 @@ class ServerSocket implements java.io.Closeable {
* @see #isClosed() * @see #isClosed()
*/ */
public void setReuseAddress(boolean on) throws SocketException { public void setReuseAddress(boolean on) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setReuseAddress(on);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
...@@ -740,6 +809,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -740,6 +809,9 @@ class ServerSocket implements java.io.Closeable {
* @see #setReuseAddress(boolean) * @see #setReuseAddress(boolean)
*/ */
public boolean getReuseAddress() throws SocketException { public boolean getReuseAddress() throws SocketException {
if (WispEngine.transparentWispSwitch()) {
return asyncImpl.getReuseAddress();
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue(); return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
...@@ -759,6 +831,8 @@ class ServerSocket implements java.io.Closeable { ...@@ -759,6 +831,8 @@ class ServerSocket implements java.io.Closeable {
* @return a string representation of this socket. * @return a string representation of this socket.
*/ */
public String toString() { public String toString() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.toString();
if (!isBound()) if (!isBound())
return "ServerSocket[unbound]"; return "ServerSocket[unbound]";
InetAddress in; InetAddress in;
...@@ -771,10 +845,14 @@ class ServerSocket implements java.io.Closeable { ...@@ -771,10 +845,14 @@ class ServerSocket implements java.io.Closeable {
} }
void setBound() { void setBound() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
bound = true; bound = true;
} }
void setCreated() { void setCreated() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
created = true; created = true;
} }
...@@ -809,6 +887,8 @@ class ServerSocket implements java.io.Closeable { ...@@ -809,6 +887,8 @@ class ServerSocket implements java.io.Closeable {
* @see SecurityManager#checkSetFactory * @see SecurityManager#checkSetFactory
*/ */
public static synchronized void setSocketFactory(SocketImplFactory fac) throws IOException { public static synchronized void setSocketFactory(SocketImplFactory fac) throws IOException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (factory != null) { if (factory != null) {
throw new SocketException("factory already defined"); throw new SocketException("factory already defined");
} }
...@@ -856,6 +936,10 @@ class ServerSocket implements java.io.Closeable { ...@@ -856,6 +936,10 @@ class ServerSocket implements java.io.Closeable {
* @see #getReceiveBufferSize * @see #getReceiveBufferSize
*/ */
public synchronized void setReceiveBufferSize (int size) throws SocketException { public synchronized void setReceiveBufferSize (int size) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setReceiveBufferSize(size);
return;
}
if (!(size > 0)) { if (!(size > 0)) {
throw new IllegalArgumentException("negative receive size"); throw new IllegalArgumentException("negative receive size");
} }
...@@ -880,6 +964,9 @@ class ServerSocket implements java.io.Closeable { ...@@ -880,6 +964,9 @@ class ServerSocket implements java.io.Closeable {
*/ */
public synchronized int getReceiveBufferSize() public synchronized int getReceiveBufferSize()
throws SocketException{ throws SocketException{
if (WispEngine.transparentWispSwitch())
asyncImpl.getReceiveBufferSize();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
int result = 0; int result = 0;
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
package java.net; package java.net;
import sun.security.util.SecurityConstants; import sun.security.util.SecurityConstants;
import com.alibaba.wisp.engine.WispEngine;
import sun.nio.ch.WispSocketImpl;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
...@@ -54,6 +56,9 @@ import java.security.PrivilegedAction; ...@@ -54,6 +56,9 @@ import java.security.PrivilegedAction;
*/ */
public public
class Socket implements java.io.Closeable { class Socket implements java.io.Closeable {
private WispSocketImpl asyncImpl;
/** /**
* Various states of this socket. * Various states of this socket.
*/ */
...@@ -83,9 +88,19 @@ class Socket implements java.io.Closeable { ...@@ -83,9 +88,19 @@ class Socket implements java.io.Closeable {
* @revised 1.4 * @revised 1.4
*/ */
public Socket() { public Socket() {
if (WispEngine.transparentWispSwitch()) {
asyncImpl = new WispSocketImpl(this);
return;
}
setImpl(); 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, * Creates an unconnected socket, specifying the type of proxy, if any,
* that should be used regardless of any other settings. * that should be used regardless of any other settings.
...@@ -115,6 +130,9 @@ class Socket implements java.io.Closeable { ...@@ -115,6 +130,9 @@ class Socket implements java.io.Closeable {
* @since 1.5 * @since 1.5
*/ */
public Socket(Proxy proxy) { public Socket(Proxy proxy) {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
// Create a copy of Proxy as a security measure // Create a copy of Proxy as a security measure
if (proxy == null) { if (proxy == null) {
throw new IllegalArgumentException("Invalid Proxy"); throw new IllegalArgumentException("Invalid Proxy");
...@@ -171,6 +189,8 @@ class Socket implements java.io.Closeable { ...@@ -171,6 +189,8 @@ class Socket implements java.io.Closeable {
checkPermission(impl); checkPermission(impl);
this.impl = impl; this.impl = impl;
if (impl != null) { if (impl != null) {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
checkOldImpl(); checkOldImpl();
this.impl.setSocket(this); this.impl.setSocket(this);
} }
...@@ -439,13 +459,21 @@ class Socket implements java.io.Closeable { ...@@ -439,13 +459,21 @@ class Socket implements java.io.Closeable {
private Socket(SocketAddress address, SocketAddress localAddr, private Socket(SocketAddress address, SocketAddress localAddr,
boolean stream) throws IOException { boolean stream) throws IOException {
if (WispEngine.transparentWispSwitch()) {
if (!stream)
throw new UnsupportedOperationException();
asyncImpl = new WispSocketImpl(this);
} else {
setImpl(); setImpl();
}
// backward compatibility // backward compatibility
if (address == null) if (address == null)
throw new NullPointerException(); throw new NullPointerException();
try { try {
if (!WispEngine.transparentWispSwitch())
createImpl(stream); createImpl(stream);
if (localAddr != null) if (localAddr != null)
bind(localAddr); bind(localAddr);
...@@ -469,6 +497,9 @@ class Socket implements java.io.Closeable { ...@@ -469,6 +497,9 @@ class Socket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
void createImpl(boolean stream) throws SocketException { void createImpl(boolean stream) throws SocketException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (impl == null) if (impl == null)
setImpl(); setImpl();
try { try {
...@@ -480,6 +511,9 @@ class Socket implements java.io.Closeable { ...@@ -480,6 +511,9 @@ class Socket implements java.io.Closeable {
} }
private void checkOldImpl() { private void checkOldImpl() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (impl == null) if (impl == null)
return; return;
// SocketImpl.connect() is a protected method, therefore we need to use // SocketImpl.connect() is a protected method, therefore we need to use
...@@ -512,6 +546,9 @@ class Socket implements java.io.Closeable { ...@@ -512,6 +546,9 @@ class Socket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
void setImpl() { void setImpl() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (factory != null) { if (factory != null) {
impl = factory.createSocketImpl(); impl = factory.createSocketImpl();
checkOldImpl(); checkOldImpl();
...@@ -534,6 +571,9 @@ class Socket implements java.io.Closeable { ...@@ -534,6 +571,9 @@ class Socket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
SocketImpl getImpl() throws SocketException { SocketImpl getImpl() throws SocketException {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (!created) if (!created)
createImpl(true); createImpl(true);
return impl; return impl;
...@@ -553,6 +593,10 @@ class Socket implements java.io.Closeable { ...@@ -553,6 +593,10 @@ class Socket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public void connect(SocketAddress endpoint) throws IOException { public void connect(SocketAddress endpoint) throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.connect(endpoint);
return;
}
connect(endpoint, 0); connect(endpoint, 0);
} }
...@@ -589,6 +633,11 @@ class Socket implements java.io.Closeable { ...@@ -589,6 +633,11 @@ class Socket implements java.io.Closeable {
if (!(endpoint instanceof InetSocketAddress)) if (!(endpoint instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type"); throw new IllegalArgumentException("Unsupported address type");
if (WispEngine.transparentWispSwitch()) {
asyncImpl.connect(endpoint, timeout);
return;
}
InetSocketAddress epoint = (InetSocketAddress) endpoint; InetSocketAddress epoint = (InetSocketAddress) endpoint;
InetAddress addr = epoint.getAddress (); InetAddress addr = epoint.getAddress ();
int port = epoint.getPort(); int port = epoint.getPort();
...@@ -639,6 +688,11 @@ class Socket implements java.io.Closeable { ...@@ -639,6 +688,11 @@ class Socket implements java.io.Closeable {
* @see #isBound * @see #isBound
*/ */
public void bind(SocketAddress bindpoint) throws IOException { public void bind(SocketAddress bindpoint) throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.bind(bindpoint);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!oldImpl && isBound()) if (!oldImpl && isBound())
...@@ -664,6 +718,9 @@ class Socket implements java.io.Closeable { ...@@ -664,6 +718,9 @@ class Socket implements java.io.Closeable {
} }
private void checkAddress (InetAddress addr, String op) { private void checkAddress (InetAddress addr, String op) {
if (WispEngine.transparentWispSwitch()) {
throw new UnsupportedOperationException();
}
if (addr == null) { if (addr == null) {
return; return;
} }
...@@ -676,20 +733,29 @@ class Socket implements java.io.Closeable { ...@@ -676,20 +733,29 @@ class Socket implements java.io.Closeable {
* set the flags after an accept() call. * set the flags after an accept() call.
*/ */
final void postAccept() { final void postAccept() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
connected = true; connected = true;
created = true; created = true;
bound = true; bound = true;
} }
void setCreated() { void setCreated() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
created = true; created = true;
} }
void setBound() { void setBound() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
bound = true; bound = true;
} }
void setConnected() { void setConnected() {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
connected = true; connected = true;
} }
...@@ -704,6 +770,9 @@ class Socket implements java.io.Closeable { ...@@ -704,6 +770,9 @@ class Socket implements java.io.Closeable {
* or {@code null} if the socket is not connected. * or {@code null} if the socket is not connected.
*/ */
public InetAddress getInetAddress() { public InetAddress getInetAddress() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getInetAddress();
if (!isConnected()) if (!isConnected())
return null; return null;
try { try {
...@@ -729,6 +798,9 @@ class Socket implements java.io.Closeable { ...@@ -729,6 +798,9 @@ class Socket implements java.io.Closeable {
* @see SecurityManager#checkConnect * @see SecurityManager#checkConnect
*/ */
public InetAddress getLocalAddress() { public InetAddress getLocalAddress() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getLocalAddress();
// This is for backward compatibility // This is for backward compatibility
if (!isBound()) if (!isBound())
return InetAddress.anyLocalAddress(); return InetAddress.anyLocalAddress();
...@@ -760,6 +832,9 @@ class Socket implements java.io.Closeable { ...@@ -760,6 +832,9 @@ class Socket implements java.io.Closeable {
* 0 if the socket is not connected yet. * 0 if the socket is not connected yet.
*/ */
public int getPort() { public int getPort() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getPort();
if (!isConnected()) if (!isConnected())
return 0; return 0;
try { try {
...@@ -781,6 +856,9 @@ class Socket implements java.io.Closeable { ...@@ -781,6 +856,9 @@ class Socket implements java.io.Closeable {
* if the socket is not bound yet. * if the socket is not bound yet.
*/ */
public int getLocalPort() { public int getLocalPort() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getLocalPort();
if (!isBound()) if (!isBound())
return -1; return -1;
try { try {
...@@ -868,6 +946,9 @@ class Socket implements java.io.Closeable { ...@@ -868,6 +946,9 @@ class Socket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public SocketChannel getChannel() { public SocketChannel getChannel() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getChannel();
return null; return null;
} }
...@@ -917,6 +998,9 @@ class Socket implements java.io.Closeable { ...@@ -917,6 +998,9 @@ class Socket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public InputStream getInputStream() throws IOException { public InputStream getInputStream() throws IOException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getInputStream();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!isConnected()) if (!isConnected())
...@@ -957,6 +1041,9 @@ class Socket implements java.io.Closeable { ...@@ -957,6 +1041,9 @@ class Socket implements java.io.Closeable {
* @spec JSR-51 * @spec JSR-51
*/ */
public OutputStream getOutputStream() throws IOException { public OutputStream getOutputStream() throws IOException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getOutputStream();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!isConnected()) if (!isConnected())
...@@ -993,6 +1080,10 @@ class Socket implements java.io.Closeable { ...@@ -993,6 +1080,10 @@ class Socket implements java.io.Closeable {
* @see #getTcpNoDelay() * @see #getTcpNoDelay()
*/ */
public void setTcpNoDelay(boolean on) throws SocketException { public void setTcpNoDelay(boolean on) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setTcpNoDelay(on);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on)); getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
...@@ -1009,6 +1100,9 @@ class Socket implements java.io.Closeable { ...@@ -1009,6 +1100,9 @@ class Socket implements java.io.Closeable {
* @see #setTcpNoDelay(boolean) * @see #setTcpNoDelay(boolean)
*/ */
public boolean getTcpNoDelay() throws SocketException { public boolean getTcpNoDelay() throws SocketException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getTcpNoDelay();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue(); return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue();
...@@ -1030,6 +1124,10 @@ class Socket implements java.io.Closeable { ...@@ -1030,6 +1124,10 @@ class Socket implements java.io.Closeable {
* @see #getSoLinger() * @see #getSoLinger()
*/ */
public void setSoLinger(boolean on, int linger) throws SocketException { public void setSoLinger(boolean on, int linger) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setSoLinger(on, linger);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!on) { if (!on) {
...@@ -1058,6 +1156,9 @@ class Socket implements java.io.Closeable { ...@@ -1058,6 +1156,9 @@ class Socket implements java.io.Closeable {
* @see #setSoLinger(boolean, int) * @see #setSoLinger(boolean, int)
*/ */
public int getSoLinger() throws SocketException { public int getSoLinger() throws SocketException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getSoLinger();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
Object o = getImpl().getOption(SocketOptions.SO_LINGER); Object o = getImpl().getOption(SocketOptions.SO_LINGER);
...@@ -1079,6 +1180,10 @@ class Socket implements java.io.Closeable { ...@@ -1079,6 +1180,10 @@ class Socket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public void sendUrgentData (int data) throws IOException { public void sendUrgentData (int data) throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.sendUrgentData(data);
return;
}
if (!getImpl().supportsUrgentData ()) { if (!getImpl().supportsUrgentData ()) {
throw new SocketException ("Urgent data not supported"); throw new SocketException ("Urgent data not supported");
} }
...@@ -1111,6 +1216,10 @@ class Socket implements java.io.Closeable { ...@@ -1111,6 +1216,10 @@ class Socket implements java.io.Closeable {
* @see #getOOBInline() * @see #getOOBInline()
*/ */
public void setOOBInline(boolean on) throws SocketException { public void setOOBInline(boolean on) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setOOBInline(on);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on)); getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
...@@ -1128,6 +1237,9 @@ class Socket implements java.io.Closeable { ...@@ -1128,6 +1237,9 @@ class Socket implements java.io.Closeable {
* @see #setOOBInline(boolean) * @see #setOOBInline(boolean)
*/ */
public boolean getOOBInline() throws SocketException { public boolean getOOBInline() throws SocketException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getOOBInline();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue(); return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue();
...@@ -1153,6 +1265,10 @@ class Socket implements java.io.Closeable { ...@@ -1153,6 +1265,10 @@ class Socket implements java.io.Closeable {
public synchronized void setSoTimeout(int timeout) throws SocketException { public synchronized void setSoTimeout(int timeout) throws SocketException {
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setSoTimeout(timeout);
return;
}
if (timeout < 0) if (timeout < 0)
throw new IllegalArgumentException("timeout can't be negative"); throw new IllegalArgumentException("timeout can't be negative");
...@@ -1173,6 +1289,8 @@ class Socket implements java.io.Closeable { ...@@ -1173,6 +1289,8 @@ class Socket implements java.io.Closeable {
public synchronized int getSoTimeout() throws SocketException { public synchronized int getSoTimeout() throws SocketException {
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (WispEngine.transparentWispSwitch())
return asyncImpl.getSoTimeout();
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
/* extra type safety */ /* extra type safety */
if (o instanceof Integer) { if (o instanceof Integer) {
...@@ -1207,6 +1325,10 @@ class Socket implements java.io.Closeable { ...@@ -1207,6 +1325,10 @@ class Socket implements java.io.Closeable {
*/ */
public synchronized void setSendBufferSize(int size) public synchronized void setSendBufferSize(int size)
throws SocketException{ throws SocketException{
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setSendBufferSize(size);
return;
}
if (!(size > 0)) { if (!(size > 0)) {
throw new IllegalArgumentException("negative send size"); throw new IllegalArgumentException("negative send size");
} }
...@@ -1229,6 +1351,9 @@ class Socket implements java.io.Closeable { ...@@ -1229,6 +1351,9 @@ class Socket implements java.io.Closeable {
* @since 1.2 * @since 1.2
*/ */
public synchronized int getSendBufferSize() throws SocketException { public synchronized int getSendBufferSize() throws SocketException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getSendBufferSize();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
int result = 0; int result = 0;
...@@ -1281,6 +1406,10 @@ class Socket implements java.io.Closeable { ...@@ -1281,6 +1406,10 @@ class Socket implements java.io.Closeable {
*/ */
public synchronized void setReceiveBufferSize(int size) public synchronized void setReceiveBufferSize(int size)
throws SocketException{ throws SocketException{
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setReceiveBufferSize(size);
return;
}
if (size <= 0) { if (size <= 0) {
throw new IllegalArgumentException("invalid receive size"); throw new IllegalArgumentException("invalid receive size");
} }
...@@ -1303,6 +1432,9 @@ class Socket implements java.io.Closeable { ...@@ -1303,6 +1432,9 @@ class Socket implements java.io.Closeable {
*/ */
public synchronized int getReceiveBufferSize() public synchronized int getReceiveBufferSize()
throws SocketException{ throws SocketException{
if (WispEngine.transparentWispSwitch())
return asyncImpl.getReceiveBufferSize();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
int result = 0; int result = 0;
...@@ -1323,6 +1455,10 @@ class Socket implements java.io.Closeable { ...@@ -1323,6 +1455,10 @@ class Socket implements java.io.Closeable {
* @see #getKeepAlive() * @see #getKeepAlive()
*/ */
public void setKeepAlive(boolean on) throws SocketException { public void setKeepAlive(boolean on) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setKeepAlive(on);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on)); getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
...@@ -1339,6 +1475,9 @@ class Socket implements java.io.Closeable { ...@@ -1339,6 +1475,9 @@ class Socket implements java.io.Closeable {
* @see #setKeepAlive(boolean) * @see #setKeepAlive(boolean)
*/ */
public boolean getKeepAlive() throws SocketException { public boolean getKeepAlive() throws SocketException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getKeepAlive();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue(); return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue();
...@@ -1391,6 +1530,10 @@ class Socket implements java.io.Closeable { ...@@ -1391,6 +1530,10 @@ class Socket implements java.io.Closeable {
* @see SocketOptions#IP_TOS * @see SocketOptions#IP_TOS
*/ */
public void setTrafficClass(int tc) throws SocketException { public void setTrafficClass(int tc) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setTrafficClass(tc);
return;
}
if (tc < 0 || tc > 255) if (tc < 0 || tc > 255)
throw new IllegalArgumentException("tc is not in range 0 -- 255"); throw new IllegalArgumentException("tc is not in range 0 -- 255");
...@@ -1423,6 +1566,9 @@ class Socket implements java.io.Closeable { ...@@ -1423,6 +1566,9 @@ class Socket implements java.io.Closeable {
* @see SocketOptions#IP_TOS * @see SocketOptions#IP_TOS
*/ */
public int getTrafficClass() throws SocketException { public int getTrafficClass() throws SocketException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getTrafficClass();
return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue(); return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();
} }
...@@ -1462,6 +1608,10 @@ class Socket implements java.io.Closeable { ...@@ -1462,6 +1608,10 @@ class Socket implements java.io.Closeable {
* @see #isBound() * @see #isBound()
*/ */
public void setReuseAddress(boolean on) throws SocketException { public void setReuseAddress(boolean on) throws SocketException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.setReuseAddress(on);
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
...@@ -1478,6 +1628,9 @@ class Socket implements java.io.Closeable { ...@@ -1478,6 +1628,9 @@ class Socket implements java.io.Closeable {
* @see #setReuseAddress(boolean) * @see #setReuseAddress(boolean)
*/ */
public boolean getReuseAddress() throws SocketException { public boolean getReuseAddress() throws SocketException {
if (WispEngine.transparentWispSwitch())
return asyncImpl.getReuseAddress();
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue(); return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
...@@ -1506,6 +1659,10 @@ class Socket implements java.io.Closeable { ...@@ -1506,6 +1659,10 @@ class Socket implements java.io.Closeable {
* @see #isClosed * @see #isClosed
*/ */
public synchronized void close() throws IOException { public synchronized void close() throws IOException {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.close();
return;
}
synchronized(closeLock) { synchronized(closeLock) {
if (isClosed()) if (isClosed())
return; return;
...@@ -1535,6 +1692,10 @@ class Socket implements java.io.Closeable { ...@@ -1535,6 +1692,10 @@ class Socket implements java.io.Closeable {
*/ */
public void shutdownInput() throws IOException public void shutdownInput() throws IOException
{ {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.shutdownInput();
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!isConnected()) if (!isConnected())
...@@ -1565,6 +1726,10 @@ class Socket implements java.io.Closeable { ...@@ -1565,6 +1726,10 @@ class Socket implements java.io.Closeable {
*/ */
public void shutdownOutput() throws IOException public void shutdownOutput() throws IOException
{ {
if (WispEngine.transparentWispSwitch()) {
asyncImpl.shutdownOutput();
return;
}
if (isClosed()) if (isClosed())
throw new SocketException("Socket is closed"); throw new SocketException("Socket is closed");
if (!isConnected()) if (!isConnected())
...@@ -1581,6 +1746,9 @@ class Socket implements java.io.Closeable { ...@@ -1581,6 +1746,9 @@ class Socket implements java.io.Closeable {
* @return a string representation of this socket. * @return a string representation of this socket.
*/ */
public String toString() { public String toString() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.toString();
try { try {
if (isConnected()) if (isConnected())
return "Socket[addr=" + getImpl().getInetAddress() + return "Socket[addr=" + getImpl().getInetAddress() +
...@@ -1603,6 +1771,9 @@ class Socket implements java.io.Closeable { ...@@ -1603,6 +1771,9 @@ class Socket implements java.io.Closeable {
* @since 1.4 * @since 1.4
*/ */
public boolean isConnected() { public boolean isConnected() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.isConnected();
// Before 1.3 Sockets were always connected during creation // Before 1.3 Sockets were always connected during creation
return connected || oldImpl; return connected || oldImpl;
} }
...@@ -1620,6 +1791,9 @@ class Socket implements java.io.Closeable { ...@@ -1620,6 +1791,9 @@ class Socket implements java.io.Closeable {
* @see #bind * @see #bind
*/ */
public boolean isBound() { public boolean isBound() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.isBound();
// Before 1.3 Sockets were always bound during creation // Before 1.3 Sockets were always bound during creation
return bound || oldImpl; return bound || oldImpl;
} }
...@@ -1632,6 +1806,9 @@ class Socket implements java.io.Closeable { ...@@ -1632,6 +1806,9 @@ class Socket implements java.io.Closeable {
* @see #close * @see #close
*/ */
public boolean isClosed() { public boolean isClosed() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.isClosed();
synchronized(closeLock) { synchronized(closeLock) {
return closed; return closed;
} }
...@@ -1645,6 +1822,9 @@ class Socket implements java.io.Closeable { ...@@ -1645,6 +1822,9 @@ class Socket implements java.io.Closeable {
* @see #shutdownInput * @see #shutdownInput
*/ */
public boolean isInputShutdown() { public boolean isInputShutdown() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.isInputShutdown();
return shutIn; return shutIn;
} }
...@@ -1656,6 +1836,9 @@ class Socket implements java.io.Closeable { ...@@ -1656,6 +1836,9 @@ class Socket implements java.io.Closeable {
* @see #shutdownOutput * @see #shutdownOutput
*/ */
public boolean isOutputShutdown() { public boolean isOutputShutdown() {
if (WispEngine.transparentWispSwitch())
return asyncImpl.isOutputShutdown();
return shutOut; return shutOut;
} }
...@@ -1691,6 +1874,9 @@ class Socket implements java.io.Closeable { ...@@ -1691,6 +1874,9 @@ class Socket implements java.io.Closeable {
public static synchronized void setSocketImplFactory(SocketImplFactory fac) public static synchronized void setSocketImplFactory(SocketImplFactory fac)
throws IOException throws IOException
{ {
if (WispEngine.transparentWispSwitch())
throw new UnsupportedOperationException();
if (factory != null) { if (factory != null) {
throw new SocketException("factory already defined"); throw new SocketException("factory already defined");
} }
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
package java.nio.channels; package java.nio.channels;
import com.alibaba.wisp.engine.WispEngine;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.spi.SelectorProvider; import java.nio.channels.spi.SelectorProvider;
......
...@@ -154,6 +154,10 @@ public class LinkedBlockingDeque<E> ...@@ -154,6 +154,10 @@ public class LinkedBlockingDeque<E>
/** Maximum number of items in the deque */ /** Maximum number of items in the deque */
private final int capacity; private final int capacity;
int getCapacity() {
return capacity;
}
/** Main lock guarding all access */ /** Main lock guarding all access */
final ReentrantLock lock = new ReentrantLock(); final ReentrantLock lock = new ReentrantLock();
......
...@@ -136,6 +136,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E> ...@@ -136,6 +136,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/** The capacity bound, or Integer.MAX_VALUE if none */ /** The capacity bound, or Integer.MAX_VALUE if none */
private final int capacity; private final int capacity;
int getCapacity() {
return capacity;
}
/** Current number of elements */ /** Current number of elements */
private final AtomicInteger count = new AtomicInteger(); private final AtomicInteger count = new AtomicInteger();
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
*/ */
package java.util.concurrent; 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.LockSupport;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.*; import java.util.*;
...@@ -85,6 +89,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -85,6 +89,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable { implements BlockingQueue<E>, java.io.Serializable {
private static final long serialVersionUID = -3223113410248163686L; private static final long serialVersionUID = -3223113410248163686L;
private static WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
/* /*
* This class implements extensions of the dual stack and dual * This class implements extensions of the dual stack and dual
* queue algorithms described in "Nonblocking Concurrent Objects * queue algorithms described in "Nonblocking Concurrent Objects
...@@ -456,7 +462,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -456,7 +462,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
s.waiter = w; // establish waiter so can park next iter s.waiter = w; // establish waiter so can park next iter
else if (!timed) else if (!timed)
LockSupport.park(this); LockSupport.park(this);
else if (nanos > spinForTimeoutThreshold) else if (nanos > spinForTimeoutThreshold ||
WispEngine.transparentWispSwitch() && WEA.hasMoreTasks())
LockSupport.parkNanos(this, nanos); LockSupport.parkNanos(this, nanos);
} }
} }
...@@ -466,6 +473,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -466,6 +473,9 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* fulfiller. * fulfiller.
*/ */
boolean shouldSpin(SNode s) { boolean shouldSpin(SNode s) {
if (WispEngine.transparentWispSwitch() && WEA.hasMoreTasks()) {
return false;
}
SNode h = head; SNode h = head;
return (h == s || h == null || isFulfilling(h.mode)); return (h == s || h == null || isFulfilling(h.mode));
} }
...@@ -760,7 +770,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -760,7 +770,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
s.waiter = w; s.waiter = w;
else if (!timed) else if (!timed)
LockSupport.park(this); LockSupport.park(this);
else if (nanos > spinForTimeoutThreshold) else if (nanos > spinForTimeoutThreshold ||
WispEngine.transparentWispSwitch() && WEA.hasMoreTasks())
LockSupport.parkNanos(this, nanos); LockSupport.parkNanos(this, nanos);
} }
} }
......
...@@ -38,7 +38,11 @@ import java.util.concurrent.TimeUnit; ...@@ -38,7 +38,11 @@ import java.util.concurrent.TimeUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.SharedSecrets;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import sun.misc.WispEngineAccess;
/** /**
* Provides a framework for implementing blocking locks and related * Provides a framework for implementing blocking locks and related
...@@ -292,6 +296,8 @@ public abstract class AbstractQueuedSynchronizer ...@@ -292,6 +296,8 @@ public abstract class AbstractQueuedSynchronizer
private static final long serialVersionUID = 7373984972572414691L; private static final long serialVersionUID = 7373984972572414691L;
private static WispEngineAccess WA = SharedSecrets.getWispEngineAccess();
/** /**
* Creates a new {@code AbstractQueuedSynchronizer} instance * Creates a new {@code AbstractQueuedSynchronizer} instance
* with initial synchronization state of zero. * with initial synchronization state of zero.
...@@ -930,7 +936,8 @@ public abstract class AbstractQueuedSynchronizer ...@@ -930,7 +936,8 @@ public abstract class AbstractQueuedSynchronizer
if (nanosTimeout <= 0L) if (nanosTimeout <= 0L)
return false; return false;
if (shouldParkAfterFailedAcquire(p, node) && if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold) (nanosTimeout > spinForTimeoutThreshold ||
WispEngine.transparentWispSwitch() && WA.hasMoreTasks()))
LockSupport.parkNanos(this, nanosTimeout); LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted()) if (Thread.interrupted())
throw new InterruptedException(); throw new InterruptedException();
...@@ -1033,7 +1040,8 @@ public abstract class AbstractQueuedSynchronizer ...@@ -1033,7 +1040,8 @@ public abstract class AbstractQueuedSynchronizer
if (nanosTimeout <= 0L) if (nanosTimeout <= 0L)
return false; return false;
if (shouldParkAfterFailedAcquire(p, node) && if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold) (nanosTimeout > spinForTimeoutThreshold ||
WispEngine.transparentWispSwitch() && WA.hasMoreTasks()))
LockSupport.parkNanos(this, nanosTimeout); LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted()) if (Thread.interrupted())
throw new InterruptedException(); throw new InterruptedException();
...@@ -2074,7 +2082,8 @@ public abstract class AbstractQueuedSynchronizer ...@@ -2074,7 +2082,8 @@ public abstract class AbstractQueuedSynchronizer
transferAfterCancelledWait(node); transferAfterCancelledWait(node);
break; break;
} }
if (nanosTimeout >= spinForTimeoutThreshold) if (nanosTimeout >= spinForTimeoutThreshold ||
WispEngine.transparentWispSwitch() && WA.hasMoreTasks())
LockSupport.parkNanos(this, nanosTimeout); LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break; break;
...@@ -2159,7 +2168,8 @@ public abstract class AbstractQueuedSynchronizer ...@@ -2159,7 +2168,8 @@ public abstract class AbstractQueuedSynchronizer
timedout = transferAfterCancelledWait(node); timedout = transferAfterCancelledWait(node);
break; break;
} }
if (nanosTimeout >= spinForTimeoutThreshold) if (nanosTimeout >= spinForTimeoutThreshold ||
WispEngine.transparentWispSwitch() && WA.hasMoreTasks())
LockSupport.parkNanos(this, nanosTimeout); LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break; break;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
*/ */
package java.util.concurrent.locks; package java.util.concurrent.locks;
import sun.misc.Unsafe; import sun.misc.Unsafe;
/** /**
......
...@@ -41,8 +41,10 @@ import java.security.PrivilegedExceptionAction; ...@@ -41,8 +41,10 @@ import java.security.PrivilegedExceptionAction;
import com.alibaba.management.TenantContainerMXBean; import com.alibaba.management.TenantContainerMXBean;
import com.alibaba.management.ElasticHeapMXBean; import com.alibaba.management.ElasticHeapMXBean;
import com.alibaba.management.WispCounterMXBean;
import com.alibaba.tenant.TenantContainerMXBeanImpl; import com.alibaba.tenant.TenantContainerMXBeanImpl;
import com.alibaba.jvm.gc.ElasticHeapMXBeanImpl; import com.alibaba.jvm.gc.ElasticHeapMXBeanImpl;
import com.alibaba.wisp.engine.WispCounterMXBeanImpl;
import sun.util.logging.LoggingSupport; import sun.util.logging.LoggingSupport;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -71,6 +73,7 @@ public class ManagementFactoryHelper { ...@@ -71,6 +73,7 @@ public class ManagementFactoryHelper {
private static OperatingSystemImpl osMBean = null; private static OperatingSystemImpl osMBean = null;
private static TenantContainerMXBeanImpl tenantContainerMBean = null; private static TenantContainerMXBeanImpl tenantContainerMBean = null;
private static ElasticHeapMXBeanImpl elasticHeapMXBean = null; private static ElasticHeapMXBeanImpl elasticHeapMXBean = null;
private static WispCounterMXBeanImpl wispCounterMBean = null;
public static synchronized ClassLoadingMXBean getClassLoadingMXBean() { public static synchronized ClassLoadingMXBean getClassLoadingMXBean() {
if (classMBean == null) { if (classMBean == null) {
...@@ -128,6 +131,13 @@ public class ManagementFactoryHelper { ...@@ -128,6 +131,13 @@ public class ManagementFactoryHelper {
return elasticHeapMXBean; return elasticHeapMXBean;
} }
public static synchronized WispCounterMXBean getWispCounterMXBean() {
if (wispCounterMBean == null) {
wispCounterMBean = new WispCounterMXBeanImpl();
}
return wispCounterMBean;
}
public static List<MemoryPoolMXBean> getMemoryPoolMXBeans() { public static List<MemoryPoolMXBean> getMemoryPoolMXBeans() {
MemoryPoolMXBean[] pools = MemoryImpl.getMemoryPools(); MemoryPoolMXBean[] pools = MemoryImpl.getMemoryPools();
List<MemoryPoolMXBean> list = new ArrayList<>(pools.length); List<MemoryPoolMXBean> list = new ArrayList<>(pools.length);
......
...@@ -31,6 +31,8 @@ import java.security.AccessControlContext; ...@@ -31,6 +31,8 @@ import java.security.AccessControlContext;
import java.util.Map; import java.util.Map;
import com.alibaba.rcm.internal.AbstractResourceContainer; 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.ConstantPool;
import sun.reflect.annotation.AnnotationType; import sun.reflect.annotation.AnnotationType;
import sun.nio.ch.Interruptible; import sun.nio.ch.Interruptible;
...@@ -150,4 +152,23 @@ public interface JavaLangAccess { ...@@ -150,4 +152,23 @@ public interface JavaLangAccess {
* Get the reference to the thread's inherited {@code ResourceContainer} * Get the reference to the thread's inherited {@code ResourceContainer}
*/ */
AbstractResourceContainer getInheritedResourceContainer(Thread thread); 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();
} }
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
package sun.misc; package sun.misc;
import javax.crypto.SealedObject; import javax.crypto.SealedObject;
import sun.nio.ch.IOEventAccess;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.io.Console; import java.io.Console;
import java.io.FileDescriptor; import java.io.FileDescriptor;
...@@ -64,6 +67,8 @@ public class SharedSecrets { ...@@ -64,6 +67,8 @@ public class SharedSecrets {
private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
private static TenantAccess tenantAccess; private static TenantAccess tenantAccess;
private static JavaSecuritySignatureAccess javaSecuritySignatureAccess; private static JavaSecuritySignatureAccess javaSecuritySignatureAccess;
private static WispEngineAccess wispEngineAccess;
private static IOEventAccess ioEventAccess;
public static JavaUtilJarAccess javaUtilJarAccess() { public static JavaUtilJarAccess javaUtilJarAccess() {
if (javaUtilJarAccess == null) { if (javaUtilJarAccess == null) {
...@@ -257,4 +262,27 @@ public class SharedSecrets { ...@@ -257,4 +262,27 @@ public class SharedSecrets {
public static TenantAccess getTenantAccess() { public static TenantAccess getTenantAccess() {
return tenantAccess; 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;
}
} }
...@@ -28,6 +28,7 @@ package sun.misc; ...@@ -28,6 +28,7 @@ package sun.misc;
import java.security.*; import java.security.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import com.alibaba.wisp.engine.WispEngine;
import sun.reflect.CallerSensitive; import sun.reflect.CallerSensitive;
import sun.reflect.Reflection; import sun.reflect.Reflection;
...@@ -53,6 +54,18 @@ public final class Unsafe { ...@@ -53,6 +54,18 @@ public final class Unsafe {
private static final Unsafe theUnsafe = new 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 * Provides the caller with the capability of performing unsafe
* operations. * operations.
...@@ -971,7 +984,7 @@ public final class Unsafe { ...@@ -971,7 +984,7 @@ public final class Unsafe {
public native void putOrderedLong(Object o, long offset, long x); public native void putOrderedLong(Object o, long offset, long x);
/** /**
* Unblock the given thread blocked on <tt>park</tt>, or, if it is * Unblock the given thread(or coroutine) blocked on <tt>park</tt>, or, if it is
* not blocked, cause the subsequent call to <tt>park</tt> not to * not blocked, cause the subsequent call to <tt>park</tt> not to
* block. Note: this operation is "unsafe" solely because the * block. Note: this operation is "unsafe" solely because the
* caller must somehow ensure that the thread has not been * caller must somehow ensure that the thread has not been
...@@ -982,10 +995,25 @@ public final class Unsafe { ...@@ -982,10 +995,25 @@ public final class Unsafe {
* @param thread the thread to unpark. * @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
* <tt>unpark</tt> occurs, or a balancing <tt>unpark</tt> has * <tt>unpark</tt> occurs, or a balancing <tt>unpark</tt> has
* already occurred, or the thread is interrupted, or, if not * already occurred, or the thread is interrupted, or, if not
* absolute and time is not zero, the given time nanoseconds have * absolute and time is not zero, the given time nanoseconds have
...@@ -995,7 +1023,25 @@ public final class Unsafe { ...@@ -995,7 +1023,25 @@ public final class Unsafe {
* because <tt>unpark</tt> is, so it would be strange to place it * because <tt>unpark</tt> is, so it would be strange to place it
* elsewhere. * 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 * Gets the load average in the system run queue assigned
......
package sun.misc;
public interface UnsafeAccess {
void unpark0(Object thread);
void park0(boolean isAbsolute, long time);
}
...@@ -410,6 +410,7 @@ public class VM { ...@@ -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_INDEFINITELY = 0x0010;
private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020;
/* /*
* Returns first non-privileged class loader on the stack (excluding * Returns first non-privileged class loader on the stack (excluding
* reflection generated frames) or the extension class loader if only * reflection generated frames) or the extension class loader if only
......
/*
* 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<Object> status, final Object INTERRUPTED) throws IOException;
void interruptEpoll(AtomicReference<Object> 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);
}
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
...@@ -46,6 +46,7 @@ public class SelectionKeyImpl ...@@ -46,6 +46,7 @@ public class SelectionKeyImpl
private volatile int interestOps; private volatile int interestOps;
private int readyOps; private int readyOps;
public int wispOps; // pass argument, access by WispSelector
SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) { SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) {
channel = ch; channel = ch;
...@@ -102,6 +103,7 @@ public class SelectionKeyImpl ...@@ -102,6 +103,7 @@ public class SelectionKeyImpl
public SelectionKey nioInterestOps(int ops) { public SelectionKey nioInterestOps(int ops) {
if ((ops & ~channel().validOps()) != 0) if ((ops & ~channel().validOps()) != 0)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
wispOps = ops; // read by WispSelector.putEventOps
channel.translateAndSetInterestOps(ops, this); channel.translateAndSetInterestOps(ops, this);
interestOps = ops; interestOps = ops;
return this; return this;
......
...@@ -141,7 +141,13 @@ public abstract class SelectorImpl ...@@ -141,7 +141,13 @@ public abstract class SelectorImpl
// Precondition: Synchronized on this, keys, and selectedKeys // Precondition: Synchronized on this, keys, and selectedKeys
Set<SelectionKey> cks = cancelledKeys(); Set<SelectionKey> cks = cancelledKeys();
synchronized (cks) { synchronized (cks) {
if (!cks.isEmpty()) { if (cks.isEmpty()) {
return;
}
cks = new HashSet<>(cks);
cancelledKeys().clear();
}
try { // now cks is a thread local copy
Iterator<SelectionKey> i = cks.iterator(); Iterator<SelectionKey> i = cks.iterator();
while (i.hasNext()) { while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
...@@ -153,6 +159,11 @@ public abstract class SelectorImpl ...@@ -153,6 +159,11 @@ public abstract class SelectorImpl
i.remove(); i.remove();
} }
} }
} finally {
if (!cks.isEmpty()) {
synchronized (cancelledKeys()) {
cancelledKeys().addAll(cks);
}
} }
} }
} }
......
...@@ -31,6 +31,10 @@ import java.net.*; ...@@ -31,6 +31,10 @@ import java.net.*;
import java.nio.channels.*; import java.nio.channels.*;
import java.nio.channels.spi.*; import java.nio.channels.spi.*;
import java.util.*; import java.util.*;
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.SharedSecrets;
import sun.misc.WispEngineAccess;
import sun.net.NetHooks; import sun.net.NetHooks;
...@@ -42,6 +46,7 @@ class ServerSocketChannelImpl ...@@ -42,6 +46,7 @@ class ServerSocketChannelImpl
extends ServerSocketChannel extends ServerSocketChannel
implements SelChImpl implements SelChImpl
{ {
private static final WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
// Used to make native close and configure calls // Used to make native close and configure calls
private static NativeDispatcher nd; private static NativeDispatcher nd;
...@@ -238,18 +243,31 @@ class ServerSocketChannelImpl ...@@ -238,18 +243,31 @@ class ServerSocketChannelImpl
FileDescriptor newfd = new FileDescriptor(); FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1]; InetSocketAddress[] isaa = new InetSocketAddress[1];
final boolean wispAndBlocking = WispEngine.transparentWispSwitch() && isBlocking() &&
WEA.usingWispEpoll();
try { try {
begin(); begin();
if (!isOpen()) if (!isOpen())
return null; return null;
thread = NativeThread.current(); thread = NativeThread.current();
if (wispAndBlocking) {
IOUtil.configureBlocking(fd, false);
}
for (;;) { for (;;) {
n = accept(this.fd, newfd, isaa); n = accept(this.fd, newfd, isaa);
if ((n == IOStatus.INTERRUPTED) && isOpen()) if ((n == IOStatus.INTERRUPTED) && isOpen())
continue; continue;
if (wispAndBlocking && n < 0) {
WEA.registerEvent(this, SelectionKey.OP_ACCEPT);
WEA.park(-1);
continue;
}
break; break;
} }
} finally { } finally {
if (wispAndBlocking) {
IOUtil.configureBlocking(fd, true);
}
thread = 0; thread = 0;
end(n > 0); end(n > 0);
assert IOStatus.check(n); assert IOStatus.check(n);
......
...@@ -2032,6 +2032,14 @@ skip_method(CrwClassImage *ci, const char *name, ...@@ -2032,6 +2032,14 @@ skip_method(CrwClassImage *ci, const char *name,
unsigned access_flags, ByteOffset code_len, unsigned access_flags, ByteOffset code_len,
int system_class, jboolean *pskip_call_return_sites) 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; *pskip_call_return_sites = JNI_FALSE;
if ( system_class ) { if ( system_class ) {
if ( code_len == 1 && is_init_method(name) ) { if ( code_len == 1 && is_init_method(name) ) {
......
...@@ -268,6 +268,9 @@ JVM_Interrupt(JNIEnv *env, jobject thread); ...@@ -268,6 +268,9 @@ JVM_Interrupt(JNIEnv *env, jobject thread);
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
JVM_IsInterrupted(JNIEnv *env, jobject thread, jboolean clearInterrupted); JVM_IsInterrupted(JNIEnv *env, jobject thread, jboolean clearInterrupted);
JNIEXPORT jboolean JNICALL
JVM_CheckAndClearNativeInterruptForWisp(JNIEnv* env, jobject task, jobject jthread);
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
JVM_HoldsLock(JNIEnv *env, jclass threadClass, jobject obj); JVM_HoldsLock(JNIEnv *env, jclass threadClass, jobject obj);
...@@ -280,6 +283,9 @@ JVM_GetAllThreads(JNIEnv *env, jclass dummy); ...@@ -280,6 +283,9 @@ JVM_GetAllThreads(JNIEnv *env, jclass dummy);
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
JVM_SetNativeThreadName(JNIEnv *env, jobject jthread, jstring name); JVM_SetNativeThreadName(JNIEnv *env, jobject jthread, jstring name);
JNIEXPORT jboolean JNICALL
JVM_IsInSameNative(JNIEnv *env, jobject thread);
/* getStackTrace() and getAllStackTraces() method */ /* getStackTrace() and getAllStackTraces() method */
JNIEXPORT jobjectArray JNICALL JNIEXPORT jobjectArray JNICALL
JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobjectArray threads); JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobjectArray threads);
...@@ -342,6 +348,15 @@ JVM_CheckJWarmUpCompilationIsComplete(JNIEnv *env, jclass clz); ...@@ -342,6 +348,15 @@ JVM_CheckJWarmUpCompilationIsComplete(JNIEnv *env, jclass clz);
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
JVM_NotifyJVMDeoptWarmUpMethods(JNIEnv* env, jclass clz); 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 * com.alibaba.management.ElasticHeapMXBean
*/ */
......
/*
* 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));
}
...@@ -43,13 +43,13 @@ ...@@ -43,13 +43,13 @@
static JNINativeMethod methods[] = { static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread}, {"start0", "()V", (void *)&JVM_StartThread},
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread}, {"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive", "()Z", (void *)&JVM_IsThreadAlive}, {"isAlive0", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread}, {"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread}, {"resume0", "()V", (void *)&JVM_ResumeThread},
{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority}, {"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
{"yield", "()V", (void *)&JVM_Yield}, {"yield0", "()V", (void *)&JVM_Yield},
{"sleep", "(J)V", (void *)&JVM_Sleep}, {"sleep0", "(J)V", (void *)&JVM_Sleep},
{"currentThread", "()" THD, (void *)&JVM_CurrentThread}, {"currentThread0", "()" THD, (void *)&JVM_CurrentThread},
{"countStackFrames", "()I", (void *)&JVM_CountStackFrames}, {"countStackFrames", "()I", (void *)&JVM_CountStackFrames},
{"interrupt0", "()V", (void *)&JVM_Interrupt}, {"interrupt0", "()V", (void *)&JVM_Interrupt},
{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted}, {"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
...@@ -57,6 +57,7 @@ static JNINativeMethod methods[] = { ...@@ -57,6 +57,7 @@ static JNINativeMethod methods[] = {
{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads}, {"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads}, {"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName}, {"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
{"isInSameNative", "()Z", (void *)&JVM_IsInSameNative},
}; };
#undef THD #undef THD
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
package sun.nio.ch; package sun.nio.ch;
import java.io.IOException; import java.io.IOException;
import sun.misc.SharedSecrets;
import sun.misc.Unsafe; import sun.misc.Unsafe;
/** /**
...@@ -62,6 +64,8 @@ class EPoll { ...@@ -62,6 +64,8 @@ class EPoll {
// flags // flags
static final int EPOLLONESHOT = (1 << 30); static final int EPOLLONESHOT = (1 << 30);
static final int ENOENT;
/** /**
* Allocates a poll array to handle up to {@code count} events. * Allocates a poll array to handle up to {@code count} events.
*/ */
...@@ -109,10 +113,17 @@ class EPoll { ...@@ -109,10 +113,17 @@ class EPoll {
static native int epollCtl(int epfd, int opcode, int fd, int events); 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; throws IOException;
static native int errnoENOENT();
static { static {
IOUtil.load(); IOUtil.load();
ENOENT = errnoENOENT();
} }
} }
...@@ -30,6 +30,13 @@ import java.security.AccessController; ...@@ -30,6 +30,13 @@ import java.security.AccessController;
import java.util.BitSet; import java.util.BitSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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; import sun.security.action.GetIntegerAction;
/** /**
...@@ -57,6 +64,8 @@ import sun.security.action.GetIntegerAction; ...@@ -57,6 +64,8 @@ import sun.security.action.GetIntegerAction;
*/ */
class EPollArrayWrapper { class EPollArrayWrapper {
private static final WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
// EPOLL_EVENTS // EPOLL_EVENTS
private static final int EPOLLIN = 0x001; private static final int EPOLLIN = 0x001;
...@@ -266,7 +275,9 @@ class EPollArrayWrapper { ...@@ -266,7 +275,9 @@ class EPollArrayWrapper {
int poll(long timeout) throws IOException { int poll(long timeout) throws IOException {
updateRegistrations(); updateRegistrations();
updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd); updated = WispEngine.transparentWispSwitch() ?
handleEPollWithWisp(timeout) :
epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
for (int i=0; i<updated; i++) { for (int i=0; i<updated; i++) {
if (getDescriptor(i) == incomingInterruptFD) { if (getDescriptor(i) == incomingInterruptFD) {
interruptedIndex = i; interruptedIndex = i;
...@@ -277,6 +288,20 @@ class EPollArrayWrapper { ...@@ -277,6 +288,20 @@ class EPollArrayWrapper {
return updated; return updated;
} }
private final static Object INTERRUPTED = new Object();
private AtomicReference<Object> 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. * Update the pending registrations.
*/ */
...@@ -314,8 +339,12 @@ class EPollArrayWrapper { ...@@ -314,8 +339,12 @@ class EPollArrayWrapper {
private boolean interrupted = false; private boolean interrupted = false;
public void interrupt() { public void interrupt() {
if (WispEngine.transparentWispSwitch() && WEA.useDirectSelectorWakeup()) {
WEA.interruptEpoll(status, INTERRUPTED, outgoingInterruptFD);
} else {
interrupt(outgoingInterruptFD); interrupt(outgoingInterruptFD);
} }
}
public int interruptedIndex() { public int interruptedIndex() {
return interruptedIndex; return interruptedIndex;
...@@ -327,6 +356,10 @@ class EPollArrayWrapper { ...@@ -327,6 +356,10 @@ class EPollArrayWrapper {
void clearInterrupted() { void clearInterrupted() {
interrupted = false; interrupted = false;
if (WispEngine.transparentWispSwitch() && WEA.useDirectSelectorWakeup()) {
assert status.get() == INTERRUPTED;
status.lazySet(null);
}
} }
static { static {
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
package sun.nio.ch; package sun.nio.ch;
import sun.misc.SharedSecrets;
import java.nio.channels.spi.AsynchronousChannelProvider; import java.nio.channels.spi.AsynchronousChannelProvider;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
...@@ -319,5 +321,91 @@ final class EPollPort ...@@ -319,5 +321,91 @@ final class EPollPort
static { static {
IOUtil.load(); 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);
}
});
} }
} }
...@@ -29,6 +29,8 @@ import java.io.IOException; ...@@ -29,6 +29,8 @@ import java.io.IOException;
import java.nio.channels.*; import java.nio.channels.*;
import java.nio.channels.spi.*; import java.nio.channels.spi.*;
import java.util.*; import java.util.*;
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.*; import sun.misc.*;
/** /**
...@@ -38,6 +40,7 @@ import sun.misc.*; ...@@ -38,6 +40,7 @@ import sun.misc.*;
class EPollSelectorImpl class EPollSelectorImpl
extends SelectorImpl extends SelectorImpl
{ {
private static final WispEngineAccess WEA = SharedSecrets.getWispEngineAccess();
// File descriptors used for interrupt // File descriptors used for interrupt
protected int fd0; protected int fd0;
...@@ -101,7 +104,12 @@ class EPollSelectorImpl ...@@ -101,7 +104,12 @@ class EPollSelectorImpl
pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0); pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0);
synchronized (interruptLock) { synchronized (interruptLock) {
pollWrapper.clearInterrupted(); pollWrapper.clearInterrupted();
if (WispEngine.transparentWispSwitch()
&& WEA.useDirectSelectorWakeup() && WEA.isAllThreadAsWisp()) {
// skip
} else {
IOUtil.drain(fd0); IOUtil.drain(fd0);
}
interruptTriggered = false; interruptTriggered = false;
} }
} }
......
...@@ -84,12 +84,12 @@ Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd, ...@@ -84,12 +84,12 @@ Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd,
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sun_nio_ch_EPoll_epollWait(JNIEnv *env, jclass c, 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); struct epoll_event *events = jlong_to_ptr(address);
int res; int res;
RESTARTABLE(epoll_wait(epfd, events, numfds, -1), res); RESTARTABLE(epoll_wait(epfd, events, numfds, timeout), res);
if (res < 0) { if (res < 0) {
JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed"); JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
} }
...@@ -101,3 +101,8 @@ Java_sun_nio_ch_EPoll_close0(JNIEnv *env, jclass c, jint epfd) { ...@@ -101,3 +101,8 @@ Java_sun_nio_ch_EPoll_close0(JNIEnv *env, jclass c, jint epfd) {
int res; int res;
RESTARTABLE(close(epfd), res); RESTARTABLE(close(epfd), res);
} }
JNIEXPORT jint JNICALL
Java_sun_nio_ch_EPoll_errnoENOENT(JNIEnv *env, jclass this) {
return (jint)ENOENT;
}
/*
* 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 {
}
/*
* 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<Boolean> getRunningStates() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getSwitchCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getWaitTimeTotal() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getRunningTimeTotal() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getCompleteTaskCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getCreateTaskCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getParkCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getUnparkCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getLazyUnparkCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getUnparkInterruptSelectorCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getSelectableIOCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTimeOutCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getEventLoopCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getQueueLength() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getNumberOfRunningTasks() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalEnqueueTime() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getEnqueueCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalExecutionTime() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getExecutionCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalWaitSocketIOTime() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getWaitSocketIOCount() {
throw new UnsupportedOperationException();
}
@Override
public List<Long> getTotalBlockingTime() {
throw new UnsupportedOperationException();
}
@Override
public WispCounter getWispCounter(long id) {
throw new UnsupportedOperationException();
}
@Override
public ObjectName getObjectName() {
throw new UnsupportedOperationException();
}
}
/*
* 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<Object> status, Object INTERRUPTED) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void interruptEpoll(AtomicReference<Object> 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();
}
});
}
}
/*
* 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();
}
}
/*
* 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();
}
}
package sun.nio.ch;
public class IOEvent {
public static Class<?> eventClass() {
return IOEventRegister.class;
}
}
\ No newline at end of file
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
/*
* 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();
}
}
/*
* 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();
}
}
/*
* 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 {
}
/*
* 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();
}
}
/*
* 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);
}
}
}
/*
* 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<String> 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");
}
}
/*
* 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();
}
}
}
/*
* 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<String> futureA = new FutureTask<>(ExecutionTest::nodeA);
FutureTask<String> 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;
};
/**
* <pre>
* 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
* </pre>
*
* 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<String> future1 = new FutureTask<>(() -> slowReq("B1"));
FutureTask<String> 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";
}
}
/*
* 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<Properties>() {
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);
}
}
}
/*
* 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<Integer> q1 = new ArrayBlockingQueue<>(1);
BlockingQueue<Integer> 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<Integer> pingQ;
final BlockingQueue<Integer> pongQ;
final CountDownLatch latch;
public PingPong(BlockingQueue<Integer> pingQ, BlockingQueue<Integer> 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) {
}
}
}
}
/*
* 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");
}
}
/*
* 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<Boolean> 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));
}
}
/*
* 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);
}
}
}
/*
* 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<Thread> set = (Set<Thread>) 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);
}
}
}
/*
* 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));
}
}
/*
* 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);
}
}
/*
* 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());
}
}
/*
* 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");
}
}
/*
* 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<WispEngine> 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));
}
}
/*
* 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();
}
}
#!/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
/*
* 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<WispEngine> 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();
}
}
/*
* 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() {
}
}
}
/*
* 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");
}
}
}
/*
* 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");
}
}
/*
* 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!");
}
}
/*
* 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);
}
}
/*
* 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();
}
}
/*
* 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();
}
}
/*
* 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;
}
}
/*
* 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();
}
}
/*
* 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<Properties>() {
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();
}
}
/*
* 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!!!");
}
}
/*
* 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;
}
}
}
/*
* 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<Socket> 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<Socket> 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<Socket> 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);
}
}
/*
* 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();
}
}
/*
* 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");
}
}
/*
* 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());
}
}
/*
* 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();
}
}
/*
* 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!");
}
}
/*
* 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);
}
}
/*
* 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++;
}
}
/*
* 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();
}
}
}
}
/*
* 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];
}
/*
* 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));
}
}
}
/*
* 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<Runnable> 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);
}
}
}
}
/*
* 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() {
}
}
/*
* 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 {
}
}
/*
* 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));
}
}
/*
* 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");
}
}
/*
* 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);
}
}
/*
* 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<WispEngine> 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));
}
}
/*
* 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<Thread> 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");
}
}
/*
* 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());
}
}
/*
* 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<Thread> 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());
}
}
/*
* 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;
}
/*
* 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]);
}
}
/*
* 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<WispTask> 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.");
}
}
/*
* 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<TimeOut> {
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<Long> sorted = new ArrayList<>(n);
for (int i = 0; i < n; i++)
sorted.add(new Long(i));
List<Long> shuffled = new ArrayList<>(sorted);
Collections.shuffle(shuffled);
Object pq = getTimerQueue();
for (Iterator<Long> i = shuffled.iterator(); i.hasNext(); )
add(pq, new TimeOut(null, i.next(), false));
List<Long> 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<Long> i = sorted.iterator(); i.hasNext(); )
if ((i.next().intValue() % 2) != 1)
i.remove();
assertTrue(recons.equals(sorted), "Odd Sort failed");
}
}
/*
* 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<Future<Boolean>> rpcs = IntStream.range(0, 50).mapToObj(i -> {
AtomicBoolean done = new AtomicBoolean(false);
FutureTask<Boolean> 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;
}
}));
}
}
/*
* 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<Integer> 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;
}
}));
}
}
/*
* 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);
}
}
/*
* 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"));
}
}
/*
* 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));
}
}
/*
* 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"));
}
}
/*
* 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]);
}
}
/*
* 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);
}
}
/*
* 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();
}
/*
* 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<Properties>() {
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<Thread> set = (Set<Thread>)field.get(null);
// Thread.sleep(200);
// assertTrue(set.size() == 1);
}
}
/*
* 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<Properties>() {
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");
}
}
}
/*
* 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());
}
}
/*
* 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
/*
* 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<WispTask> 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"));
}
}
/*
* 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));
}
}
/*
* 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());
}
}
/*
* 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<Properties>() {
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());
}
}
/*
* 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
/*
* 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();
}
}
/*
* 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<Boolean> 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<Boolean> 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<Boolean> future = new FutureTask<>(ThreadAsWispBlackListTest::isRealThread);
ForkJoinPool.commonPool().execute(future);
assertTrue(future.get());
}
private static void testMultiEntry() throws Exception {
setBlackList("name:m1111;name:m2222");
FutureTask<Boolean> 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);
}
}
/*
* 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();
}
}
/*
* 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();
}
}
/*
* 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<Boolean> list = mbean.getRunningStates();
System.out.println(list);
int size1 = list.size();
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
list = mbean.getRunningStates();
System.out.println(list);
int size2 = list.size();
assertTrue((size1 - size2) == 4);
}
// task running in compiled code
private static void decIt(long num) {
while (0 != num--) ;
}
private static final Runnable RUN_COMPILED_BUSY_LOOP = () -> {
// warmup
for (int i = 0; i < 5000; ++i) {
decIt(i);
}
while (true) {
decIt(0xFFFFFFFFl);
}
};
static class WispMultiThreadExecutor extends AbstractExecutorService {
private final WispEngine delegated;
public WispMultiThreadExecutor(int threadCount, ThreadFactory threadFactory) {
delegated = WispEngine.createEngine(threadCount, threadFactory);
}
@Override
public void execute(Runnable command) {
delegated.execute(command);
}
@Override
public void shutdown() {
delegated.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
return null;
}
@Override
public boolean isShutdown() {
return false;
}
@Override
public boolean isTerminated() {
return false;
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegated.awaitTermination(timeout, unit);
}
}
}
/*
* 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 Wisp2ShutdownTest
* @requires os.family == "linux"
* @library /lib/testlibrary
* @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 Wisp2ShutdownTest
*/
import com.alibaba.wisp.engine.WispEngine;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static jdk.testlibrary.Asserts.assertEQ;
import static jdk.testlibrary.Asserts.assertTrue;
public class Wisp2ShutdownTest {
public static void main(String[] args) throws Exception {
basicShutDownTest();
multiGroupsShutDownTest();
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void basicShutDownTest() throws Exception {
AtomicInteger n = new AtomicInteger();
WispEngine g = WispEngine.createEngine(4, Thread::new);
for (int i = 0; i < 888; i++) {
g.execute(() -> {
n.incrementAndGet();
try {
while (true) {
sleep(1000000);
}
} finally {
n.decrementAndGet();
}
});
}
while (n.get() != 888) {
n.get();
}
long start = System.currentTimeMillis();
g.shutdown();
assertTrue(g.awaitTermination(3, TimeUnit.SECONDS));
System.out.println(System.currentTimeMillis() - start + "ms");
assertEQ(n.get(), 0);
}
private static void multiGroupsShutDownTest() throws Exception {
CountDownLatch latch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
WispEngine.dispatch(() -> {
try {
basicShutDownTest();
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
});
}
assertTrue(latch.await(5, TimeUnit.SECONDS));
}
}
/*
* 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 canceled timers are removed ASAP
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 Wisp2TimerRemoveTest
* @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.highPrecisionTimer=true Wisp2TimerRemoveTest
*/
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.SharedSecrets;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.concurrent.*;
import static jdk.testlibrary.Asserts.*;
public class Wisp2TimerRemoveTest {
public static void main(String[] args) throws Exception {
BlockingQueue<Integer> q1 = new ArrayBlockingQueue<>(1);
BlockingQueue<Integer> q2 = new ArrayBlockingQueue<>(1);
ExecutorService es = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(2);
final int WORKERS = Runtime.getRuntime().availableProcessors();
for (int i = 0; i < WORKERS; i++) {
es.submit(() -> {
TimeUnit.MINUTES.sleep(10);
return null;
});
}
es.submit(() -> pingpong(q1, q2, latch));
es.submit(() -> pingpong(q2, q1, latch));
q1.offer(1);
latch.await();
for (int i = 0; i < WORKERS * 10; i++) { // iterate all carriers
Integer ql = es.submit(() -> {
// Object carrier = new FieldAccessor
Thread thread = Thread.currentThread();
TimeUnit.MILLISECONDS.sleep(1);
assertEQ(Thread.currentThread(), thread);
return new FieldAccessor(SharedSecrets.getJavaLangAccess().getWispTask(thread))
.access("carrier")
.access("worker")
.access("timerManager")
.access("queue")
.getInt("size");
}).get();
assertLessThanOrEqual(ql, WORKERS);
}
}
private static Void pingpong(BlockingQueue<Integer> pingQ,
BlockingQueue<Integer> pongQ,
CountDownLatch latch) throws Exception {
for (int i = 0; i < 100000; i++) {
pingQ.poll(1, TimeUnit.HOURS);
pongQ.offer(1);
}
stealInfo();
latch.countDown();
return null;
}
private static void stealInfo() throws ReflectiveOperationException {
int stealCount = new FieldAccessor(SharedSecrets.getWispEngineAccess().getCurrentTask())
.getInt("stealCount");
System.out.println("stealCount = " + stealCount);
}
static class FieldAccessor {
final Object obj;
FieldAccessor(Object o) {
this.obj = o;
}
FieldAccessor access(String fieldName) throws ReflectiveOperationException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return new FieldAccessor(field.get(obj));
}
int getInt(String fieldName) throws ReflectiveOperationException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.getInt(obj);
}
}
}
/*
* 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.wait/notify with coroutine in wisp2
* @requires os.family == "linux"
* @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 Wisp2WaitNotifyTest
*/
import com.alibaba.wisp.engine.WispEngine;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import static jdk.testlibrary.Asserts.assertEQ;
public class Wisp2WaitNotifyTest {
private AtomicInteger seq = new AtomicInteger();
private int finishCnt = 0;
private CountDownLatch latch = new CountDownLatch(1);
private boolean fooCond = false;
public static void main(String[] args) throws Exception {
Wisp2WaitNotifyTest s = new Wisp2WaitNotifyTest();
synchronized (s) {
WispEngine.dispatch(s::foo);
assertEQ(s.seq.getAndIncrement(), 0);
}
s.latch.await();
assertEQ(s.seq.getAndIncrement(), 5);
synchronized (s) {
while (s.finishCnt < 2) {
s.wait();
}
}
assertEQ(s.seq.getAndIncrement(), 6);
}
private synchronized void foo() {
assertEQ(seq.getAndIncrement(), 1);
WispEngine.dispatch(this::bar);
assertEQ(seq.getAndIncrement(), 2);
try {
while (!fooCond) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
assertEQ(seq.getAndIncrement(), 4);
latch.countDown();
finishCnt++;
notifyAll();
}
private void bar() {
synchronized (this) {
assertEQ(seq.getAndIncrement(), 3);
fooCond = true;
notifyAll();
}
synchronized (this) {
finishCnt++;
notifyAll();
}
}
}
/*
* 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 task exit flow for ThreadAsWisp task
* @requires os.family == "linux"
* @run main/othervm -XX:ActiveProcessorCount=2 -XX:+EnableCoroutine -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -XX:+UseWispMonitor -Dcom.alibaba.wisp.enableThreadAsWisp=true -Dcom.alibaba.wisp.allThreadAsWisp=true -Dcom.alibaba.wisp.engineTaskCache=2 Wisp2WithGlobalCacheTest
*/
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 Wisp2WithGlobalCacheTest {
public static void main(String[] args) throws Exception {
CountDownLatch done = new CountDownLatch(80);
Runnable r = () -> {
try {
Thread.sleep(100);
} catch(Throwable t) {
}
if (SharedSecrets.getJavaLangAccess().currentThread0() != Thread.currentThread()) {
done.countDown();
}
};
for (int i = 0; i < 10; i++) {
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();
new Thread() {
@Override
public void run() {
r.run();
}
}.start();
new Thread() {
@Override
public void run() {
r.run();
}
}.start();
new Thread() {
@Override
public void run() {
r.run();
}
}.start();
new Thread() {
@Override
public void run() {
r.run();
}
}.start();
new Thread() {
@Override
public void run() {
r.run();
}
}.start();
}
assertTrue(done.await(10, TimeUnit.SECONDS));
}
}
/*
* 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 verification of work stealing really happened
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.schedule.stealRetry=100 -Dcom.alibaba.wisp.schedule.helpStealRetry=100 Wisp2WorkStealTest
*/
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.SharedSecrets;
import java.util.concurrent.atomic.AtomicReference;
import static jdk.testlibrary.Asserts.assertNE;
public class Wisp2WorkStealTest {
public static void main(String[] args) {
Object lock = new Object();
AtomicReference<Thread> t = new AtomicReference<>();
AtomicReference<Thread> t2 = new AtomicReference<>();
WispEngine.dispatch(() -> {
t.set(SharedSecrets.getJavaLangAccess().currentThread0());
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t2.set(SharedSecrets.getJavaLangAccess().currentThread0());
});
// letting a coroutine occupy the carrier
while (true) {
AtomicReference<Boolean> found = new AtomicReference<>(null);
WispEngine.dispatch(() -> {
if (SharedSecrets.getJavaLangAccess().currentThread0() == t.get()) {
found.set(true);
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 1000) {
// occupy the carrier
}
} else {
found.set(false);
}
});
while (found.get() == null) {
}
if (found.get()) {
break;
}
}
synchronized (lock) {
lock.notify();
}
while (t2.get() == null) {
}
assertNE(t.get(), t2.get());
}
}
/*
* 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 semantic change after refactor
* @requires os.family == "linux"
* @library /lib/testlibrary
* @run main/othervm -XX:+UseWisp2 WispEngineCurrentTest
*/
import com.alibaba.wisp.engine.WispEngine;
import java.util.*;
import java.util.concurrent.*;
import static jdk.testlibrary.Asserts.assertTrue;
public class WispEngineCurrentTest {
public static void main(String[] args) throws Exception {
WispEngine engine = WispEngine.createEngine(4, r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
});
Set<WispEngine> wispEngineSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
CountDownLatch latch0 = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
engine.execute(() -> {
wispEngineSet.add(WispEngine.current());
latch0.countDown();
});
}
assertTrue(latch0.await(1, TimeUnit.SECONDS));
assertTrue(wispEngineSet.size() == 1);
CountDownLatch latch1 = new CountDownLatch(1);
WispEngine.dispatch(() -> {
wispEngineSet.add(WispEngine.current());
latch1.countDown();
});
assertTrue(latch1.await(1, TimeUnit.SECONDS));
assertTrue(wispEngineSet.size() == 2);
}
}
/*
* 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 WispInitShutdownTest
* @requires os.family == "linux"
* @library /lib/testlibrary
* @run main/othervm -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 WispInitShutdownTest
*/
import com.alibaba.wisp.engine.WispEngine;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static jdk.testlibrary.Asserts.assertEQ;
import static jdk.testlibrary.Asserts.assertTrue;
public class WispInitShutdownTest {
public static CountDownLatch shutddownLatch = new CountDownLatch(1);
public static AtomicBoolean suc = new AtomicBoolean(false);
public static void main(String[] args) throws Exception {
CountDownLatch finish = new CountDownLatch(1);
CountDownLatch cinit = new CountDownLatch(1);
WispEngine engine = WispEngine.createEngine(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("test-thread");
return t;
}
});
engine.execute(new Runnable() {
@Override
public void run() {
try {
cinit.countDown();
Class.forName("SomeC");
suc.set(true);
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
finish.countDown();
}
}
});
shutddownLatch.countDown();
cinit.await();
engine.shutdown();
finish.await();
assertTrue(suc.get());
}
}
class SomeC {
static {
try {
WispInitShutdownTest.shutddownLatch.await();
for (int i = 0; i < 10; i++) {
Thread.sleep(40);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
\ No newline at end of file
/*
* 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 ensure thread.isAlive() is false after thread.join()
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 ConcurrentThreadJoinTest
*/
import static jdk.testlibrary.Asserts.assertFalse;
public class ConcurrentThreadJoinTest {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 3000) {
Thread thread = new Thread(() -> {
});
thread.start();
thread.join(1000);
assertFalse(thread.isAlive());
}
}
}
/*
* 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 of update stealEnable fail
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 DisableStealBugTest
*/
import com.alibaba.wisp.engine.WispEngine;
import com.alibaba.wisp.engine.WispTask;
import sun.misc.SharedSecrets;
import java.lang.reflect.Field;
import java.util.concurrent.atomic.AtomicReference;
import static jdk.testlibrary.Asserts.assertTrue;
public class DisableStealBugTest {
public static void main(String[] args) throws Exception {
AtomicReference<WispTask> task = new AtomicReference<>();
WispEngine.dispatch(() -> {
task.set(SharedSecrets.getWispEngineAccess().getCurrentTask());
setOrGetStealEnable(task.get(), true, false);
try {
Thread.sleep(10);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread.sleep(2000);
boolean stealEnable = setOrGetStealEnable(task.get(), false, false);
assertTrue(stealEnable);
}
static boolean setOrGetStealEnable(WispTask task, boolean isSet, boolean b) {
try {
Field resumeEntryField = task.getClass().getDeclaredField("resumeEntry");
resumeEntryField.setAccessible(true);
final Object resumeEntry = resumeEntryField.get(task);
Field stealEnableField = resumeEntry.getClass().getDeclaredField("stealEnable");
stealEnableField.setAccessible(true);
if (isSet) {
stealEnableField.setBoolean(resumeEntry, b);
return b;
} else {
return stealEnableField.getBoolean(resumeEntry);
}
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
}
/*
* 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 epoll without wisp will not produce NPE
* @requires os.family == "linux"
* @run main EpollNPETest
*/
import java.nio.channels.Selector;
public class EpollNPETest {
public static void main(String[] args) throws Exception {
Selector sel = Selector.open();
sel.wakeup();
sel.select(100);
}
}
/*
* 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 selector.wakeup() dispatched
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 -verbose:class EpollWakeupTest 3000
*/
import java.nio.channels.Selector;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static jdk.testlibrary.Asserts.assertTrue;
/**
* Sleep random us before wakeup/select,
* To help us coverage all branches, including pre-wakeup, normal-wakeup, concurrent-wakeup
*/
public class EpollWakeupTest {
public static void main(String[] args) throws Exception {
Selector selector = Selector.open();
CyclicBarrier barrier = new CyclicBarrier(2);
Random random = new Random();
final Object lock = new Object();
boolean[] wakened = new boolean[1];
int[] cnt = new int[1];
Thread io = new Thread(() -> {
try {
while (true) {
barrier.await();
new CountDownLatch(1).await(random.nextInt(10), TimeUnit.MICROSECONDS);
selector.select();
synchronized (lock) {
cnt[0]++;
wakened[0] = true;
lock.notifyAll();
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}, "IO thread");
Thread biz = new Thread(() -> {
try {
while (true) {
selector.selectNow(); // clean up
wakened[0] = false;
barrier.await();
new CountDownLatch(1).await(random.nextInt(10), TimeUnit.MICROSECONDS);
selector.wakeup();
synchronized (lock) {
while (!wakened[0]) {
lock.wait();
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}, "biz thread");
io.setDaemon(true);
io.start();
biz.setDaemon(true);
biz.start();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
System.out.println(cnt[0]);
synchronized (lock) {
cnt[0] = 0;
}
}, 1, 1, TimeUnit.SECONDS);
Thread.sleep(Integer.valueOf(args[0]));
long deadline = System.currentTimeMillis() + 1000;
synchronized (lock) {
while (!wakened[0]) {
long timeout = deadline - System.currentTimeMillis();
assertTrue(timeout > 0, "io thread hang...");
lock.wait(timeout);
}
}
}
}
/*
* 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.isInNative() is correct
* @requires os.family == "linux"
* @run main/othervm -XX:+EnableCoroutine IsInNativeTest
*/
import sun.misc.SharedSecrets;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Properties;
import static jdk.testlibrary.Asserts.assertFalse;
import static jdk.testlibrary.Asserts.assertTrue;
public class IsInNativeTest {
static Properties p;
static String socketAddr;
static {
p = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Properties>() {
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 {
Thread nthread = new Thread(() -> {
try {
SocketChannel ch = SocketChannel.open(new InetSocketAddress(socketAddr, 80));
ch.read(ByteBuffer.allocate(4096));
} catch (IOException e) {
e.printStackTrace();
}
});
nthread.start();
Thread thread = new Thread(() -> {
while (true) {
}
});
thread.start();
Thread thread2 = new Thread(() -> {
});
thread2.start();
Thread.sleep(500);
assertFalse(SharedSecrets.getJavaLangAccess().isInSameNative(nthread));
assertFalse(SharedSecrets.getJavaLangAccess().isInSameNative(thread));
assertFalse(SharedSecrets.getJavaLangAccess().isInSameNative(thread2));
Thread.sleep(1000);
assertFalse(SharedSecrets.getJavaLangAccess().isInSameNative(thread));
}
}
/*
* 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 Verify wisp internal logic can not be preempted
* @requires os.family == "linux"
* @library /lib/testlibrary
* @run main PreemptWispInternalBugTest
*/
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.SharedSecrets;
import java.util.concurrent.FutureTask;
public class PreemptWispInternalBugTest {
private static final int timeOut = 1000;
private static String[] tasks = new String[] {"toString", "addTimer"};
public static void main(String[] args) throws Exception {
if (args.length == 0) {
for (int i = 0; i < tasks.length; i++) {
ProcessBuilder pb = jdk.testlibrary.ProcessTools.createJavaProcessBuilder(
"-XX:+UseWisp2", "-XX:+UnlockDiagnosticVMOptions", "-XX:+VerboseWisp", "-XX:-Inline",
"-Xcomp", "-Dcom.alibaba.wisp.sysmonTickUs=100000",
PreemptWispInternalBugTest.class.getName(), tasks[i]);
jdk.testlibrary.OutputAnalyzer output = new jdk.testlibrary.OutputAnalyzer(pb.start());
output.shouldContain("[WISP] preempt was blocked, because wisp internal method on the stack");
}
return;
}
FutureTask future = getTask(args[0]);
WispEngine.dispatch(future);
future.get();
}
private static FutureTask getFutureTask(Runnable runnable) {
return new FutureTask<>(() -> {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < timeOut) {
runnable.run();
}
return null;
});
}
private static FutureTask getTask(String taskName) {
switch (taskName) {
case "toString":
return getFutureTask(() -> SharedSecrets.getWispEngineAccess().getCurrentTask().toString());
case "addTimer":
return getFutureTask(() -> {
SharedSecrets.getWispEngineAccess().addTimer(System.nanoTime() + 1008611);
SharedSecrets.getWispEngineAccess().cancelTimer();
});
default:
throw new IllegalArgumentException();
}
}
}
\ No newline at end of file
/*
* 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 queue length not growth infinity
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 DisableStealBugTest
*/
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.SharedSecrets;
import java.lang.reflect.Method;
import java.util.concurrent.CountDownLatch;
import static jdk.testlibrary.Asserts.assertLT;
public class SchedulerQLBugTest {
public static void main(String[] args) throws Exception {
WispEngine g = WispEngine.createEngine(2, Thread::new);
CountDownLatch latch = new CountDownLatch(1);
g.execute(() -> {
DisableStealBugTest.setOrGetStealEnable(SharedSecrets.getWispEngineAccess().getCurrentTask(), true, false);
latch.countDown();
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
latch.await();
for (int i = 0; i < 10; i++) { // trigger steal
g.execute(() -> { /**/});
}
Thread.sleep(100);
for (int i = 0; i < 10; i++) {
int ql = g.submit(() -> {
try {
Method getCurrent = WispCarrier.class.getDeclaredMethod("current");
getCurrent.setAccessible(true);
Method m = WispCarrier.class.getDeclaredMethod("getTaskQueueLength");
m.setAccessible(true);
return (int) m.invoke(getCurrent.invoke(null));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}).get();
assertLT(ql, 100);
}
}
}
/*
* 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 thread object leak in thread group
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 Wisp2ThreadObjLeakInThreadGroupTest
*/
import java.util.concurrent.CountDownLatch;
import static jdk.testlibrary.Asserts.assertEQ;
public class Wisp2ThreadObjLeakInThreadGroupTest {
public static void main(String[] args) throws Exception {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
int count = tg.activeCount();
CountDownLatch c1 = new CountDownLatch(1), c2 = new CountDownLatch(1);
Thread thread = new Thread(tg, () -> {
c1.countDown();
try {
c2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, Wisp2ThreadObjLeakInThreadGroupTest.class.getSimpleName());
thread.start();
c1.await(); // wait start
assertEQ(tg.activeCount(), count + 1);
c2.countDown(); // notify finish
thread.join();
assertEQ(tg.activeCount(), count);
}
}
/*
* 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 yield in wisp2
* @requires os.family == "linux"
* @run main/othervm -XX:-UseBiasedLocking -XX:+EnableCoroutine -XX:+UseWispMonitor -Dcom.alibaba.wisp.transparentWispSwitch=true -Dcom.alibaba.wisp.version=2 -Dcom.alibaba.wisp.workerEngines=1 Wisp2YieldTest
*/
import com.alibaba.wisp.engine.WispEngine;
import static jdk.testlibrary.Asserts.assertTrue;
public class Wisp2YieldTest {
public static void main(String[] args) {
boolean success[] = new boolean[1];
WispEngine.dispatch(() -> {
WispEngine.dispatch(() -> {
success[0] = true;
});
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 100) {
}
Thread.yield();
while (true) {
}
});
sleep(1000);
assertTrue(success[0]);
}
private static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
* 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 yield not really happened when queue is empty
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 YieldEmptyQueueTest
*/
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.JavaLangAccess;
import sun.misc.SharedSecrets;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.Executors;
import static jdk.testlibrary.Asserts.assertTrue;
public class YieldEmptyQueueTest {
public static void main(String[] args) throws Exception {
assertTrue(Executors.newSingleThreadExecutor().submit(() -> {
long sc = (long) new ObjAccess(SharedSecrets.getJavaLangAccess().getWispTask(Thread.currentThread()))
.ref("carrier").ref("counter").ref("switchCount").obj;
Thread.yield();
return (long) new ObjAccess(SharedSecrets.getJavaLangAccess().getWispTask(Thread.currentThread()))
.ref("carrier").ref("counter").ref("switchCount").obj == sc;
}).get());
}
static class ObjAccess {
Object obj;
ObjAccess(Object obj) {
this.obj = obj;
}
ObjAccess ref(String field) {
try {
Field f;
try {
f = obj.getClass().getDeclaredField(field);
} catch (NoSuchFieldException e) {
f = obj.getClass().getSuperclass().getDeclaredField(field);
}
f.setAccessible(true);
return new ObjAccess(f.get(obj));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
}
}
/*
* 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 park not happened for a very small interval
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 YieldFewNanosTest
*/
import com.alibaba.wisp.engine.WispEngine;
import sun.misc.SharedSecrets;
import java.lang.reflect.Method;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.LockSupport;
import static jdk.testlibrary.Asserts.assertTrue;
public class YieldFewNanosTest {
public static void main(String[] args) throws Exception {
assertTrue(Executors.newSingleThreadExecutor().submit(() -> {
long pc = (long) new YieldEmptyQueueTest.ObjAccess(SharedSecrets.getJavaLangAccess().getWispTask(Thread.currentThread()))
.ref("carrier").ref("counter").ref("parkCount").obj;
LockSupport.parkNanos(1);
return (long) new YieldEmptyQueueTest.ObjAccess(SharedSecrets.getJavaLangAccess().getWispTask(Thread.currentThread()))
.ref("carrier").ref("counter").ref("parkCount").obj == pc;
}).get());
}
}
/*
* 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 timer could be processed when we're yielding
* @requires os.family == "linux"
* @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.carrierEngines=1 YieldTimerTest
* @run main/othervm -XX:+UseWisp2 -Dcom.alibaba.wisp.carrierEngines=1 -Dcom.alibaba.wisp.highPrecisionTimer=true YieldTimerTest
*/
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class YieldTimerTest {
public static void main(String[] args) throws Exception {
Future<?> future = Executors.newSingleThreadExecutor().submit(() -> {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
new Thread(() -> {
while (true) {
Thread.yield();
}
}).start();
future.get(1, TimeUnit.SECONDS);
}
}
...@@ -87,6 +87,10 @@ abstract class Task<T> implements Runnable { ...@@ -87,6 +87,10 @@ abstract class Task<T> implements Runnable {
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
String name = entries.nextElement().getName(); String name = entries.nextElement().getName();
if (name.startsWith("java") && name.endsWith(".class")) { if (name.startsWith("java") && name.endsWith(".class")) {
if (name.startsWith("java/dyn")) {
// skip coroutine classes
continue;
}
classes.add(Class.forName(name.substring(0, name.indexOf(".")).replace('/', '.'))); classes.add(Class.forName(name.substring(0, name.indexOf(".")).replace('/', '.')));
if (count == classes.size()) { if (count == classes.size()) {
break; break;
......
/*
* 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 basic coroutine steal mechanism
* @library /lib/testlibrary
* @run main/othervm -XX:+EnableCoroutine BasicStealTest
*/
import java.dyn.Coroutine;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import static jdk.testlibrary.Asserts.assertEQ;
import static jdk.testlibrary.Asserts.assertTrue;
public class BasicStealTest {
public static void main(String[] args) {
AtomicReference<Coroutine> toBeStolen = new AtomicReference<>();
Thread main = Thread.currentThread();
Thread t = new Thread(() -> {
Coroutine threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
Coroutine coro = new Coroutine(() -> {
AtomicReference<Consumer<Integer>> foo = new AtomicReference<>();
foo.set((x) -> {
if (x == 10) {
Coroutine.yieldTo(threadCoro);
} else {
System.out.println(x + " enter " + Thread.currentThread());
foo.get().accept(x + 1);
System.out.println(x + " exit" + Thread.currentThread());
assertEQ(Thread.currentThread(), main);
}
});
foo.get().accept(0);
});
Coroutine.yieldTo(coro);
// switch from foo()...
toBeStolen.set(coro);
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "new_thread");
t.setDaemon(true);
t.start();
while (toBeStolen.get() == null) {
}
assertEQ(toBeStolen.get().steal(false), Coroutine.StealResult.SUCCESS);
Coroutine.yieldTo(toBeStolen.get());
}
}
/*
* 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 unit tests for steal in concurrent situation
* @run junit/othervm/timeout=300 -XX:+EnableCoroutine ConcurrentStealTest
*/
import org.junit.Test;
import java.dyn.Coroutine;
import java.dyn.CoroutineSupport;
import java.util.Arrays;
import java.util.Comparator;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import static org.junit.Assert.*;
public class ConcurrentStealTest {
@Test
public void stealRunning() throws Exception {
Coroutine[] coro = new Coroutine[1];
CountDownLatch cdl = new CountDownLatch(1);
Thread t = new Thread(() -> {
coro[0] = new Coroutine(() -> {
try {
cdl.countDown();
Thread.sleep(10000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Coroutine.yieldTo(coro[0]);
}, "stealRunning");
t.setDaemon(true);
t.start();
cdl.await();
Thread.sleep(500);
assertEquals(coro[0].steal(false), Coroutine.StealResult.FAIL_BY_STATUS);
}
final static int THREADS = Math.min(Runtime.getRuntime().availableProcessors(), 8);
final static int CORO_PER_TH = 20;
final static int TIMEOUT = 10;
@Test
public void randomSteal() throws Exception {
CoroutineAdaptor[] coro = new CoroutineAdaptor[THREADS * CORO_PER_TH];
Stat[] cnt = new Stat[THREADS];
StealWorker[] stealWorkers = new StealWorker[THREADS];
AtomicInteger sync = new AtomicInteger();
for (int th = 0; th < THREADS; th++) {
cnt[th] = new Stat();
stealWorkers[th] = new StealWorker(coro, cnt , sync, th, stealWorkers);
Thread t = new Thread(stealWorkers[th], "randomSteal-" + th);
t.setDaemon(true);
t.start();
}
while (sync.get() != THREADS) {
}
long start = System.nanoTime();
while (System.nanoTime() - start < TimeUnit.SECONDS.toNanos(TIMEOUT)) {
}
for (int i = 0; i < cnt.length; i++) {
cnt[i].stealCnt /= TIMEOUT;
cnt[i].yieldCnt /= TIMEOUT;
cnt[i].stealFailedCnt /= TIMEOUT;
}
System.out.println(Arrays.toString(cnt));
}
class StealWorker implements Runnable {
CoroutineAdaptor[] coro;
Coroutine threadCoro;
public ConcurrentSkipListSet<CoroutineAdaptor> stealables = new ConcurrentSkipListSet<>(new Comparator<CoroutineAdaptor>() {
@Override
public int compare(CoroutineAdaptor o1, CoroutineAdaptor o2) {
return Long.compare(o1.id, o2.id);
}
});
Stat[] cnt;
StealWorker[] workers;
AtomicInteger sync;
int cth;
StealWorker(CoroutineAdaptor[] coro, Stat[] cnt, AtomicInteger sync, int cth, StealWorker[] workers) {
this.coro = coro;
this.cnt = cnt;
this.sync = sync;
this.cth = cth;
this.workers = workers;
}
@Override
public void run() {
threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
for (int i = 0; i < CORO_PER_TH; i++) {
coro[CORO_PER_TH * cth + i] = new CoroutineAdaptor(() -> {
while (true) {
Coroutine.yieldTo(threadCoro);
cnt[cth].yieldCnt++;
}
});
}
for (int i = 0; i < CORO_PER_TH; i++) {
CoroutineAdaptor coroutineAdaptor = new CoroutineAdaptor(() ->{
while (true) {
yield();
}
});
Coroutine.yieldTo(coroutineAdaptor);
stealables.add(coroutineAdaptor);
}
sync.incrementAndGet();
while (sync.get() != THREADS) {
}
runRandom(System.nanoTime(), (cth + 1) % THREADS);
}
void yield() {
Coroutine.yieldTo(coro[CORO_PER_TH * cth + ThreadLocalRandom.current().nextInt(CORO_PER_TH)]);
}
void runRandom(long start, int nxt) {
while (System.nanoTime() - start < TimeUnit.SECONDS.toNanos(TIMEOUT)) {
for (int i = 0; i < 2; i ++) {
if(i != 1) {
yield();
cnt[cth].yieldCnt++;
} else {
CoroutineAdaptor target = workers[nxt].stealables.pollFirst();
if (target != null && target.steal(true) == Coroutine.StealResult.SUCCESS) {
stealables.add(target);
cnt[cth].stealCnt++;
} else {
if (target != null)
workers[nxt].stealables.add(target);
cnt[cth].stealFailedCnt++;
}
}
}
}
}
}
static AtomicInteger seq = new AtomicInteger(0);
class CoroutineAdaptor extends Coroutine {
long id;
CoroutineAdaptor(Runnable runnable) {
super(runnable);
id = seq.addAndGet(1);
}
}
class Stat {
int stealCnt;
int yieldCnt;
int stealFailedCnt;
@Override
public String toString() {
return "\n < steal Cnt " + stealCnt + ">, < yieldCnt" + yieldCnt + "> , < stealFailedCnt " + stealFailedCnt + " > ";
}
}
}
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
package test.java.dyn; package test.java.dyn;
import java.dyn.Coroutine; import java.dyn.Coroutine;
import java.dyn.AsymCoroutine;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
...@@ -51,188 +50,78 @@ public class CoroutineTest { ...@@ -51,188 +50,78 @@ public class CoroutineTest {
@Test @Test
public void symSequence() { public void symSequence() {
Coroutine threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
Coroutine coro = new Coroutine() { Coroutine coro = new Coroutine() {
protected void run() { protected void run() {
seq.append("c"); seq.append("c");
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
yield(); Coroutine.yieldTo(threadCoro);
seq.append("e"); seq.append("e");
} }
} }
}; };
seq.append("b"); seq.append("b");
assertFalse(coro.isFinished()); assertFalse(coro.isFinished());
Coroutine.yield(); Coroutine.yieldTo(coro);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
seq.append("d"); seq.append("d");
assertFalse(coro.isFinished()); assertFalse(coro.isFinished());
Coroutine.yield(); Coroutine.yieldTo(coro);
} }
seq.append("f"); seq.append("f");
assertTrue(coro.isFinished()); assertTrue(coro.isFinished());
Coroutine.yield();
seq.append("g"); seq.append("g");
assertEquals("abcdededefg", seq.toString()); assertEquals("abcdededefg", seq.toString());
} }
@Test
public void symMultiSequence() {
for (int i = 0; i < 10; i++)
new Coroutine() {
protected void run() {
seq.append("c");
yield();
seq.append("e");
}
};
seq.append("b");
Coroutine.yield();
seq.append("d");
Coroutine.yield();
seq.append("f");
Coroutine.yield();
seq.append("g");
assertEquals("abccccccccccdeeeeeeeeeefg", seq.toString());
}
@Test
public void asymSequence() {
AsymCoroutine<Void, Void> coro = new AsymCoroutine<Void, Void>() {
protected Void run(Void value) {
seq.append(value + "b");
Object o = ret();
seq.append(o + "d");
return null;
}
};
assertFalse(coro.isFinished());
coro.call();
assertFalse(coro.isFinished());
seq.append("c");
coro.call();
seq.append("e");
assertTrue(coro.isFinished());
RuntimeException exception = null;
try {
coro.call();
} catch (RuntimeException e) {
exception = e;
}
assertNotNull(exception);
assertEquals("anullbcnullde", seq.toString());
}
@Test
public void asymMultiSequence() {
AsymCoroutine<Void, Void> coro = null;
for (int j = 4; j >= 0; j--) {
final AsymCoroutine<Void, Void> last = coro;
final int i = j;
coro = new AsymCoroutine<Void, Void>() {
protected Void run(Void value) {
seq.append("b" + i);
if (last != null)
last.call();
seq.append("c" + i);
ret();
seq.append("e" + i);
if (last != null)
last.call();
seq.append("f" + i);
return null;
}
};
}
seq.append("_");
assertFalse(coro.isFinished());
coro.call();
assertFalse(coro.isFinished());
seq.append("d");
coro.call();
seq.append("g");
assertTrue(coro.isFinished());
RuntimeException exception = null;
try {
coro.call();
} catch (RuntimeException e) {
exception = e;
}
assertNotNull(exception);
assertEquals("a_b0b1b2b3b4c4c3c2c1c0de0e1e2e3e4f4f3f2f1f0g", seq.toString());
}
@Test
public void asymReturnValue() {
AsymCoroutine<Integer, Integer> coro = new AsymCoroutine<Integer, Integer>() {
protected Integer run(Integer value) {
value = ret(value * 2 + 1);
value = ret(value * 2 + 2);
value = ret(value * 2 + 3);
value = ret(value * 2 + 4);
value = ret(value * 2 + 5);
return value * 2 + 6;
}
};
assertFalse(coro.isFinished());
assertEquals(2001, (int) coro.call(1000));
assertEquals(4002, (int) coro.call(2000));
assertEquals(6003, (int) coro.call(3000));
assertEquals(8004, (int) coro.call(4000));
assertEquals(10005, (int) coro.call(5000));
assertEquals(12006, (int) coro.call(6000));
assertTrue(coro.isFinished());
}
@Test @Test
public void gcTest1() { public void gcTest1() {
new Coroutine() { Coroutine threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
Coroutine coro = new Coroutine() {
protected void run() { protected void run() {
seq.append("c"); seq.append("c");
Integer v1 = 1; Integer v1 = 1;
Integer v2 = 14555668; Integer v2 = 14555668;
yield(); yieldTo(threadCoro);
seq.append("e"); seq.append("e");
seq.append("(" + v1 + "," + v2 + ")"); seq.append("(" + v1 + "," + v2 + ")");
} }
}; };
seq.append("b"); seq.append("b");
System.gc(); System.gc();
Coroutine.yield(); Coroutine.yieldTo(coro);
System.gc(); System.gc();
seq.append("d"); seq.append("d");
Coroutine.yield(); Coroutine.yieldTo(coro);
seq.append("f"); seq.append("fg");
Coroutine.yield();
seq.append("g");
assertEquals("abcde(1,14555668)fg", seq.toString()); assertEquals("abcde(1,14555668)fg", seq.toString());
} }
@Test @Test
public void exceptionTest1() { public void exceptionTest1() {
Coroutine threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
Coroutine coro = new Coroutine() { Coroutine coro = new Coroutine() {
protected void run() { protected void run() {
seq.append("c"); seq.append("c");
long temp = System.nanoTime(); long temp = System.nanoTime();
if (temp != 0) if (temp != 0)
throw new RuntimeException(); throw new RuntimeException();
yield();
seq.append("e"); seq.append("e");
} }
}; };
seq.append("b"); seq.append("b");
assertFalse(coro.isFinished()); assertFalse(coro.isFinished());
Coroutine.yield(); Coroutine.yieldTo(coro);
seq.append("d"); seq.append("d");
Coroutine.yield();
seq.append("f"); seq.append("f");
assertEquals("abcdf", seq.toString()); assertEquals("abcdf", seq.toString());
} }
@Test @Test
public void largeStackframeTest() { public void largeStackframeTest() {
new Coroutine() { Coroutine threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
Coroutine coro = new Coroutine() {
protected void run() { protected void run() {
seq.append("c"); seq.append("c");
Integer v0 = 10000; Integer v0 = 10000;
...@@ -255,47 +144,48 @@ public class CoroutineTest { ...@@ -255,47 +144,48 @@ public class CoroutineTest {
Integer v17 = 10017; Integer v17 = 10017;
Integer v18 = 10018; Integer v18 = 10018;
Integer v19 = 10019; Integer v19 = 10019;
yield(); yieldTo(threadCoro);
int sum = v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + v14 + v15 + v16 + v17 + v18 + v19; int sum = v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + v14 + v15 + v16 + v17 + v18 + v19;
seq.append("e" + sum); seq.append("e" + sum);
} }
}; };
seq.append("b"); seq.append("b");
System.gc(); System.gc();
Coroutine.yield(); Coroutine.yieldTo(coro);
System.gc(); System.gc();
seq.append("d"); seq.append("d");
Coroutine.yield(); Coroutine.yieldTo(coro);
seq.append("f"); seq.append("f");
assertEquals("abcde200190f", seq.toString()); assertEquals("abcde200190f", seq.toString());
} }
@Test @Test
public void shaTest() { public void shaTest() {
Coroutine threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
Coroutine coro = new Coroutine(65536) { Coroutine coro = new Coroutine(65536) {
protected void run() { protected void run() {
try { try {
MessageDigest digest = MessageDigest.getInstance("SHA"); MessageDigest digest = MessageDigest.getInstance("SHA");
digest.update("TestMessage".getBytes()); digest.update("TestMessage".getBytes());
seq.append("b"); seq.append("b");
yield(); yieldTo(threadCoro);
seq.append(digest.digest()[0]); seq.append(digest.digest()[0]);
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
}; };
Coroutine.yield(); Coroutine.yieldTo(coro);
seq.append("c"); seq.append("c");
assertFalse(coro.isFinished()); assertFalse(coro.isFinished());
Coroutine.yield(); Coroutine.yieldTo(coro);
assertTrue(coro.isFinished()); assertTrue(coro.isFinished());
assertEquals("abc72", seq.toString()); assertEquals("abc72", seq.toString());
} }
public void stackoverflowTest() { public void stackoverflowTest() {
for (int i = 0; i < 10; i++) { Coroutine threadCoro = Thread.currentThread().getCoroutineSupport().threadCoroutine();
new Coroutine(65536) { new Coroutine(255) {
int i = 0; int i = 0;
protected void run() { protected void run() {
...@@ -314,7 +204,11 @@ public class CoroutineTest { ...@@ -314,7 +204,11 @@ public class CoroutineTest {
iter(); iter();
} }
}; };
Coroutine.yieldTo(threadCoro);
} }
Coroutine.yield();
@Test
public void destroyNonInitedTest() {
new Coroutine();
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册