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.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len, jlong numPages)
|
||||
jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len, jlong numPages)
|
||||
{
|
||||
jboolean loaded = JNI_TRUE;
|
||||
int result = 0;
|
||||
@ -93,8 +92,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||
void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
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
|
||||
Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
char *a = (char *)jlong_to_ptr(address);
|
||||
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;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||
void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||
jlong address, jlong len)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
*/
|
||||
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) {
|
||||
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
|
||||
* obtaining the lookup.
|
||||
*/
|
||||
static long findNativeInternal(ClassLoader loader, String entryName) {
|
||||
static NativeLibraries nativeLibrariesFor(ClassLoader loader) {
|
||||
if (loader == null) {
|
||||
return BootLoader.getNativeLibraries().find(entryName);
|
||||
return BootLoader.getNativeLibraries();
|
||||
} else {
|
||||
return loader.libraries.find(entryName);
|
||||
return loader.libraries;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.javac.Restricted;
|
||||
import jdk.internal.loader.NativeLibraries;
|
||||
import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder;
|
||||
import jdk.internal.misc.Blocker;
|
||||
import jdk.internal.misc.CarrierThreadLocal;
|
||||
@ -2662,8 +2663,8 @@ public final class System {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long findNative(ClassLoader loader, String entry) {
|
||||
return ClassLoader.findNativeInternal(loader, entry);
|
||||
public NativeLibraries nativeLibrariesFor(ClassLoader loader) {
|
||||
return ClassLoader.nativeLibrariesFor(loader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,6 +31,7 @@ import jdk.internal.foreign.MemorySessionImpl;
|
||||
import jdk.internal.foreign.Utils;
|
||||
import jdk.internal.javac.Restricted;
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.loader.NativeLibraries;
|
||||
import jdk.internal.loader.NativeLibrary;
|
||||
import jdk.internal.loader.RawNativeLibraries;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
@ -256,7 +257,8 @@ public interface SymbolLookup {
|
||||
if (Utils.containsNullChars(name)) return Optional.empty();
|
||||
JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
|
||||
// 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 ?
|
||||
Optional.empty() :
|
||||
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 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
|
||||
|
||||
// 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.lang.annotation.Annotation;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.SymbolLookup;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
@ -46,6 +47,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.loader.NativeLibraries;
|
||||
import jdk.internal.misc.CarrierThreadLocal;
|
||||
import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.reflect.ConstantPool;
|
||||
@ -478,7 +480,11 @@ public interface JavaLangAccess {
|
||||
|
||||
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
|
||||
|
@ -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.
|
||||
*
|
||||
* 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;
|
||||
#endif
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len, jlong numPages)
|
||||
jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len, jlong numPages)
|
||||
{
|
||||
jboolean loaded = JNI_TRUE;
|
||||
int result = 0;
|
||||
@ -80,8 +79,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||
void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
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
|
||||
Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
char *a = (char *)jlong_to_ptr(address);
|
||||
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
|
||||
Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||
void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||
jlong address, jlong len)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
#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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,9 +30,8 @@
|
||||
#include "java_nio_MappedMemoryUtils.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len, jlong numPages)
|
||||
jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len, jlong numPages)
|
||||
{
|
||||
jboolean loaded = JNI_FALSE;
|
||||
/* Information not available?
|
||||
@ -43,22 +42,19 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres
|
||||
return loaded;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||
void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
// no madvise available
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address,
|
||||
jlong len)
|
||||
{
|
||||
// no madvise available
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||
void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo,
|
||||
jlong address, jlong len)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
#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