8339285: Test fails with assert(depth < max_critical_stack_depth) failed: can't have more than 10 critical frames
Reviewed-by: alanb
This commit is contained in:
parent
48d79431c9
commit
9e1af8cc7c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -46,9 +46,8 @@ static long calculate_number_of_pages_in_range(void* address, size_t len, size_t
|
|||||||
return numPages;
|
return numPages;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
jlong len, jlong numPages)
|
||||||
jlong len, jlong numPages)
|
|
||||||
{
|
{
|
||||||
jboolean loaded = JNI_TRUE;
|
jboolean loaded = JNI_TRUE;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
@ -93,8 +92,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
|
||||||
jlong len)
|
jlong len)
|
||||||
{
|
{
|
||||||
char *a = (char *)jlong_to_ptr(address);
|
char *a = (char *)jlong_to_ptr(address);
|
||||||
@ -104,9 +102,8 @@ Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
jlong len)
|
||||||
jlong len)
|
|
||||||
{
|
{
|
||||||
char *a = (char *)jlong_to_ptr(address);
|
char *a = (char *)jlong_to_ptr(address);
|
||||||
int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED);
|
int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED);
|
||||||
@ -198,8 +195,7 @@ static int validate_msync_address(size_t address)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||||
Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
|
||||||
jlong address, jlong len)
|
jlong address, jlong len)
|
||||||
{
|
{
|
||||||
void* a = (void *)jlong_to_ptr(address);
|
void* a = (void *)jlong_to_ptr(address);
|
||||||
@ -218,3 +214,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
|||||||
JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed");
|
JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FD "Ljava/io/FileDescriptor;"
|
||||||
|
|
||||||
|
static JNINativeMethod methods[] = {
|
||||||
|
{"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0},
|
||||||
|
{"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0},
|
||||||
|
{"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0},
|
||||||
|
{"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0},
|
||||||
|
};
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls)
|
||||||
|
{
|
||||||
|
(*env)->RegisterNatives(env, cls,
|
||||||
|
methods, sizeof(methods)/sizeof(methods[0]));
|
||||||
|
}
|
||||||
|
@ -2450,7 +2450,8 @@ public abstract class ClassLoader {
|
|||||||
* @param javaName the native method's declared name
|
* @param javaName the native method's declared name
|
||||||
*/
|
*/
|
||||||
static long findNative(ClassLoader loader, Class<?> clazz, String entryName, String javaName) {
|
static long findNative(ClassLoader loader, Class<?> clazz, String entryName, String javaName) {
|
||||||
long addr = findNativeInternal(loader, entryName);
|
NativeLibraries nativeLibraries = nativeLibrariesFor(loader);
|
||||||
|
long addr = nativeLibraries.find(entryName);
|
||||||
if (addr != 0 && loader != null) {
|
if (addr != 0 && loader != null) {
|
||||||
Reflection.ensureNativeAccess(clazz, clazz, javaName, true);
|
Reflection.ensureNativeAccess(clazz, clazz, javaName, true);
|
||||||
}
|
}
|
||||||
@ -2462,11 +2463,11 @@ public abstract class ClassLoader {
|
|||||||
* to avoid a restricted check, as that check has already been performed when
|
* to avoid a restricted check, as that check has already been performed when
|
||||||
* obtaining the lookup.
|
* obtaining the lookup.
|
||||||
*/
|
*/
|
||||||
static long findNativeInternal(ClassLoader loader, String entryName) {
|
static NativeLibraries nativeLibrariesFor(ClassLoader loader) {
|
||||||
if (loader == null) {
|
if (loader == null) {
|
||||||
return BootLoader.getNativeLibraries().find(entryName);
|
return BootLoader.getNativeLibraries();
|
||||||
} else {
|
} else {
|
||||||
return loader.libraries.find(entryName);
|
return loader.libraries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import jdk.internal.javac.Restricted;
|
import jdk.internal.javac.Restricted;
|
||||||
|
import jdk.internal.loader.NativeLibraries;
|
||||||
import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder;
|
import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder;
|
||||||
import jdk.internal.misc.Blocker;
|
import jdk.internal.misc.Blocker;
|
||||||
import jdk.internal.misc.CarrierThreadLocal;
|
import jdk.internal.misc.CarrierThreadLocal;
|
||||||
@ -2662,8 +2663,8 @@ public final class System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long findNative(ClassLoader loader, String entry) {
|
public NativeLibraries nativeLibrariesFor(ClassLoader loader) {
|
||||||
return ClassLoader.findNativeInternal(loader, entry);
|
return ClassLoader.nativeLibrariesFor(loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,6 +31,7 @@ import jdk.internal.foreign.MemorySessionImpl;
|
|||||||
import jdk.internal.foreign.Utils;
|
import jdk.internal.foreign.Utils;
|
||||||
import jdk.internal.javac.Restricted;
|
import jdk.internal.javac.Restricted;
|
||||||
import jdk.internal.loader.BuiltinClassLoader;
|
import jdk.internal.loader.BuiltinClassLoader;
|
||||||
|
import jdk.internal.loader.NativeLibraries;
|
||||||
import jdk.internal.loader.NativeLibrary;
|
import jdk.internal.loader.NativeLibrary;
|
||||||
import jdk.internal.loader.RawNativeLibraries;
|
import jdk.internal.loader.RawNativeLibraries;
|
||||||
import jdk.internal.reflect.CallerSensitive;
|
import jdk.internal.reflect.CallerSensitive;
|
||||||
@ -256,7 +257,8 @@ public interface SymbolLookup {
|
|||||||
if (Utils.containsNullChars(name)) return Optional.empty();
|
if (Utils.containsNullChars(name)) return Optional.empty();
|
||||||
JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
|
JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
|
||||||
// note: ClassLoader::findNative supports a null loader
|
// note: ClassLoader::findNative supports a null loader
|
||||||
long addr = javaLangAccess.findNative(loader, name);
|
NativeLibraries nativeLibraries = javaLangAccess.nativeLibrariesFor(loader);
|
||||||
|
long addr = nativeLibraries.find(name);
|
||||||
return addr == 0L ?
|
return addr == 0L ?
|
||||||
Optional.empty() :
|
Optional.empty() :
|
||||||
Optional.of(MemorySegment.ofAddress(addr)
|
Optional.of(MemorySegment.ofAddress(addr)
|
||||||
|
@ -116,6 +116,18 @@ import jdk.internal.misc.Unsafe;
|
|||||||
private static native void unload0(long address, long length);
|
private static native void unload0(long address, long length);
|
||||||
private static native void force0(FileDescriptor fd, long address, long length) throws IOException;
|
private static native void force0(FileDescriptor fd, long address, long length) throws IOException;
|
||||||
|
|
||||||
|
/* Register the natives via the static initializer.
|
||||||
|
*
|
||||||
|
* This is required, as these native methods are "scoped methods" (see ScopedMemoryAccess).
|
||||||
|
* As such, it's better not to end up doing a full JNI lookup while in a scoped method context,
|
||||||
|
* as that will make the stack trace too deep.
|
||||||
|
*/
|
||||||
|
private static native void registerNatives();
|
||||||
|
static {
|
||||||
|
registerNatives();
|
||||||
|
isLoaded0(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// utility methods
|
// utility methods
|
||||||
|
|
||||||
// Returns the distance (in bytes) of the buffer start from the
|
// Returns the distance (in bytes) of the buffer start from the
|
||||||
|
@ -29,6 +29,7 @@ import java.io.InputStream;
|
|||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.foreign.MemorySegment;
|
import java.lang.foreign.MemorySegment;
|
||||||
|
import java.lang.foreign.SymbolLookup;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.module.ModuleDescriptor;
|
import java.lang.module.ModuleDescriptor;
|
||||||
@ -46,6 +47,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import jdk.internal.loader.NativeLibraries;
|
||||||
import jdk.internal.misc.CarrierThreadLocal;
|
import jdk.internal.misc.CarrierThreadLocal;
|
||||||
import jdk.internal.module.ServicesCatalog;
|
import jdk.internal.module.ServicesCatalog;
|
||||||
import jdk.internal.reflect.ConstantPool;
|
import jdk.internal.reflect.ConstantPool;
|
||||||
@ -478,7 +480,11 @@ public interface JavaLangAccess {
|
|||||||
|
|
||||||
int getCharsUTF16(long i, int index, byte[] buf);
|
int getCharsUTF16(long i, int index, byte[] buf);
|
||||||
|
|
||||||
long findNative(ClassLoader loader, String entry);
|
/**
|
||||||
|
* Returns the {@link NativeLibraries} object associated with the provided class loader.
|
||||||
|
* This is used by {@link SymbolLookup#loaderLookup()}.
|
||||||
|
*/
|
||||||
|
NativeLibraries nativeLibrariesFor(ClassLoader loader);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Direct access to Shutdown.exit to avoid security manager checks
|
* Direct access to Shutdown.exit to avoid security manager checks
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -40,9 +40,8 @@ typedef unsigned char mincore_vec_t;
|
|||||||
typedef char mincore_vec_t;
|
typedef char mincore_vec_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
jlong len, jlong numPages)
|
||||||
jlong len, jlong numPages)
|
|
||||||
{
|
{
|
||||||
jboolean loaded = JNI_TRUE;
|
jboolean loaded = JNI_TRUE;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
@ -80,8 +79,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
|
||||||
jlong len)
|
jlong len)
|
||||||
{
|
{
|
||||||
char *a = (char *)jlong_to_ptr(address);
|
char *a = (char *)jlong_to_ptr(address);
|
||||||
@ -91,9 +89,8 @@ Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
jlong len)
|
||||||
jlong len)
|
|
||||||
{
|
{
|
||||||
char *a = (char *)jlong_to_ptr(address);
|
char *a = (char *)jlong_to_ptr(address);
|
||||||
int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED);
|
int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED);
|
||||||
@ -102,8 +99,7 @@ Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||||
Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
|
||||||
jlong address, jlong len)
|
jlong address, jlong len)
|
||||||
{
|
{
|
||||||
void* a = (void *)jlong_to_ptr(address);
|
void* a = (void *)jlong_to_ptr(address);
|
||||||
@ -112,3 +108,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
|||||||
JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed");
|
JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FD "Ljava/io/FileDescriptor;"
|
||||||
|
|
||||||
|
static JNINativeMethod methods[] = {
|
||||||
|
{"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0},
|
||||||
|
{"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0},
|
||||||
|
{"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0},
|
||||||
|
{"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0},
|
||||||
|
};
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls)
|
||||||
|
{
|
||||||
|
(*env)->RegisterNatives(env, cls,
|
||||||
|
methods, sizeof(methods)/sizeof(methods[0]));
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,9 +30,8 @@
|
|||||||
#include "java_nio_MappedMemoryUtils.h"
|
#include "java_nio_MappedMemoryUtils.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
jlong len, jlong numPages)
|
||||||
jlong len, jlong numPages)
|
|
||||||
{
|
{
|
||||||
jboolean loaded = JNI_FALSE;
|
jboolean loaded = JNI_FALSE;
|
||||||
/* Information not available?
|
/* Information not available?
|
||||||
@ -43,22 +42,19 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres
|
|||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
|
||||||
jlong len)
|
jlong len)
|
||||||
{
|
{
|
||||||
// no madvise available
|
// no madvise available
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||||
Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
jlong len)
|
||||||
jlong len)
|
|
||||||
{
|
{
|
||||||
// no madvise available
|
// no madvise available
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||||
Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
|
||||||
jlong address, jlong len)
|
jlong address, jlong len)
|
||||||
{
|
{
|
||||||
void *a = (void *) jlong_to_ptr(address);
|
void *a = (void *) jlong_to_ptr(address);
|
||||||
@ -106,3 +102,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
|||||||
JNU_ThrowIOExceptionWithLastError(env, "Flush failed");
|
JNU_ThrowIOExceptionWithLastError(env, "Flush failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FD "Ljava/io/FileDescriptor;"
|
||||||
|
|
||||||
|
static JNINativeMethod methods[] = {
|
||||||
|
{"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0},
|
||||||
|
{"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0},
|
||||||
|
{"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0},
|
||||||
|
{"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0},
|
||||||
|
};
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls)
|
||||||
|
{
|
||||||
|
(*env)->RegisterNatives(env, cls,
|
||||||
|
methods, sizeof(methods)/sizeof(methods[0]));
|
||||||
|
}
|
||||||
|
142
test/jdk/java/foreign/TestMappedHandshake.java
Normal file
142
test/jdk/java/foreign/TestMappedHandshake.java
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @requires vm.flavor != "zero"
|
||||||
|
* @modules java.base/jdk.internal.vm.annotation java.base/jdk.internal.misc
|
||||||
|
* @key randomness
|
||||||
|
* @run testng/othervm TestMappedHandshake
|
||||||
|
* @run testng/othervm -Xint TestMappedHandshake
|
||||||
|
* @run testng/othervm -XX:TieredStopAtLevel=1 TestMappedHandshake
|
||||||
|
* @run testng/othervm -XX:-TieredCompilation TestMappedHandshake
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.foreign.Arena;
|
||||||
|
import java.lang.foreign.MemorySegment;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
public class TestMappedHandshake {
|
||||||
|
|
||||||
|
static final int SEGMENT_SIZE = 1_000_000;
|
||||||
|
static final int ACCESS_START_DELAY_MILLIS = 100;
|
||||||
|
static final int POST_ACCESS_DELAY_MILLIS = 1;
|
||||||
|
static final int TIMED_RUN_TIME_SECONDS = 10;
|
||||||
|
static final int MAX_EXECUTOR_WAIT_SECONDS = 20;
|
||||||
|
|
||||||
|
static final int NUM_ACCESSORS = 5;
|
||||||
|
|
||||||
|
static final Path tempPath;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
File file = File.createTempFile("buffer", "txt");
|
||||||
|
file.deleteOnExit();
|
||||||
|
tempPath = file.toPath();
|
||||||
|
Files.write(file.toPath(), new byte[SEGMENT_SIZE], StandardOpenOption.WRITE);
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new ExceptionInInitializerError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandshake() throws InterruptedException, IOException {
|
||||||
|
try (FileChannel fileChannel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE) ;
|
||||||
|
Arena arena = Arena.ofShared()) {
|
||||||
|
MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, SEGMENT_SIZE, arena);
|
||||||
|
ExecutorService accessExecutor = Executors.newFixedThreadPool(NUM_ACCESSORS + 1);
|
||||||
|
// start handshaker
|
||||||
|
accessExecutor.execute(new Handshaker());
|
||||||
|
Thread.sleep(ACCESS_START_DELAY_MILLIS);
|
||||||
|
// start accessors
|
||||||
|
for (int i = 0 ; i < NUM_ACCESSORS ; i++) {
|
||||||
|
accessExecutor.execute(new MappedSegmentAccessor(segment));
|
||||||
|
}
|
||||||
|
|
||||||
|
accessExecutor.shutdown();
|
||||||
|
assertTrue(accessExecutor.awaitTermination(MAX_EXECUTOR_WAIT_SECONDS, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class TimedAction implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
doAction();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
long elapsed = System.currentTimeMillis() - start;
|
||||||
|
if (elapsed > TIMED_RUN_TIME_SECONDS * 1000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void doAction() throws Throwable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MappedSegmentAccessor extends TimedAction {
|
||||||
|
|
||||||
|
final MemorySegment segment;
|
||||||
|
|
||||||
|
MappedSegmentAccessor(MemorySegment segment) {
|
||||||
|
this.segment = segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void doAction() throws Throwable {
|
||||||
|
segment.load();
|
||||||
|
Thread.sleep(POST_ACCESS_DELAY_MILLIS);
|
||||||
|
segment.isLoaded();
|
||||||
|
Thread.sleep(POST_ACCESS_DELAY_MILLIS);
|
||||||
|
segment.unload();
|
||||||
|
Thread.sleep(POST_ACCESS_DELAY_MILLIS);
|
||||||
|
segment.force();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Handshaker extends TimedAction {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doAction() {
|
||||||
|
Arena.ofShared().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user