undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
82
test/jdk/java/nio/Buffer/AllocateDirectInit.java
Normal file
82
test/jdk/java/nio/Buffer/AllocateDirectInit.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2025, 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
|
||||
* @bug 4490253 6535542 8357959
|
||||
* @key randomness
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @summary Verify that newly allocated direct buffers are initialized.
|
||||
* @run main/othervm AllocateDirectInit
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Random;
|
||||
|
||||
import jdk.test.lib.RandomFactory;
|
||||
|
||||
public class AllocateDirectInit {
|
||||
private static final int MAX_BIN_LIMIT = 16 * 1024 * 1024;
|
||||
private static final int MAX_DEC_LIMIT = 10 * 1000 * 1000;
|
||||
private static final int TRIES_PER_LIMIT = 1024;
|
||||
|
||||
private static final Random RND = RandomFactory.getRandom();
|
||||
|
||||
public static void main(String [] args){
|
||||
// Try power of two limits
|
||||
for (int limit = 1; limit < MAX_BIN_LIMIT; limit *= 2) {
|
||||
check(ByteBuffer.allocateDirect(limit - 1));
|
||||
check(ByteBuffer.allocateDirect(limit));
|
||||
check(ByteBuffer.allocateDirect(limit + 1));
|
||||
}
|
||||
|
||||
// Try power of ten limits
|
||||
for (int limit = 1; limit < MAX_DEC_LIMIT; limit *= 10) {
|
||||
check(ByteBuffer.allocateDirect(limit - 1));
|
||||
check(ByteBuffer.allocateDirect(limit));
|
||||
check(ByteBuffer.allocateDirect(limit + 1));
|
||||
}
|
||||
|
||||
// Try random sizes within power of two limits
|
||||
for (int limit = 1; limit < MAX_BIN_LIMIT; limit *= 2) {
|
||||
for (int t = 0; t < TRIES_PER_LIMIT; t++) {
|
||||
check(ByteBuffer.allocateDirect(RND.nextInt(limit)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void check(ByteBuffer bb) {
|
||||
while (bb.hasRemaining()) {
|
||||
if (bb.get() != 0) {
|
||||
int mismatchPos = bb.position();
|
||||
System.out.print("byte [");
|
||||
for (bb.position(0); bb.position() < bb.limit(); ) {
|
||||
System.out.print(" " + Integer.toHexString(bb.get() & 0xff));
|
||||
}
|
||||
System.out.println(" ]");
|
||||
throw new RuntimeException("uninitialized buffer, position = " + mismatchPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1227
test/jdk/java/nio/Buffer/Basic-X.java.template
Normal file
1227
test/jdk/java/nio/Buffer/Basic-X.java.template
Normal file
File diff suppressed because it is too large
Load diff
144
test/jdk/java/nio/Buffer/Basic.java
Normal file
144
test/jdk/java/nio/Buffer/Basic.java
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2023, 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
|
||||
* @summary Unit test for buffers
|
||||
* @bug 4413135 4414911 4416536 4416562 4418782 4471053 4472779 4490253 4523725
|
||||
* 4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 5029431
|
||||
* 5071718 6231529 6221101 6234263 6535542 6591971 6593946 6795561 7190219
|
||||
* 7199551 8065556 8149469 8230665 8237514 8306374 8306623 8306959
|
||||
* @modules java.base/java.nio:open
|
||||
* java.base/jdk.internal.misc
|
||||
* @author Mark Reinhold
|
||||
*/
|
||||
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
|
||||
public class Basic {
|
||||
|
||||
static PrintStream out = System.err;
|
||||
|
||||
static long ic(int i) {
|
||||
int j = i % 54;
|
||||
return j + 'a' + ((j > 26) ? 128 : 0);
|
||||
}
|
||||
|
||||
static String toString(Buffer b) {
|
||||
return (b.getClass().getName()
|
||||
+ "[pos=" + b.position()
|
||||
+ " lim=" + b.limit()
|
||||
+ " cap=" + b.capacity()
|
||||
+ "]");
|
||||
}
|
||||
|
||||
static void show(int level, Buffer b) {
|
||||
for (int i = 0; i < level; i++)
|
||||
out.print(" ");
|
||||
out.println(toString(b) + " " + Integer.toHexString(b.hashCode()));
|
||||
}
|
||||
|
||||
static void fail(String s) {
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
|
||||
static void fail(String s, Buffer b) {
|
||||
throw new RuntimeException(s + ": " + toString(b));
|
||||
}
|
||||
|
||||
static void fail(String s, Buffer b, Buffer b2) {
|
||||
throw new RuntimeException(s + ": "
|
||||
+ toString(b) + ", " + toString(b2));
|
||||
}
|
||||
|
||||
static void fail(Buffer b,
|
||||
String expected, char expectedChar,
|
||||
String got, char gotChar)
|
||||
{
|
||||
if (b instanceof ByteBuffer) {
|
||||
ByteBuffer bb = (ByteBuffer)b;
|
||||
int n = Math.min(16, bb.limit());
|
||||
for (int i = 0; i < n; i++)
|
||||
out.print(" " + Integer.toHexString(bb.get(i) & 0xff));
|
||||
out.println();
|
||||
}
|
||||
if (b instanceof CharBuffer) {
|
||||
CharBuffer bb = (CharBuffer)b;
|
||||
int n = Math.min(16, bb.limit());
|
||||
for (int i = 0; i < n; i++)
|
||||
out.print(" " + Integer.toHexString(bb.get(i) & 0xffff));
|
||||
out.println();
|
||||
}
|
||||
throw new RuntimeException(toString(b)
|
||||
+ ": Expected '" + expectedChar + "'=0x"
|
||||
+ expected
|
||||
+ ", got '" + gotChar + "'=0x"
|
||||
+ got);
|
||||
}
|
||||
|
||||
static void fail(Buffer b, long expected, long got) {
|
||||
fail(b,
|
||||
Long.toHexString(expected), (char)expected,
|
||||
Long.toHexString(got), (char)got);
|
||||
}
|
||||
|
||||
static void ck(Buffer b, boolean cond) {
|
||||
if (!cond)
|
||||
fail("Condition failed", b);
|
||||
}
|
||||
|
||||
static void ck(Buffer b, long got, long expected) {
|
||||
if (expected != got)
|
||||
fail(b, expected, got);
|
||||
}
|
||||
|
||||
static void ck(Buffer b, float got, float expected) {
|
||||
if (expected != got)
|
||||
fail(b,
|
||||
Float.toString(expected), (char)expected,
|
||||
Float.toString(got), (char)got);
|
||||
}
|
||||
|
||||
static void ck(Buffer b, double got, double expected) {
|
||||
if (expected != got)
|
||||
fail(b,
|
||||
Double.toString(expected), (char)expected,
|
||||
Double.toString(got), (char)got);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
BasicByte.test();
|
||||
BasicChar.test();
|
||||
BasicShort.test();
|
||||
BasicInt.test();
|
||||
BasicLong.test();
|
||||
BasicFloat.test();
|
||||
BasicDouble.test();
|
||||
}
|
||||
|
||||
}
|
||||
1227
test/jdk/java/nio/Buffer/BasicByte.java
Normal file
1227
test/jdk/java/nio/Buffer/BasicByte.java
Normal file
File diff suppressed because it is too large
Load diff
1227
test/jdk/java/nio/Buffer/BasicChar.java
Normal file
1227
test/jdk/java/nio/Buffer/BasicChar.java
Normal file
File diff suppressed because it is too large
Load diff
1227
test/jdk/java/nio/Buffer/BasicDouble.java
Normal file
1227
test/jdk/java/nio/Buffer/BasicDouble.java
Normal file
File diff suppressed because it is too large
Load diff
1227
test/jdk/java/nio/Buffer/BasicFloat.java
Normal file
1227
test/jdk/java/nio/Buffer/BasicFloat.java
Normal file
File diff suppressed because it is too large
Load diff
1227
test/jdk/java/nio/Buffer/BasicInt.java
Normal file
1227
test/jdk/java/nio/Buffer/BasicInt.java
Normal file
File diff suppressed because it is too large
Load diff
1227
test/jdk/java/nio/Buffer/BasicLong.java
Normal file
1227
test/jdk/java/nio/Buffer/BasicLong.java
Normal file
File diff suppressed because it is too large
Load diff
1227
test/jdk/java/nio/Buffer/BasicShort.java
Normal file
1227
test/jdk/java/nio/Buffer/BasicShort.java
Normal file
File diff suppressed because it is too large
Load diff
425
test/jdk/java/nio/Buffer/BulkPutBuffer.java
Normal file
425
test/jdk/java/nio/Buffer/BulkPutBuffer.java
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8219014 8245121
|
||||
* @summary Ensure that a bulk put of a buffer into another is correct.
|
||||
* @compile BulkPutBuffer.java
|
||||
* @run junit/othervm BulkPutBuffer
|
||||
*/
|
||||
public class BulkPutBuffer {
|
||||
static final long SEED = System.nanoTime();
|
||||
static final MyRandom RND = new MyRandom(SEED);
|
||||
|
||||
static final int ITERATIONS = 100;
|
||||
static final int MAX_CAPACITY = 1024;
|
||||
|
||||
static class MyRandom extends Random {
|
||||
MyRandom(long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
public byte nextByte() {
|
||||
return (byte)next(8);
|
||||
}
|
||||
|
||||
public char nextChar() {
|
||||
return (char)next(16);
|
||||
}
|
||||
|
||||
public short nextShort() {
|
||||
return (short)next(16);
|
||||
}
|
||||
}
|
||||
|
||||
enum BufferKind {
|
||||
HEAP,
|
||||
HEAP_VIEW,
|
||||
DIRECT,
|
||||
STRING;
|
||||
}
|
||||
|
||||
static final Map<Class<?>,TypeAttr> typeToAttr;
|
||||
|
||||
static record TypeAttr(Class<?> type, int bytes, String name) {}
|
||||
|
||||
static {
|
||||
typeToAttr = Map.of(
|
||||
byte.class, new TypeAttr(ByteBuffer.class, Byte.BYTES, "Byte"),
|
||||
char.class, new TypeAttr(CharBuffer.class, Character.BYTES, "Char"),
|
||||
short.class, new TypeAttr(ShortBuffer.class, Short.BYTES, "Short"),
|
||||
int.class, new TypeAttr(IntBuffer.class, Integer.BYTES, "Int"),
|
||||
float.class, new TypeAttr(FloatBuffer.class, Float.BYTES, "Float"),
|
||||
long.class, new TypeAttr(LongBuffer.class, Long.BYTES, "Long"),
|
||||
double.class, new TypeAttr(DoubleBuffer.class, Double.BYTES, "Double")
|
||||
);
|
||||
}
|
||||
|
||||
static BufferKind[] getKinds(Class<?> elementType) {
|
||||
BufferKind[] kinds;
|
||||
if (elementType == byte.class)
|
||||
kinds = new BufferKind[] {
|
||||
BufferKind.DIRECT,
|
||||
BufferKind.HEAP
|
||||
};
|
||||
else if (elementType == char.class)
|
||||
kinds = BufferKind.values();
|
||||
else
|
||||
kinds = new BufferKind[] {
|
||||
BufferKind.DIRECT,
|
||||
BufferKind.HEAP,
|
||||
BufferKind.HEAP_VIEW
|
||||
};
|
||||
return kinds;
|
||||
}
|
||||
|
||||
static ByteOrder[] getOrders(BufferKind kind, Class<?> elementType) {
|
||||
switch (kind) {
|
||||
case HEAP:
|
||||
return new ByteOrder[] { ByteOrder.nativeOrder() };
|
||||
default:
|
||||
if (elementType == byte.class)
|
||||
return new ByteOrder[] { ByteOrder.nativeOrder() };
|
||||
else
|
||||
return new ByteOrder[] { ByteOrder.BIG_ENDIAN,
|
||||
ByteOrder.LITTLE_ENDIAN };
|
||||
}
|
||||
}
|
||||
|
||||
public static class BufferProxy {
|
||||
final Class<?> elementType;
|
||||
final BufferKind kind;
|
||||
final ByteOrder order;
|
||||
|
||||
// Buffer methods
|
||||
MethodHandle alloc;
|
||||
MethodHandle allocBB;
|
||||
MethodHandle allocDirect;
|
||||
MethodHandle asReadOnlyBuffer;
|
||||
MethodHandle asTypeBuffer;
|
||||
MethodHandle putAbs;
|
||||
MethodHandle getAbs;
|
||||
MethodHandle putBufAbs;
|
||||
MethodHandle putBufRel;
|
||||
MethodHandle equals;
|
||||
|
||||
// MyRandom method
|
||||
MethodHandle nextType;
|
||||
|
||||
BufferProxy(Class<?> elementType, BufferKind kind, ByteOrder order) {
|
||||
this.elementType = elementType;
|
||||
this.kind = kind;
|
||||
this.order = order;
|
||||
|
||||
Class<?> bufferType = typeToAttr.get(elementType).type;
|
||||
|
||||
var lookup = MethodHandles.lookup();
|
||||
try {
|
||||
String name = typeToAttr.get(elementType).name;
|
||||
|
||||
alloc = lookup.findStatic(bufferType, "allocate",
|
||||
MethodType.methodType(bufferType, int.class));
|
||||
allocBB = lookup.findStatic(ByteBuffer.class, "allocate",
|
||||
MethodType.methodType(ByteBuffer.class, int.class));
|
||||
allocDirect = lookup.findStatic(ByteBuffer.class, "allocateDirect",
|
||||
MethodType.methodType(ByteBuffer.class, int.class));
|
||||
|
||||
asReadOnlyBuffer = lookup.findVirtual(bufferType,
|
||||
"asReadOnlyBuffer", MethodType.methodType(bufferType));
|
||||
if (elementType != byte.class) {
|
||||
asTypeBuffer = lookup.findVirtual(ByteBuffer.class,
|
||||
"as" + name + "Buffer", MethodType.methodType(bufferType));
|
||||
}
|
||||
|
||||
putAbs = lookup.findVirtual(bufferType, "put",
|
||||
MethodType.methodType(bufferType, int.class, elementType));
|
||||
getAbs = lookup.findVirtual(bufferType, "get",
|
||||
MethodType.methodType(elementType, int.class));
|
||||
|
||||
putBufAbs = lookup.findVirtual(bufferType, "put",
|
||||
MethodType.methodType(bufferType, int.class, bufferType,
|
||||
int.class, int.class));
|
||||
putBufRel = lookup.findVirtual(bufferType, "put",
|
||||
MethodType.methodType(bufferType, bufferType));
|
||||
|
||||
equals = lookup.findVirtual(bufferType, "equals",
|
||||
MethodType.methodType(boolean.class, Object.class));
|
||||
|
||||
nextType = lookup.findVirtual(MyRandom.class,
|
||||
"next" + name, MethodType.methodType(elementType));
|
||||
} catch (IllegalAccessException | NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
Buffer create(int capacity) throws Throwable {
|
||||
Class<?> bufferType = typeToAttr.get(elementType).type;
|
||||
if (bufferType == ByteBuffer.class || kind == BufferKind.DIRECT ||
|
||||
kind == BufferKind.HEAP_VIEW) {
|
||||
|
||||
int len = capacity*typeToAttr.get(elementType).bytes;
|
||||
ByteBuffer bb = (ByteBuffer)allocBB.invoke(len);
|
||||
byte[] bytes = new byte[len];
|
||||
RND.nextBytes(bytes);
|
||||
bb.put(0, bytes);
|
||||
if (bufferType == ByteBuffer.class) {
|
||||
return (Buffer)bb;
|
||||
} else {
|
||||
bb.order(order);
|
||||
return (Buffer)asTypeBuffer.invoke(bb);
|
||||
}
|
||||
} else if (bufferType == CharBuffer.class &&
|
||||
kind == BufferKind.STRING) {
|
||||
char[] array = new char[capacity];
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
array[i] = RND.nextChar();
|
||||
}
|
||||
return CharBuffer.wrap(new String(array));
|
||||
} else {
|
||||
Buffer buf = (Buffer)alloc.invoke(capacity);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
putAbs.invoke(buf, i, nextType.invoke(RND));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
void copy(Buffer src, int srcOff, Buffer dst, int dstOff, int length)
|
||||
throws Throwable {
|
||||
for (int i = 0; i < length; i++) {
|
||||
putAbs.invoke(dst, dstOff + i, getAbs.invoke(src, srcOff + i));
|
||||
}
|
||||
}
|
||||
|
||||
Buffer asReadOnlyBuffer(Buffer buf) throws Throwable {
|
||||
return (Buffer)asReadOnlyBuffer.invoke(buf);
|
||||
}
|
||||
|
||||
void put(Buffer src, int srcOff, Buffer dst, int dstOff, int length)
|
||||
throws Throwable {
|
||||
putBufAbs.invoke(dst, dstOff, src, srcOff, length);
|
||||
}
|
||||
|
||||
void put(Buffer src, Buffer dst) throws Throwable {
|
||||
putBufRel.invoke(dst, src);
|
||||
}
|
||||
|
||||
boolean equals(Buffer src, Buffer dst) throws Throwable {
|
||||
return Boolean.class.cast(equals.invoke(dst, src));
|
||||
}
|
||||
}
|
||||
|
||||
static List<BufferProxy> getProxies(Class<?> type) {
|
||||
List proxies = new ArrayList();
|
||||
for (BufferKind kind : getKinds(type)) {
|
||||
for (ByteOrder order : getOrders(kind, type)) {
|
||||
proxies.add(new BufferProxy(type, kind, order));
|
||||
}
|
||||
}
|
||||
return proxies;
|
||||
}
|
||||
|
||||
static Stream<BufferProxy> proxies() {
|
||||
List<BufferProxy> args = new ArrayList<BufferProxy>();
|
||||
for (Class<?> type : typeToAttr.keySet()) {
|
||||
|
||||
List<BufferProxy> proxies = getProxies(type);
|
||||
for (BufferProxy proxy : proxies) {
|
||||
args.add(proxy);
|
||||
}
|
||||
}
|
||||
return args.stream();
|
||||
}
|
||||
|
||||
static Stream<Arguments> proxyPairs() {
|
||||
List<Arguments> args = new ArrayList<Arguments>();
|
||||
for (Class<?> type : typeToAttr.keySet()) {
|
||||
List<BufferProxy> proxies = getProxies(type);
|
||||
for (BufferProxy proxy1 : proxies) {
|
||||
for (BufferProxy proxy2 : proxies) {
|
||||
args.add(Arguments.of(proxy1, proxy2));
|
||||
}
|
||||
}
|
||||
}
|
||||
return args.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("proxies")
|
||||
public void testExceptions(BufferProxy bp) throws Throwable {
|
||||
int cap = 27;
|
||||
Buffer buf = bp.create(cap);
|
||||
|
||||
assertThrows(IndexOutOfBoundsException.class,
|
||||
() -> bp.put(buf, -1, buf, 0, 1));
|
||||
assertThrows(IndexOutOfBoundsException.class,
|
||||
() -> bp.put(buf, 0, buf, -1, 1));
|
||||
assertThrows(IndexOutOfBoundsException.class,
|
||||
() -> bp.put(buf, 1, buf, 0, cap));
|
||||
assertThrows(IndexOutOfBoundsException.class,
|
||||
() -> bp.put(buf, 0, buf, 1, cap));
|
||||
assertThrows(IndexOutOfBoundsException.class,
|
||||
() -> bp.put(buf, 0, buf, 0, cap + 1));
|
||||
assertThrows(IndexOutOfBoundsException.class,
|
||||
() -> bp.put(buf, 0, buf, 0, Integer.MAX_VALUE));
|
||||
|
||||
Buffer rob = buf.isReadOnly() ? buf : bp.asReadOnlyBuffer(buf);
|
||||
assertThrows(ReadOnlyBufferException.class,
|
||||
() -> bp.put(buf, 0, rob, 0, cap));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("proxies")
|
||||
public void testSelf(BufferProxy bp) throws Throwable {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
int cap = RND.nextInt(MAX_CAPACITY);
|
||||
Buffer buf = bp.create(cap);
|
||||
|
||||
int lowerOffset = RND.nextInt(1 + cap/10);
|
||||
int lowerLength = RND.nextInt(1 + cap/2);
|
||||
if (lowerLength < 2)
|
||||
continue;
|
||||
Buffer lower = buf.slice(lowerOffset, lowerLength);
|
||||
|
||||
Buffer lowerCopy = bp.create(lowerLength);
|
||||
if (lowerCopy.isReadOnly()) {
|
||||
assertThrows(ReadOnlyBufferException.class,
|
||||
() -> bp.copy(lower, 0, lowerCopy, 0, lowerLength));
|
||||
break;
|
||||
}
|
||||
bp.copy(lower, 0, lowerCopy, 0, lowerLength);
|
||||
|
||||
int middleOffset = RND.nextInt(1 + cap/2);
|
||||
Buffer middle = buf.slice(middleOffset, lowerLength);
|
||||
Buffer middleCopy = bp.create(lowerLength);
|
||||
bp.copy(middle, 0, middleCopy, 0, lowerLength);
|
||||
|
||||
bp.put(lower, middle);
|
||||
middle.flip();
|
||||
|
||||
assertTrue(bp.equals(lowerCopy, middle),
|
||||
String.format("%d %s %d %d %d %d%n", SEED,
|
||||
buf.getClass().getName(), cap,
|
||||
lowerOffset, lowerLength, middleOffset));
|
||||
|
||||
bp.copy(lowerCopy, 0, buf, lowerOffset, lowerLength);
|
||||
bp.copy(middleCopy, 0, buf, middleOffset, lowerLength);
|
||||
|
||||
bp.put(buf, lowerOffset, buf, middleOffset, lowerLength);
|
||||
|
||||
assertTrue(bp.equals(lowerCopy, middle),
|
||||
String.format("%d %s %d %d %d %d%n", SEED,
|
||||
buf.getClass().getName(), cap,
|
||||
lowerOffset, lowerLength, middleOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("proxyPairs")
|
||||
public void testPairs(BufferProxy bp, BufferProxy sbp) throws Throwable {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
int cap = Math.max(4, RND.nextInt(MAX_CAPACITY));
|
||||
int cap2 = cap/2;
|
||||
Buffer buf = bp.create(cap);
|
||||
|
||||
int pos = RND.nextInt(Math.max(1, cap2));
|
||||
buf.position(pos);
|
||||
buf.mark();
|
||||
int lim = pos + Math.max(1, cap - pos);
|
||||
buf.limit(lim);
|
||||
|
||||
int scap = Math.max(buf.remaining(), RND.nextInt(1024));
|
||||
Buffer src = sbp.create(scap);
|
||||
|
||||
int diff = scap - buf.remaining();
|
||||
int spos = diff > 0 ? RND.nextInt(diff) : 0;
|
||||
src.position(spos);
|
||||
src.mark();
|
||||
int slim = spos + buf.remaining();
|
||||
src.limit(slim);
|
||||
|
||||
if (buf.isReadOnly()) {
|
||||
assertThrows(ReadOnlyBufferException.class,
|
||||
() -> bp.put(src, buf));
|
||||
break;
|
||||
}
|
||||
|
||||
Buffer backup = bp.create(slim - spos);
|
||||
bp.copy(buf, pos, backup, 0, backup.capacity());
|
||||
bp.put(src, buf);
|
||||
|
||||
buf.reset();
|
||||
src.reset();
|
||||
|
||||
assertTrue(bp.equals(src, buf),
|
||||
String.format("%d %s %d %d %d %s %d %d %d%n", SEED,
|
||||
buf.getClass().getName(), cap, pos, lim,
|
||||
src.getClass().getName(), scap, spos, slim));
|
||||
|
||||
src.clear();
|
||||
buf.clear();
|
||||
bp.copy(backup, 0, buf, pos, backup.capacity());
|
||||
bp.put(src, spos, buf, pos, backup.capacity());
|
||||
src.position(spos);
|
||||
src.limit(slim);
|
||||
buf.position(pos);
|
||||
buf.limit(lim);
|
||||
|
||||
assertTrue(bp.equals(src, buf),
|
||||
String.format("%d %s %d %d %d %s %d %d %d%n", SEED,
|
||||
buf.getClass().getName(), cap, pos, lim,
|
||||
src.getClass().getName(), scap, spos, slim));
|
||||
}
|
||||
}
|
||||
}
|
||||
791
test/jdk/java/nio/Buffer/ByteBufferViews.java
Normal file
791
test/jdk/java/nio/Buffer/ByteBufferViews.java
Normal file
|
|
@ -0,0 +1,791 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2026, 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
|
||||
* @summary Binary data and view tests for byte buffers
|
||||
* @bug 8159257 8258955
|
||||
* @run junit ByteBufferViews
|
||||
*/
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.IntUnaryOperator;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junit.jupiter.api.TestInstance.Lifecycle;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class ByteBufferViews {
|
||||
static final int SIZE = 32;
|
||||
|
||||
// List of buffer allocator functions
|
||||
static final List<Map.Entry<String, IntFunction<ByteBuffer>>> BYTE_BUFFER_ALLOCATE_FUNCTIONS = List.of(
|
||||
// Heap
|
||||
Map.entry("ByteBuffer.allocate(ba)",
|
||||
size -> ByteBuffer.allocate(size)),
|
||||
// Aligned
|
||||
Map.entry("ByteBuffer.allocate(size).position(8)",
|
||||
size -> ByteBuffer.allocate(size).position(8)),
|
||||
Map.entry("ByteBuffer.allocate(size).position(8).slice()",
|
||||
size -> ByteBuffer.allocate(size).position(8).slice()),
|
||||
Map.entry("ByteBuffer.allocate(size).position(8).slice().duplicate()",
|
||||
size -> ByteBuffer.allocate(size).position(8).slice().duplicate()),
|
||||
Map.entry("ByteBuffer.allocate(size).slice(8,size-8)",
|
||||
size -> ByteBuffer.allocate(size).slice(8,size-8)),
|
||||
// Unaligned
|
||||
Map.entry("ByteBuffer.allocate(size).position(1)",
|
||||
size -> ByteBuffer.allocate(size).position(1)),
|
||||
Map.entry("ByteBuffer.allocate(size).position(1).slice()",
|
||||
size -> ByteBuffer.allocate(size).position(1).slice()),
|
||||
Map.entry("ByteBuffer.allocate(size).position(1).slice().duplicate()",
|
||||
size -> ByteBuffer.allocate(size).position(1).slice().duplicate()),
|
||||
Map.entry("ByteBuffer.allocate(size).slice(1,size-1)",
|
||||
size -> ByteBuffer.allocate(size).slice(1,size-1)),
|
||||
|
||||
// Off-heap
|
||||
Map.entry("ByteBuffer.allocateDirect(size)",
|
||||
size -> ByteBuffer.allocateDirect(size)),
|
||||
// Aligned
|
||||
Map.entry("ByteBuffer.allocateDirect(size).position(8)",
|
||||
size -> ByteBuffer.allocateDirect(size).position(8)),
|
||||
Map.entry("ByteBuffer.allocateDirect(size).position(8).slice()",
|
||||
size -> ByteBuffer.allocateDirect(size).position(8).slice()),
|
||||
Map.entry("ByteBuffer.allocateDirect(size).position(8).slice().duplicate()",
|
||||
size -> ByteBuffer.allocateDirect(size).position(8).slice().duplicate()),
|
||||
Map.entry("ByteBuffer.allocateDirect(size).slice(8,size-8)",
|
||||
size -> ByteBuffer.allocateDirect(size).slice(8,size-8)),
|
||||
// Unaligned
|
||||
Map.entry("ByteBuffer.allocateDirect(size).position(1)",
|
||||
size -> ByteBuffer.allocateDirect(size).position(1)),
|
||||
Map.entry("ByteBuffer.allocateDirect(size).position(1).slice()",
|
||||
size -> ByteBuffer.allocateDirect(size).position(1).slice()),
|
||||
Map.entry("ByteBuffer.allocateDirect(size).position(1).slice().duplicate()",
|
||||
size -> ByteBuffer.allocateDirect(size).position(1).slice().duplicate()),
|
||||
Map.entry("ByteBuffer.allocateDirect(size).slice(1,size-1)",
|
||||
size -> ByteBuffer.allocateDirect(size).slice(1,size-1))
|
||||
);
|
||||
|
||||
// List of buffer byte order functions
|
||||
static final List<Map.Entry<String, UnaryOperator<ByteBuffer>>> BYTE_BUFFER_ORDER_FUNCTIONS = List.of(
|
||||
Map.entry("order(ByteOrder.BIG_ENDIAN)",
|
||||
(ByteBuffer bb) -> bb.order(ByteOrder.BIG_ENDIAN)),
|
||||
Map.entry("order(ByteOrder.LITTLE_ENDIAN)",
|
||||
(ByteBuffer bb) -> bb.order(ByteOrder.LITTLE_ENDIAN))
|
||||
);
|
||||
|
||||
// Produce a composition of allocation and byte order buffer functions
|
||||
static List<Map.Entry<String, IntFunction<ByteBuffer>>> composeBufferFunctions(
|
||||
List<Map.Entry<String, IntFunction<ByteBuffer>>> af,
|
||||
List<Map.Entry<String, UnaryOperator<ByteBuffer>>> of) {
|
||||
return af.stream().flatMap(afe -> of.stream().
|
||||
map(ofe -> {
|
||||
String s = afe.getKey() + "." + ofe.getKey();
|
||||
IntFunction<ByteBuffer> f = size -> ofe.getValue().
|
||||
apply(afe.getValue().apply(size));
|
||||
return Map.entry(s, f);
|
||||
})
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// List of buffer allocator functions to test
|
||||
static final List<Map.Entry<String, IntFunction<ByteBuffer>>> BYTE_BUFFER_FUNCTIONS =
|
||||
composeBufferFunctions(BYTE_BUFFER_ALLOCATE_FUNCTIONS, BYTE_BUFFER_ORDER_FUNCTIONS);
|
||||
|
||||
// Creates a cross product of test arguments for
|
||||
// buffer allocator functions and buffer view functions
|
||||
static Stream<Arguments> product(List<? extends Map.Entry<String, ?>> la,
|
||||
List<? extends Map.Entry<String, ?>> lb) {
|
||||
return la.stream().flatMap(lae -> lb.stream().
|
||||
map(lbe -> Arguments.of
|
||||
(
|
||||
lae.getKey() + " -> " + lbe.getKey(),
|
||||
lae.getValue(),
|
||||
lbe.getValue())
|
||||
));
|
||||
}
|
||||
|
||||
static void assertValues(int i, Object bValue, Object bbValue, ByteBuffer bb) {
|
||||
if (!bValue.equals(bbValue)) {
|
||||
fail(String.format("Values %s and %s differ at index %d for %s",
|
||||
bValue, bbValue, i, bb));
|
||||
}
|
||||
}
|
||||
|
||||
static void assertValues(int i, Object bbValue, Object bvValue, ByteBuffer bb, Buffer bv) {
|
||||
if (!bbValue.equals(bvValue)) {
|
||||
fail(String.format("Values %s and %s differ at index %d for %s and %s",
|
||||
bbValue, bvValue, i, bb, bv));
|
||||
}
|
||||
}
|
||||
|
||||
static ByteBuffer allocate(IntFunction<ByteBuffer> f) {
|
||||
return allocate(f, i -> i);
|
||||
}
|
||||
|
||||
static ByteBuffer allocate(IntFunction<ByteBuffer> f, IntUnaryOperator o) {
|
||||
return fill(f.apply(SIZE), o);
|
||||
}
|
||||
|
||||
static ByteBuffer fill(ByteBuffer bb, IntUnaryOperator o) {
|
||||
for (int i = 0; i < bb.limit(); i++) {
|
||||
bb.put(i, (byte) o.applyAsInt(i));
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
public static Stream<Arguments> shortBufferViews() {
|
||||
List<Map.Entry<String, Function<ByteBuffer, ShortBuffer>>> bfs = List.of(
|
||||
Map.entry("bb.asShortBuffer()",
|
||||
bb -> bb.asShortBuffer()),
|
||||
Map.entry("bb.asShortBuffer().slice()",
|
||||
bb -> bb.asShortBuffer().slice()),
|
||||
Map.entry("bb.asShortBuffer().slice(index,length)",
|
||||
bb -> { var sb = bb.asShortBuffer();
|
||||
sb = sb.slice(1, sb.limit() - 1);
|
||||
bb.position(bb.position() + 2);
|
||||
return sb; }),
|
||||
Map.entry("bb.asShortBuffer().slice().duplicate()",
|
||||
bb -> bb.asShortBuffer().slice().duplicate())
|
||||
);
|
||||
|
||||
return product(BYTE_BUFFER_FUNCTIONS, bfs);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("shortBufferViews")
|
||||
public void testShortGet(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, ShortBuffer> fbi) {
|
||||
ByteBuffer bb = allocate(fbb);
|
||||
ShortBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
short fromBytes = getShortFromBytes(bb, o + i * 2);
|
||||
short fromMethodView = bb.getShort(o + i * 2);
|
||||
assertValues(i, fromBytes, fromMethodView, bb);
|
||||
|
||||
short fromBufferView = vb.get(i);
|
||||
assertValues(i, fromMethodView, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
short v = getShortFromBytes(bb, o + i * 2);
|
||||
short a = bb.getShort();
|
||||
assertValues(i, v, a, bb);
|
||||
|
||||
short b = vb.get();
|
||||
assertValues(i, a, b, bb, vb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("shortBufferViews")
|
||||
public void testShortPut(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, ShortBuffer> fbi) {
|
||||
ByteBuffer bbfilled = allocate(fbb);
|
||||
ByteBuffer bb = allocate(fbb, i -> 0);
|
||||
ShortBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
short fromFilled = bbfilled.getShort(o + i * 2);
|
||||
|
||||
vb.put(i, fromFilled);
|
||||
short fromMethodView = bb.getShort(o + i * 2);
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
short fromFilled = bbfilled.getShort(o + i * 2);
|
||||
|
||||
vb.put(fromFilled);
|
||||
short fromMethodView = bb.getShort();
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
|
||||
fill(bb, i -> 0);
|
||||
bb.clear().position(o);
|
||||
vb.clear();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
short fromFilled = bbfilled.getShort(o + i * 2);
|
||||
|
||||
bb.putShort(o + i * 2, fromFilled);
|
||||
short fromBufferView = vb.get(i);
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
short fromFilled = bbfilled.getShort(o + i * 2);
|
||||
|
||||
bb.putShort(fromFilled);
|
||||
short fromBufferView = vb.get();
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
}
|
||||
|
||||
static short getShortFromBytes(ByteBuffer bb, int i) {
|
||||
int a = bb.get(i) & 0xFF;
|
||||
int b = bb.get(i + 1) & 0xFF;
|
||||
|
||||
if (bb.order() == ByteOrder.BIG_ENDIAN) {
|
||||
return (short) ((a << 8) | b);
|
||||
}
|
||||
else {
|
||||
return (short) ((b << 8) | a);
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<Arguments> charBufferViews() {
|
||||
List<Map.Entry<String, Function<ByteBuffer, CharBuffer>>> bfs = List.of(
|
||||
Map.entry("bb.asCharBuffer()",
|
||||
bb -> bb.asCharBuffer()),
|
||||
Map.entry("bb.asCharBuffer().slice()",
|
||||
bb -> bb.asCharBuffer().slice()),
|
||||
Map.entry("bb.asCharBuffer().slice(index,length)",
|
||||
bb -> { var cb = bb.asCharBuffer();
|
||||
cb = cb.slice(1, cb.limit() - 1);
|
||||
bb.position(bb.position() + 2);
|
||||
return cb; }),
|
||||
Map.entry("bb.asCharBuffer().slice().duplicate()",
|
||||
bb -> bb.asCharBuffer().slice().duplicate())
|
||||
);
|
||||
|
||||
return product(BYTE_BUFFER_FUNCTIONS, bfs);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("charBufferViews")
|
||||
public void testCharGet(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, CharBuffer> fbi) {
|
||||
ByteBuffer bb = allocate(fbb);
|
||||
CharBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
char fromBytes = getCharFromBytes(bb, o + i * 2);
|
||||
char fromMethodView = bb.getChar(o + i * 2);
|
||||
assertValues(i, fromBytes, fromMethodView, bb);
|
||||
|
||||
char fromBufferView = vb.get(i);
|
||||
assertValues(i, fromMethodView, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
char fromBytes = getCharFromBytes(bb, o + i * 2);
|
||||
char fromMethodView = bb.getChar();
|
||||
assertValues(i, fromBytes, fromMethodView, bb);
|
||||
|
||||
char fromBufferView = vb.get();
|
||||
assertValues(i, fromMethodView, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("charBufferViews")
|
||||
public void testCharPut(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, CharBuffer> fbi) {
|
||||
ByteBuffer bbfilled = allocate(fbb);
|
||||
ByteBuffer bb = allocate(fbb, i -> 0);
|
||||
CharBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
char fromFilled = bbfilled.getChar(o + i * 2);
|
||||
|
||||
vb.put(i, fromFilled);
|
||||
char fromMethodView = bb.getChar(o + i * 2);
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
char fromFilled = bbfilled.getChar(o + i * 2);
|
||||
|
||||
vb.put(fromFilled);
|
||||
char fromMethodView = bb.getChar();
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
|
||||
fill(bb, i -> 0);
|
||||
bb.clear().position(o);
|
||||
vb.clear();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
char fromFilled = bbfilled.getChar(o + i * 2);
|
||||
|
||||
bb.putChar(o + i * 2, fromFilled);
|
||||
char fromBufferView = vb.get(i);
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
char fromFilled = bbfilled.getChar(o + i * 2);
|
||||
|
||||
bb.putChar(fromFilled);
|
||||
char fromBufferView = vb.get();
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
}
|
||||
|
||||
static char getCharFromBytes(ByteBuffer bb, int i) {
|
||||
return (char) getShortFromBytes(bb, i);
|
||||
}
|
||||
|
||||
|
||||
public static Stream<Arguments> intBufferViews() {
|
||||
List<Map.Entry<String, Function<ByteBuffer, IntBuffer>>> bfs = List.of(
|
||||
Map.entry("bb.asIntBuffer()",
|
||||
bb -> bb.asIntBuffer()),
|
||||
Map.entry("bb.asIntBuffer().slice()",
|
||||
bb -> bb.asIntBuffer().slice()),
|
||||
Map.entry("bb.asIntBuffer().slice(index,length)",
|
||||
bb -> { var ib = bb.asIntBuffer();
|
||||
ib = ib.slice(1, ib.limit() - 1);
|
||||
bb.position(bb.position() + 4);
|
||||
return ib; }),
|
||||
Map.entry("bb.asIntBuffer().slice().duplicate()",
|
||||
bb -> bb.asIntBuffer().slice().duplicate())
|
||||
);
|
||||
|
||||
return product(BYTE_BUFFER_FUNCTIONS, bfs);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("intBufferViews")
|
||||
public void testIntGet(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, IntBuffer> fbi) {
|
||||
ByteBuffer bb = allocate(fbb);
|
||||
IntBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
int fromBytes = getIntFromBytes(bb, o + i * 4);
|
||||
int fromMethodView = bb.getInt(o + i * 4);
|
||||
assertValues(i, fromBytes, fromMethodView, bb);
|
||||
|
||||
int fromBufferView = vb.get(i);
|
||||
assertValues(i, fromMethodView, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
int v = getIntFromBytes(bb, o + i * 4);
|
||||
int a = bb.getInt();
|
||||
assertValues(i, v, a, bb);
|
||||
|
||||
int b = vb.get();
|
||||
assertValues(i, a, b, bb, vb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("intBufferViews")
|
||||
public void testIntPut(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, IntBuffer> fbi) {
|
||||
ByteBuffer bbfilled = allocate(fbb);
|
||||
ByteBuffer bb = allocate(fbb, i -> 0);
|
||||
IntBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
int fromFilled = bbfilled.getInt(o + i * 4);
|
||||
|
||||
vb.put(i, fromFilled);
|
||||
int fromMethodView = bb.getInt(o + i * 4);
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
int fromFilled = bbfilled.getInt(o + i * 4);
|
||||
|
||||
vb.put(fromFilled);
|
||||
int fromMethodView = bb.getInt();
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
|
||||
fill(bb, i -> 0);
|
||||
bb.clear().position(o);
|
||||
vb.clear();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
int fromFilled = bbfilled.getInt(o + i * 4);
|
||||
|
||||
bb.putInt(o + i * 4, fromFilled);
|
||||
int fromBufferView = vb.get(i);
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
int fromFilled = bbfilled.getInt(o + i * 4);
|
||||
|
||||
bb.putInt(fromFilled);
|
||||
int fromBufferView = vb.get();
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
}
|
||||
|
||||
static int getIntFromBytes(ByteBuffer bb, int i) {
|
||||
int a = bb.get(i) & 0xFF;
|
||||
int b = bb.get(i + 1) & 0xFF;
|
||||
int c = bb.get(i + 2) & 0xFF;
|
||||
int d = bb.get(i + 3) & 0xFF;
|
||||
|
||||
if (bb.order() == ByteOrder.BIG_ENDIAN) {
|
||||
return ((a << 24) | (b << 16) | (c << 8) | d);
|
||||
}
|
||||
else {
|
||||
return ((d << 24) | (c << 16) | (b << 8) | a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Stream<Arguments> longBufferViews() {
|
||||
List<Map.Entry<String, Function<ByteBuffer, LongBuffer>>> bfs = List.of(
|
||||
Map.entry("bb.asLongBuffer()",
|
||||
bb -> bb.asLongBuffer()),
|
||||
Map.entry("bb.asLongBuffer().slice()",
|
||||
bb -> bb.asLongBuffer().slice()),
|
||||
Map.entry("bb.asLongBuffer().slice(index,length)",
|
||||
bb -> { var lb = bb.asLongBuffer();
|
||||
lb = lb.slice(1, lb.limit() - 1);
|
||||
bb.position(bb.position() + 8);
|
||||
return lb; }),
|
||||
Map.entry("bb.asLongBuffer().slice().duplicate()",
|
||||
bb -> bb.asLongBuffer().slice().duplicate())
|
||||
);
|
||||
|
||||
return product(BYTE_BUFFER_FUNCTIONS, bfs);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("longBufferViews")
|
||||
public void testLongGet(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, LongBuffer> fbi) {
|
||||
ByteBuffer bb = allocate(fbb);
|
||||
LongBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
long fromBytes = getLongFromBytes(bb, o + i * 8);
|
||||
long fromMethodView = bb.getLong(o + i * 8);
|
||||
assertValues(i, fromBytes, fromMethodView, bb);
|
||||
|
||||
long fromBufferView = vb.get(i);
|
||||
assertValues(i, fromMethodView, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
long v = getLongFromBytes(bb, o + i * 8);
|
||||
long a = bb.getLong();
|
||||
assertValues(i, v, a, bb);
|
||||
|
||||
long b = vb.get();
|
||||
assertValues(i, a, b, bb, vb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("longBufferViews")
|
||||
public void testLongPut(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, LongBuffer> fbi) {
|
||||
ByteBuffer bbfilled = allocate(fbb);
|
||||
ByteBuffer bb = allocate(fbb, i -> 0);
|
||||
LongBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
long fromFilled = bbfilled.getLong(o + i * 8);
|
||||
|
||||
vb.put(i, fromFilled);
|
||||
long fromMethodView = bb.getLong(o + i * 8);
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
long fromFilled = bbfilled.getLong(o + i * 8);
|
||||
|
||||
vb.put(fromFilled);
|
||||
long fromMethodView = bb.getLong();
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
|
||||
fill(bb, i -> 0);
|
||||
bb.clear().position(o);
|
||||
vb.clear();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
long fromFilled = bbfilled.getLong(o + i * 8);
|
||||
|
||||
bb.putLong(o + i * 8, fromFilled);
|
||||
long fromBufferView = vb.get(i);
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
long fromFilled = bbfilled.getLong(o + i * 8);
|
||||
|
||||
bb.putLong(fromFilled);
|
||||
long fromBufferView = vb.get();
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
}
|
||||
|
||||
static long getLongFromBytes(ByteBuffer bb, int i) {
|
||||
long a = bb.get(i) & 0xFF;
|
||||
long b = bb.get(i + 1) & 0xFF;
|
||||
long c = bb.get(i + 2) & 0xFF;
|
||||
long d = bb.get(i + 3) & 0xFF;
|
||||
long e = bb.get(i + 4) & 0xFF;
|
||||
long f = bb.get(i + 5) & 0xFF;
|
||||
long g = bb.get(i + 6) & 0xFF;
|
||||
long h = bb.get(i + 7) & 0xFF;
|
||||
|
||||
if (bb.order() == ByteOrder.BIG_ENDIAN) {
|
||||
return ((a << 56) | (b << 48) | (c << 40) | (d << 32) |
|
||||
(e << 24) | (f << 16) | (g << 8) | h);
|
||||
}
|
||||
else {
|
||||
return ((h << 56) | (g << 48) | (f << 40) | (e << 32) |
|
||||
(d << 24) | (c << 16) | (b << 8) | a);
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<Arguments> floatBufferViews() {
|
||||
List<Map.Entry<String, Function<ByteBuffer, FloatBuffer>>> bfs = List.of(
|
||||
Map.entry("bb.asFloatBuffer()",
|
||||
bb -> bb.asFloatBuffer()),
|
||||
Map.entry("bb.asFloatBuffer().slice()",
|
||||
bb -> bb.asFloatBuffer().slice()),
|
||||
Map.entry("bb.asFloatBuffer().slice(index,length)",
|
||||
bb -> { var fb = bb.asFloatBuffer();
|
||||
fb = fb.slice(1, fb.limit() - 1);
|
||||
bb.position(bb.position() + 4);
|
||||
return fb; }),
|
||||
Map.entry("bb.asFloatBuffer().slice().duplicate()",
|
||||
bb -> bb.asFloatBuffer().slice().duplicate())
|
||||
);
|
||||
|
||||
return product(BYTE_BUFFER_FUNCTIONS, bfs);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("floatBufferViews")
|
||||
public void testFloatGet(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, FloatBuffer> fbi) {
|
||||
ByteBuffer bb = allocate(fbb);
|
||||
FloatBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
float fromBytes = getFloatFromBytes(bb, o + i * 4);
|
||||
float fromMethodView = bb.getFloat(o + i * 4);
|
||||
assertValues(i, fromBytes, fromMethodView, bb);
|
||||
|
||||
float fromBufferView = vb.get(i);
|
||||
assertValues(i, fromMethodView, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
float v = getFloatFromBytes(bb, o + i * 4);
|
||||
float a = bb.getFloat();
|
||||
assertValues(i, v, a, bb);
|
||||
|
||||
float b = vb.get();
|
||||
assertValues(i, a, b, bb, vb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("floatBufferViews")
|
||||
public void testFloatPut(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, FloatBuffer> fbi) {
|
||||
ByteBuffer bbfilled = allocate(fbb);
|
||||
ByteBuffer bb = allocate(fbb, i -> 0);
|
||||
FloatBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
float fromFilled = bbfilled.getFloat(o + i * 4);
|
||||
|
||||
vb.put(i, fromFilled);
|
||||
float fromMethodView = bb.getFloat(o + i * 4);
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
float fromFilled = bbfilled.getFloat(o + i * 4);
|
||||
|
||||
vb.put(fromFilled);
|
||||
float fromMethodView = bb.getFloat();
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
|
||||
fill(bb, i -> 0);
|
||||
bb.clear().position(o);
|
||||
vb.clear();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
float fromFilled = bbfilled.getFloat(o + i * 4);
|
||||
|
||||
bb.putFloat(o + i * 4, fromFilled);
|
||||
float fromBufferView = vb.get(i);
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
float fromFilled = bbfilled.getFloat(o + i * 4);
|
||||
|
||||
bb.putFloat(fromFilled);
|
||||
float fromBufferView = vb.get();
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
}
|
||||
|
||||
static float getFloatFromBytes(ByteBuffer bb, int i) {
|
||||
return Float.intBitsToFloat(getIntFromBytes(bb, i));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> doubleBufferViews() {
|
||||
List<Map.Entry<String, Function<ByteBuffer, DoubleBuffer>>> bfs = List.of(
|
||||
Map.entry("bb.asDoubleBuffer()",
|
||||
bb -> bb.asDoubleBuffer()),
|
||||
Map.entry("bb.asDoubleBuffer().slice()",
|
||||
bb -> bb.asDoubleBuffer().slice()),
|
||||
Map.entry("bb.asDoubleBuffer().slice(index,length)",
|
||||
bb -> { var db = bb.asDoubleBuffer();
|
||||
db = db.slice(1, db.limit() - 1);
|
||||
bb.position(bb.position() + 8);
|
||||
return db; }),
|
||||
Map.entry("bb.asDoubleBuffer().slice().duplicate()",
|
||||
bb -> bb.asDoubleBuffer().slice().duplicate())
|
||||
);
|
||||
|
||||
return product(BYTE_BUFFER_FUNCTIONS, bfs);
|
||||
}
|
||||
|
||||
@MethodSource("doubleBufferViews")
|
||||
public void testDoubleGet(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, DoubleBuffer> fbi) {
|
||||
ByteBuffer bb = allocate(fbb);
|
||||
DoubleBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
double fromBytes = getDoubleFromBytes(bb, o + i * 8);
|
||||
double fromMethodView = bb.getDouble(o + i * 8);
|
||||
assertValues(i, fromBytes, fromMethodView, bb);
|
||||
|
||||
double fromBufferView = vb.get(i);
|
||||
assertValues(i, fromMethodView, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
double v = getDoubleFromBytes(bb, o + i * 8);
|
||||
double a = bb.getDouble();
|
||||
assertValues(i, v, a, bb);
|
||||
|
||||
double b = vb.get();
|
||||
assertValues(i, a, b, bb, vb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("doubleBufferViews")
|
||||
public void testDoublePut(String desc, IntFunction<ByteBuffer> fbb,
|
||||
Function<ByteBuffer, DoubleBuffer> fbi) {
|
||||
ByteBuffer bbfilled = allocate(fbb);
|
||||
ByteBuffer bb = allocate(fbb, i -> 0);
|
||||
DoubleBuffer vb = fbi.apply(bb);
|
||||
int o = bb.position();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
double fromFilled = bbfilled.getDouble(o + i * 8);
|
||||
|
||||
vb.put(i, fromFilled);
|
||||
double fromMethodView = bb.getDouble(o + i * 8);
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
double fromFilled = bbfilled.getDouble(o + i * 8);
|
||||
|
||||
vb.put(fromFilled);
|
||||
double fromMethodView = bb.getDouble();
|
||||
assertValues(i, fromFilled, fromMethodView, bb, vb);
|
||||
}
|
||||
|
||||
|
||||
fill(bb, i -> 0);
|
||||
bb.clear().position(o);
|
||||
vb.clear();
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
double fromFilled = bbfilled.getDouble(o + i * 8);
|
||||
|
||||
bb.putDouble(o + i * 8, fromFilled);
|
||||
double fromBufferView = vb.get(i);
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
|
||||
for (int i = 0; i < vb.limit(); i++) {
|
||||
double fromFilled = bbfilled.getDouble(o + i * 8);
|
||||
|
||||
bb.putDouble(fromFilled);
|
||||
double fromBufferView = vb.get();
|
||||
assertValues(i, fromFilled, fromBufferView, bb, vb);
|
||||
}
|
||||
}
|
||||
|
||||
static double getDoubleFromBytes(ByteBuffer bb, int i) {
|
||||
return Double.longBitsToDouble(getLongFromBytes(bb, i));
|
||||
}
|
||||
}
|
||||
38
test/jdk/java/nio/Buffer/CharAt.java
Normal file
38
test/jdk/java/nio/Buffer/CharAt.java
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 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
|
||||
* @summary Test charAt index checking
|
||||
* @bug 4510323
|
||||
*/
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CharAt {
|
||||
public static void main (String[] args) {
|
||||
CharSequence cs = CharBuffer.wrap("foo");
|
||||
for (int i = 0; i < cs.length(); i++)
|
||||
System.err.print(cs.charAt(i));
|
||||
System.err.println();
|
||||
}
|
||||
}
|
||||
326
test/jdk/java/nio/Buffer/CharBufferAsCharSequenceTest.java
Normal file
326
test/jdk/java/nio/Buffer/CharBufferAsCharSequenceTest.java
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.PrimitiveIterator.OfInt;
|
||||
import java.util.Random;
|
||||
|
||||
import jdk.test.lib.RandomFactory;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8343110 8361299 8364345
|
||||
* @key randomness
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @summary Tests CharBuffer implementations of CharSequence
|
||||
* @run junit CharBufferAsCharSequenceTest
|
||||
*/
|
||||
public class CharBufferAsCharSequenceTest {
|
||||
|
||||
private static final Random RAND = RandomFactory.getRandom();
|
||||
private static final int SIZE = RAND.nextInt(128, 1153);
|
||||
|
||||
private static char[] randomChars() {
|
||||
char[] chars = new char[SIZE];
|
||||
for (int i=0; i<SIZE; ++i) {
|
||||
chars[i] = (char) RAND.nextInt();
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly adjusts the position and limit such that the position will be in the
|
||||
* first 1/4th and the limit in the last half.
|
||||
*/
|
||||
private static CharBuffer randomizeRange(CharBuffer cb) {
|
||||
int mid = cb.capacity() >>> 1;
|
||||
int start = RAND.nextInt(mid >> 1); // from 0 to 1/4
|
||||
int end = RAND.nextInt(mid + 1, cb.capacity()); // from mid to capacity
|
||||
cb.position(start);
|
||||
cb.limit(end);
|
||||
return cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random content to use for populating <i>cb</i> then calling through
|
||||
* to {@code addCases(String, char[], CharBuffer, List)}
|
||||
*
|
||||
* @param type String description of the type of CharBuffer under test.
|
||||
* @param cb CharBuffer instance to populate as base of creating cases.
|
||||
* @param cases The {@code List} to populate with the cases for use from
|
||||
* {@link #charBufferArguments()}.
|
||||
*/
|
||||
private static void populateAndAddCases(String type, CharBuffer cb, List<Arguments> cases) {
|
||||
assert cb.position() == 0 && cb.limit() == cb.capacity();
|
||||
char[] buf = randomChars();
|
||||
cb.put(buf);
|
||||
cb.clear();
|
||||
addCases(type, buf, cb, cases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds 4 cases to <i>cases</i>.
|
||||
* <ul>
|
||||
* <li>Full use of cb</li>.
|
||||
* <li>A duplicate of <i>cb</i> with a randomized position and limit. See
|
||||
* {@code randomizeRange(CharBuffer)}
|
||||
* <li>
|
||||
* <li>A {@link CharBuffer#slice() sliced} copy of randomized range.</li>
|
||||
* <li>A {@link CharBuffer#slice() sliced} copy of randomized range with a
|
||||
* randomized position and limit.</li>
|
||||
* </ul>
|
||||
*/
|
||||
private static void addCases(String type, char[] buf, CharBuffer cb, List<Arguments> cases) {
|
||||
assert cb.position() == 0 && cb.limit() == cb.capacity();
|
||||
cases.add(Arguments.of(cb, buf, 0, buf.length, type + " full"));
|
||||
|
||||
CharBuffer rndRange = randomizeRange(cb.duplicate());
|
||||
cases.add(Arguments.of(rndRange, buf, rndRange.position(), rndRange.limit(),
|
||||
type + " at " + rndRange.position() + " through " + rndRange.limit()));
|
||||
cases.add(Arguments.of(rndRange.slice(), buf, rndRange.position(), rndRange.limit(),
|
||||
type + " sliced at " + rndRange.position() + " through " + rndRange.limit()));
|
||||
|
||||
CharBuffer rndSlicedRange = randomizeRange(rndRange.slice());
|
||||
cases.add(Arguments.of(rndSlicedRange,
|
||||
buf,
|
||||
rndRange.position() + rndSlicedRange.position(),
|
||||
rndRange.position() + rndSlicedRange.limit(),
|
||||
type + " sliced at " + rndRange.position() + " with position " +
|
||||
rndSlicedRange.position() + " and limit " + rndSlicedRange.limit()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code List} of {@link Arguments}, with each entry representing a
|
||||
* test case scenario.
|
||||
* <ul>
|
||||
* <li>CharBuffer - the instance to be tested</li>
|
||||
* <li>char[] - the data expected to be backing the current state of the CharBuffer</li>
|
||||
* <li>int start - index (inclusive) into char[] where the CharBuffer should be positioned</li>
|
||||
* <li>int stop - index (exclusive) into char[] where the CharBuffer should be limited</li>
|
||||
* <li>String - description of the test scenario</li>
|
||||
* </ul>
|
||||
*
|
||||
* Generates the following sets of arguments/test cases.
|
||||
* <ul>
|
||||
* <li>See {@code populateAndAddCases(String, CharBuffer, List)} for the
|
||||
* following types:
|
||||
* <ul>
|
||||
* <li>HeapCharBuffer</i>
|
||||
* <li>HeapByteBuffer Big Endian</i>
|
||||
* <li>HeapByteBuffer Little Endian</i>
|
||||
* <li>DirectByteBuffer Big Endian</i>
|
||||
* <li>DirectByteBuffer Little Endian</i>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>Randomly generated content into {@link CharBuffer#wrap(CharSequence)
|
||||
* StringCharBuffer} - see {@code addCases(String, char[], CharBuffer, List)}.
|
||||
* <ul>
|
||||
* <li>StringCharBuffer wrapping a {@code CharBuffer} created from
|
||||
* {@link CharBuffer#wrap(char[])}</li>
|
||||
* <li>StringCharBuffer wrapping a {@code String}</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
static List<Arguments> charBufferArguments() {
|
||||
List<Arguments> args = new ArrayList<>();
|
||||
|
||||
populateAndAddCases("HeapCharBuffer", CharBuffer.allocate(SIZE), args);
|
||||
populateAndAddCases("HeapByteBuffer BE",
|
||||
ByteBuffer.allocate(SIZE * 2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), args);
|
||||
populateAndAddCases("HeapByteBuffer LE",
|
||||
ByteBuffer.allocate(SIZE * 2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), args);
|
||||
populateAndAddCases("DirectByteBuffer BE",
|
||||
ByteBuffer.allocateDirect(SIZE * 2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), args);
|
||||
populateAndAddCases("DirectByteBuffer LE",
|
||||
ByteBuffer.allocateDirect(SIZE * 2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), args);
|
||||
|
||||
char[] randomChars = randomChars();
|
||||
CharBuffer cb = CharBuffer.wrap(randomChars);
|
||||
addCases("StringCharBuffer over CharBuffer", randomChars, CharBuffer.wrap(cb), args);
|
||||
|
||||
addCases("StringCharBuffer over String", randomChars, CharBuffer.wrap(new String(randomChars)), args);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testToString(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
assertEquals(new String(expected, start, stop - start), actual.toString(), description);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testLength(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
assertEquals(stop - start, actual.length(), description);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsRange(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[16];
|
||||
int length = Math.min(10, stop - start - 1);
|
||||
actual.getChars(1, length + 1, val, 3);
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
assertEquals(expected[i + start + 1], val[i + 3], "val at offset of " + i + " from " + description);
|
||||
}
|
||||
// test that calling getChars did not move the position
|
||||
assertEquals(expected[start], actual.charAt(0), "first char after calling getChars: " + description);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsAll(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[stop - start];
|
||||
actual.getChars(0, val.length, val, 0);
|
||||
|
||||
for (int i = 0; i < val.length; ++i) {
|
||||
assertEquals(expected[i + start], val[i], "val at offset of " + i + " from " + description);
|
||||
}
|
||||
// test that calling getChars did not move the position
|
||||
assertEquals(expected[start], actual.charAt(0), "first char after calling getChars: " + description);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsNegativeSrcBegin(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[16];
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(-1, 4, val, 1));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsNegativeSrcEnd(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[16];
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(0, -4, val, 1));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsSrcEndBeforeBegin(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[16];
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(3, 2, val, 1));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsNegativeDstBegin(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[16];
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(1, 3, val, -1));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsDstBeginOOB(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[16];
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(1, 4, val, val.length + 1));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsDstLengthOOB(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
char[] val = new char[16];
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(1, 4, val, val.length - 2));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testGetCharsNullDst(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
assertThrows(NullPointerException.class, () -> actual.getChars(0, 1, null, 0));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testCharAt(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
for (int i = 0, j = stop - start; i < j; ++i) {
|
||||
assertEquals(expected[start + i], actual.charAt(i), "chart at " + i + ": " + description);
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testCharAtNegativePos(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.charAt(-1));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testCharAtPosOOB(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> actual.charAt(stop - start + 1));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testChars(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
OfInt chars = actual.chars().iterator();
|
||||
for (int i = 0, j = stop - start; i < j; ++i) {
|
||||
assertEquals(expected[start + i], (char) chars.nextInt(), "chart at " + i + ": " + description);
|
||||
}
|
||||
assertFalse(chars.hasNext(), "chars has more elements than expected " + description);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testCodePoints(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
OfInt codePoints = actual.codePoints().iterator();
|
||||
for (int i = 0, j = stop - start; i < j; ++i) {
|
||||
char c1 = expected[start + i];
|
||||
int expectedCodePoint = c1;
|
||||
if (Character.isHighSurrogate(c1) && (i + 1) < j) {
|
||||
char c2 = expected[start + i + 1];
|
||||
if (Character.isLowSurrogate(c2)) {
|
||||
expectedCodePoint = Character.toCodePoint(c1, c2);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
assertEquals(expectedCodePoint, codePoints.nextInt(), "code point at " + i + ": " + description);
|
||||
}
|
||||
assertFalse(codePoints.hasNext(), "codePoints has more elements than expected " + description);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name="{4}")
|
||||
@MethodSource("charBufferArguments")
|
||||
void testSubSequence(CharSequence actual, char[] expected, int start, int stop, String description) {
|
||||
int maxTests = Math.min(7, ((stop - start) >> 1) - 1);
|
||||
for (int i = 0; i < maxTests; ++i) {
|
||||
assertEquals(new String(expected, start + i, stop - start - (2 * i)),
|
||||
actual.subSequence(i, actual.length() - i).toString(),
|
||||
"subsequence at index " + i + " for " + description);
|
||||
}
|
||||
}
|
||||
}
|
||||
140
test/jdk/java/nio/Buffer/Chars.java
Normal file
140
test/jdk/java/nio/Buffer/Chars.java
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2026, 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
|
||||
* @bug 8014854
|
||||
* @summary Exercises CharBuffer#chars on each of the CharBuffer types
|
||||
* @run junit Chars
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class Chars {
|
||||
|
||||
static final Random RAND = new Random();
|
||||
|
||||
static final int SIZE = 128 + RAND.nextInt(1024);
|
||||
|
||||
/**
|
||||
* Randomize the char buffer's position and limit.
|
||||
*/
|
||||
static CharBuffer randomizeRange(CharBuffer cb) {
|
||||
int mid = cb.capacity() >>> 1;
|
||||
int start = RAND.nextInt(mid + 1); // from 0 to mid
|
||||
int end = mid + RAND.nextInt(cb.capacity() - mid + 1); // from mid to capacity
|
||||
cb.position(start);
|
||||
cb.limit(end);
|
||||
return cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomize the char buffer's contents, position and limit.
|
||||
*/
|
||||
static CharBuffer randomize(CharBuffer cb) {
|
||||
while (cb.hasRemaining()) {
|
||||
cb.put((char)RAND.nextInt());
|
||||
}
|
||||
return randomizeRange(cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sums the remaining chars in the char buffer.
|
||||
*/
|
||||
static int intSum(CharBuffer cb) {
|
||||
int sum = 0;
|
||||
cb.mark();
|
||||
while (cb.hasRemaining()) {
|
||||
sum += cb.get();
|
||||
}
|
||||
cb.reset();
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates char buffers to test, adding them to the given list.
|
||||
*/
|
||||
static void addCases(CharBuffer cb, List<CharBuffer> buffers) {
|
||||
randomize(cb);
|
||||
buffers.add(cb);
|
||||
|
||||
buffers.add(cb.slice());
|
||||
buffers.add(cb.duplicate());
|
||||
buffers.add(cb.asReadOnlyBuffer());
|
||||
|
||||
buffers.add(randomizeRange(cb.slice()));
|
||||
buffers.add(randomizeRange(cb.duplicate()));
|
||||
buffers.add(randomizeRange(cb.asReadOnlyBuffer()));
|
||||
}
|
||||
|
||||
private static Stream<Arguments> createCharBuffers() {
|
||||
List<CharBuffer> buffers = new ArrayList<>();
|
||||
|
||||
// heap
|
||||
addCases(CharBuffer.allocate(SIZE), buffers);
|
||||
addCases(CharBuffer.wrap(new char[SIZE]), buffers);
|
||||
addCases(ByteBuffer.allocate(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(),
|
||||
buffers);
|
||||
addCases(ByteBuffer.allocate(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(),
|
||||
buffers);
|
||||
|
||||
// direct
|
||||
addCases(ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(),
|
||||
buffers);
|
||||
addCases(ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(),
|
||||
buffers);
|
||||
|
||||
// read-only buffer backed by a CharSequence
|
||||
buffers.add(CharBuffer.wrap(randomize(CharBuffer.allocate(SIZE))));
|
||||
|
||||
List<Arguments> params = new ArrayList<Arguments>();
|
||||
for (int i = 0; i < buffers.size(); i++) {
|
||||
CharBuffer cb = buffers.get(i);
|
||||
params.add((Arguments.of(cb.getClass().getName(), cb)));
|
||||
}
|
||||
|
||||
return params.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("createCharBuffers")
|
||||
public void testChars(String type, CharBuffer cb) {
|
||||
System.err.format("%s position=%d, limit=%d%n", type, cb.position(), cb.limit());
|
||||
int expected = intSum(cb);
|
||||
assertEquals(expected, cb.chars().sum());
|
||||
assertEquals(expected, cb.chars().parallel().sum());
|
||||
}
|
||||
}
|
||||
42
test/jdk/java/nio/Buffer/Chew.java
Normal file
42
test/jdk/java/nio/Buffer/Chew.java
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 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
|
||||
* @bug 5046110
|
||||
* @summary Ensure that direct memory can be unreserved
|
||||
* as the reserving thread sleeps
|
||||
*
|
||||
* @run main/othervm -Xmx16M Chew
|
||||
*/
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
|
||||
public class Chew {
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 64; i++)
|
||||
ByteBuffer.allocateDirect(1 << 20);
|
||||
}
|
||||
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirect-X-Memory.java.template
Normal file
70
test/jdk/java/nio/Buffer/CopyDirect-X-Memory.java.template
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
#warn This file is preprocessed before being compiled
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirect$Type$Memory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init($Type$Buffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, ($type$)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init($type$ [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = ($type$)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
#if[byte]
|
||||
ByteBuffer b = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
#else[byte]
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
$Type$Buffer b = bb.as$Type$Buffer();
|
||||
#end[byte]
|
||||
init(b);
|
||||
$type$ [] a = new $type$[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFrom$Type$Array (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), ($type$)ic(i + 1));
|
||||
|
||||
// copyTo$Type$Array (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirectByteMemory.java
Normal file
70
test/jdk/java/nio/Buffer/CopyDirectByteMemory.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectByteMemory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init(ByteBuffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, (byte)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init(byte [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = (byte)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
|
||||
ByteBuffer b = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
|
||||
|
||||
|
||||
|
||||
init(b);
|
||||
byte [] a = new byte[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFromByteArray (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), (byte)ic(i + 1));
|
||||
|
||||
// copyToByteArray (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirectCharMemory.java
Normal file
70
test/jdk/java/nio/Buffer/CopyDirectCharMemory.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectCharMemory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init(CharBuffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, (char)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init(char [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = (char)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
|
||||
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
CharBuffer b = bb.asCharBuffer();
|
||||
|
||||
init(b);
|
||||
char [] a = new char[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFromCharArray (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), (char)ic(i + 1));
|
||||
|
||||
// copyToCharArray (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirectDoubleMemory.java
Normal file
70
test/jdk/java/nio/Buffer/CopyDirectDoubleMemory.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectDoubleMemory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init(DoubleBuffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, (double)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init(double [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = (double)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
|
||||
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
DoubleBuffer b = bb.asDoubleBuffer();
|
||||
|
||||
init(b);
|
||||
double [] a = new double[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFromDoubleArray (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), (double)ic(i + 1));
|
||||
|
||||
// copyToDoubleArray (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirectFloatMemory.java
Normal file
70
test/jdk/java/nio/Buffer/CopyDirectFloatMemory.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectFloatMemory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init(FloatBuffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, (float)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init(float [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = (float)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
|
||||
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
FloatBuffer b = bb.asFloatBuffer();
|
||||
|
||||
init(b);
|
||||
float [] a = new float[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFromFloatArray (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), (float)ic(i + 1));
|
||||
|
||||
// copyToFloatArray (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirectIntMemory.java
Normal file
70
test/jdk/java/nio/Buffer/CopyDirectIntMemory.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectIntMemory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init(IntBuffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, (int)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init(int [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = (int)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
|
||||
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
IntBuffer b = bb.asIntBuffer();
|
||||
|
||||
init(b);
|
||||
int [] a = new int[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFromIntArray (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), (int)ic(i + 1));
|
||||
|
||||
// copyToIntArray (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirectLongMemory.java
Normal file
70
test/jdk/java/nio/Buffer/CopyDirectLongMemory.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectLongMemory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init(LongBuffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, (long)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init(long [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = (long)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
|
||||
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
LongBuffer b = bb.asLongBuffer();
|
||||
|
||||
init(b);
|
||||
long [] a = new long[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFromLongArray (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), (long)ic(i + 1));
|
||||
|
||||
// copyToLongArray (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
47
test/jdk/java/nio/Buffer/CopyDirectMemory.java
Normal file
47
test/jdk/java/nio/Buffer/CopyDirectMemory.java
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2016, 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
|
||||
* @summary Test view buffer bulk operations for large buffers.
|
||||
* @bug 4463011
|
||||
*
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @build Basic
|
||||
* @run main CopyDirectMemory
|
||||
*/
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectMemory
|
||||
extends Basic
|
||||
{
|
||||
public static void main(String [] args) {
|
||||
CopyDirectByteMemory.test();
|
||||
CopyDirectCharMemory.test();
|
||||
CopyDirectShortMemory.test();
|
||||
CopyDirectIntMemory.test();
|
||||
CopyDirectLongMemory.test();
|
||||
CopyDirectFloatMemory.test();
|
||||
CopyDirectDoubleMemory.test();
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/nio/Buffer/CopyDirectShortMemory.java
Normal file
70
test/jdk/java/nio/Buffer/CopyDirectShortMemory.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2007, 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.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class CopyDirectShortMemory
|
||||
extends CopyDirectMemory
|
||||
{
|
||||
private static void init(ShortBuffer b) {
|
||||
int n = b.capacity();
|
||||
b.clear();
|
||||
for (int i = 0; i < n; i++)
|
||||
b.put(i, (short)ic(i));
|
||||
b.limit(n);
|
||||
b.position(0);
|
||||
}
|
||||
|
||||
private static void init(short [] a) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
a[i] = (short)ic(i + 1);
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
|
||||
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024);
|
||||
ShortBuffer b = bb.asShortBuffer();
|
||||
|
||||
init(b);
|
||||
short [] a = new short[b.capacity()];
|
||||
init(a);
|
||||
|
||||
// copyFromShortArray (a -> b)
|
||||
b.put(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
ck(b, b.get(i), (short)ic(i + 1));
|
||||
|
||||
// copyToShortArray (b -> a)
|
||||
init(b);
|
||||
init(a);
|
||||
b.get(a);
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != b.get(i))
|
||||
fail("Copy failed at " + i + ": '"
|
||||
+ a[i] + "' != '" + b.get(i) + "'");
|
||||
}
|
||||
}
|
||||
174
test/jdk/java/nio/Buffer/DirectBufferAllocTest.java
Normal file
174
test/jdk/java/nio/Buffer/DirectBufferAllocTest.java
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 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
|
||||
* @bug 6857566
|
||||
* @summary DirectByteBuffer garbage creation can outpace reclamation
|
||||
*
|
||||
* @run main/othervm -XX:MaxDirectMemorySize=128m -XX:-ExplicitGCInvokesConcurrent DirectBufferAllocTest
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class DirectBufferAllocTest {
|
||||
// defaults
|
||||
static final int RUN_TIME_SECONDS = 5;
|
||||
static final int MIN_THREADS = 4;
|
||||
static final int MAX_THREADS = 64;
|
||||
static final int CAPACITY = 1024 * 1024; // bytes
|
||||
|
||||
/**
|
||||
* This test spawns multiple threads that constantly allocate direct
|
||||
* {@link ByteBuffer}s in a loop, trying to provoke {@link OutOfMemoryError}.<p>
|
||||
* When run without command-line arguments, it runs as a regression test
|
||||
* for at most 5 seconds.<p>
|
||||
* Command line arguments:
|
||||
* <pre>
|
||||
* -r run-time-seconds <i>(duration of successful test - default 5 s)</i>
|
||||
* -t threads <i>(default is 2 * # of CPUs, at least 4 but no more than 64)</i>
|
||||
* -c capacity <i>(of direct buffers in bytes - default is 1MB)</i>
|
||||
* -p print-alloc-time-batch-size <i>(every "batch size" iterations,
|
||||
* average time per allocation is printed)</i>
|
||||
* </pre>
|
||||
* Use something like the following to run a 10 minute stress test and
|
||||
* print allocation times as it goes:
|
||||
* <pre>
|
||||
* java -XX:MaxDirectMemorySize=128m DirectBufferAllocTest -r 600 -t 32 -p 5000
|
||||
* </pre>
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
int runTimeSeconds = RUN_TIME_SECONDS;
|
||||
int threads = Math.max(
|
||||
Math.min(
|
||||
Runtime.getRuntime().availableProcessors() * 2,
|
||||
MAX_THREADS
|
||||
),
|
||||
MIN_THREADS
|
||||
);
|
||||
int capacity = CAPACITY;
|
||||
int printBatchSize = 0;
|
||||
|
||||
// override with command line arguments
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
switch (args[i]) {
|
||||
case "-r":
|
||||
runTimeSeconds = Integer.parseInt(args[++i]);
|
||||
break;
|
||||
case "-t":
|
||||
threads = Integer.parseInt(args[++i]);
|
||||
break;
|
||||
case "-c":
|
||||
capacity = Integer.parseInt(args[++i]);
|
||||
break;
|
||||
case "-p":
|
||||
printBatchSize = Integer.parseInt(args[++i]);
|
||||
break;
|
||||
default:
|
||||
System.err.println(
|
||||
"Usage: java" +
|
||||
" [-XX:MaxDirectMemorySize=XXXm]" +
|
||||
" DirectBufferAllocTest" +
|
||||
" [-r run-time-seconds]" +
|
||||
" [-t threads]" +
|
||||
" [-c capacity-of-direct-buffers]" +
|
||||
" [-p print-alloc-time-batch-size]"
|
||||
);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.printf(
|
||||
"Allocating direct ByteBuffers with capacity %d bytes, using %d threads for %d seconds...\n",
|
||||
capacity, threads, runTimeSeconds
|
||||
);
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(threads);
|
||||
|
||||
int pbs = printBatchSize;
|
||||
int cap = capacity;
|
||||
|
||||
List<Future<Void>> futures =
|
||||
IntStream.range(0, threads)
|
||||
.mapToObj(
|
||||
i -> (Callable<Void>) () -> {
|
||||
long t0 = System.nanoTime();
|
||||
loop:
|
||||
while (true) {
|
||||
for (int n = 0; pbs == 0 || n < pbs; n++) {
|
||||
if (Thread.interrupted()) {
|
||||
break loop;
|
||||
}
|
||||
ByteBuffer.allocateDirect(cap);
|
||||
}
|
||||
long t1 = System.nanoTime();
|
||||
if (pbs > 0) {
|
||||
System.out.printf(
|
||||
"Thread %2d: %5.2f ms/allocation\n",
|
||||
i, ((double) (t1 - t0) / (1_000_000d * pbs))
|
||||
);
|
||||
}
|
||||
t0 = t1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
)
|
||||
.map(executor::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (int i = 0; i < runTimeSeconds; i++) {
|
||||
if (futures.stream().anyMatch(Future::isDone)) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(1000L);
|
||||
}
|
||||
|
||||
Exception exception = null;
|
||||
for (Future<Void> future : futures) {
|
||||
if (future.isDone()) {
|
||||
try {
|
||||
future.get();
|
||||
} catch (ExecutionException e) {
|
||||
if (exception == null) {
|
||||
exception = new RuntimeException("Errors encountered!");
|
||||
}
|
||||
exception.addSuppressed(e.getCause());
|
||||
}
|
||||
} else {
|
||||
future.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
} else {
|
||||
System.out.printf("No errors after %d seconds.\n", runTimeSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
722
test/jdk/java/nio/Buffer/EqualsCompareTest.java
Normal file
722
test/jdk/java/nio/Buffer/EqualsCompareTest.java
Normal file
|
|
@ -0,0 +1,722 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8193085 8199773
|
||||
* @summary tests for buffer equals and compare
|
||||
* @run junit EqualsCompareTest
|
||||
*/
|
||||
|
||||
public class EqualsCompareTest {
|
||||
|
||||
// Maximum width in bits
|
||||
static final int MAX_WIDTH = 512;
|
||||
|
||||
static final Map<Class, Integer> typeToWidth;
|
||||
|
||||
static {
|
||||
typeToWidth = new HashMap<>();
|
||||
typeToWidth.put(byte.class, Byte.SIZE);
|
||||
typeToWidth.put(short.class, Short.SIZE);
|
||||
typeToWidth.put(char.class, Character.SIZE);
|
||||
typeToWidth.put(int.class, Integer.SIZE);
|
||||
typeToWidth.put(long.class, Long.SIZE);
|
||||
typeToWidth.put(float.class, Float.SIZE);
|
||||
typeToWidth.put(double.class, Double.SIZE);
|
||||
}
|
||||
|
||||
static int arraySizeFor(Class<?> type) {
|
||||
assert type.isPrimitive();
|
||||
return 4 * MAX_WIDTH / typeToWidth.get(type);
|
||||
}
|
||||
|
||||
enum BufferKind {
|
||||
HEAP,
|
||||
HEAP_VIEW,
|
||||
DIRECT;
|
||||
}
|
||||
|
||||
static abstract class BufferType<T extends Buffer, E> {
|
||||
final BufferKind k;
|
||||
final Class<?> bufferType;
|
||||
final Class<?> elementType;
|
||||
|
||||
final MethodHandle eq;
|
||||
final MethodHandle cmp;
|
||||
final MethodHandle mismtch;
|
||||
|
||||
final MethodHandle getter;
|
||||
final MethodHandle setter;
|
||||
|
||||
BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType) {
|
||||
this.k = k;
|
||||
this.bufferType = bufferType;
|
||||
this.elementType = elementType;
|
||||
|
||||
var lookup = MethodHandles.lookup();
|
||||
try {
|
||||
eq = lookup.findVirtual(bufferType, "equals", MethodType.methodType(boolean.class, Object.class));
|
||||
cmp = lookup.findVirtual(bufferType, "compareTo", MethodType.methodType(int.class, bufferType));
|
||||
mismtch = lookup.findVirtual(bufferType, "mismatch", MethodType.methodType(int.class, bufferType));
|
||||
|
||||
getter = lookup.findVirtual(bufferType, "get", MethodType.methodType(elementType, int.class));
|
||||
setter = lookup.findVirtual(bufferType, "put", MethodType.methodType(bufferType, int.class, elementType));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return bufferType.getName() + " " + k;
|
||||
}
|
||||
|
||||
T construct(int length) {
|
||||
return construct(length, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
abstract T construct(int length, ByteOrder bo);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T slice(T a, int from, int to, boolean dupOtherwiseSlice) {
|
||||
a = (T) a.position(from).limit(to);
|
||||
return (T) (dupOtherwiseSlice ? a.duplicate() : a.slice());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
E get(T a, int i) {
|
||||
try {
|
||||
return (E) getter.invoke(a, i);
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
void set(T a, int i, Object v) {
|
||||
try {
|
||||
setter.invoke(a, i, convert(v));
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
abstract Object convert(Object o);
|
||||
|
||||
boolean equals(T a, T b) {
|
||||
try {
|
||||
return (boolean) eq.invoke(a, b);
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
int compare(T a, T b) {
|
||||
try {
|
||||
return (int) cmp.invoke(a, b);
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
boolean pairWiseEquals(T a, T b) {
|
||||
if (a.remaining() != b.remaining())
|
||||
return false;
|
||||
int p = a.position();
|
||||
for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--)
|
||||
if (!get(a, i).equals(get(b, j)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int mismatch(T a, T b) {
|
||||
try {
|
||||
return (int) mismtch.invoke(a, b);
|
||||
}
|
||||
catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new Error(t);
|
||||
}
|
||||
}
|
||||
|
||||
static class Bytes extends BufferType<ByteBuffer, Byte> {
|
||||
Bytes(BufferKind k) {
|
||||
super(k, ByteBuffer.class, byte.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
ByteBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length).order(bo);
|
||||
default:
|
||||
case HEAP_VIEW:
|
||||
case HEAP:
|
||||
return ByteBuffer.allocate(length).order(bo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).byteValue()
|
||||
: o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Chars extends BufferType<CharBuffer, Character> {
|
||||
Chars(BufferKind k) {
|
||||
super(k, CharBuffer.class, char.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
CharBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Character.BYTES).
|
||||
order(bo).
|
||||
asCharBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Character.BYTES).
|
||||
order(bo).
|
||||
asCharBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return CharBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? (char) ((Integer) o).intValue()
|
||||
: o;
|
||||
}
|
||||
|
||||
CharBuffer transformToStringBuffer(CharBuffer c) {
|
||||
char[] chars = new char[c.remaining()];
|
||||
c.get(chars);
|
||||
return CharBuffer.wrap(new String(chars));
|
||||
}
|
||||
}
|
||||
|
||||
static class Shorts extends BufferType<ShortBuffer, Short> {
|
||||
Shorts(BufferKind k) {
|
||||
super(k, ShortBuffer.class, short.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
ShortBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Short.BYTES).
|
||||
order(bo).
|
||||
asShortBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Short.BYTES).
|
||||
order(bo).
|
||||
asShortBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return ShortBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).shortValue()
|
||||
: o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Ints extends BufferType<IntBuffer, Integer> {
|
||||
Ints(BufferKind k) {
|
||||
super(k, IntBuffer.class, int.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
IntBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Integer.BYTES).
|
||||
order(bo).
|
||||
asIntBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Integer.BYTES).
|
||||
order(bo).
|
||||
asIntBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return IntBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
Object convert(Object o) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Floats extends BufferType<FloatBuffer, Float> {
|
||||
Floats(BufferKind k) {
|
||||
super(k, FloatBuffer.class, float.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
FloatBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Float.BYTES).
|
||||
order(bo).
|
||||
asFloatBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Float.BYTES).
|
||||
order(bo).
|
||||
asFloatBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return FloatBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).floatValue()
|
||||
: o;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean pairWiseEquals(FloatBuffer a, FloatBuffer b) {
|
||||
if (a.remaining() != b.remaining())
|
||||
return false;
|
||||
int p = a.position();
|
||||
for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
|
||||
float av = a.get(i);
|
||||
float bv = b.get(j);
|
||||
if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class Longs extends BufferType<LongBuffer, Long> {
|
||||
Longs(BufferKind k) {
|
||||
super(k, LongBuffer.class, long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
LongBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Long.BYTES).
|
||||
order(bo).
|
||||
asLongBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Long.BYTES).
|
||||
order(bo).
|
||||
asLongBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return LongBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).longValue()
|
||||
: o;
|
||||
}
|
||||
}
|
||||
|
||||
static class Doubles extends BufferType<DoubleBuffer, Double> {
|
||||
Doubles(BufferKind k) {
|
||||
super(k, DoubleBuffer.class, double.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
DoubleBuffer construct(int length, ByteOrder bo) {
|
||||
switch (k) {
|
||||
case DIRECT:
|
||||
return ByteBuffer.allocateDirect(length * Double.BYTES).
|
||||
order(bo).
|
||||
asDoubleBuffer();
|
||||
case HEAP_VIEW:
|
||||
return ByteBuffer.allocate(length * Double.BYTES).
|
||||
order(bo).
|
||||
asDoubleBuffer();
|
||||
default:
|
||||
case HEAP:
|
||||
return DoubleBuffer.allocate(length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Object convert(Object o) {
|
||||
return o instanceof Integer
|
||||
? ((Integer) o).doubleValue()
|
||||
: o;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean pairWiseEquals(DoubleBuffer a, DoubleBuffer b) {
|
||||
if (a.remaining() != b.remaining())
|
||||
return false;
|
||||
int p = a.position();
|
||||
for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
|
||||
double av = a.get(i);
|
||||
double bv = b.get(j);
|
||||
if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<BufferType> bufferTypesSource() {
|
||||
return Stream.of
|
||||
(new BufferType.Bytes(BufferKind.HEAP),
|
||||
new BufferType.Bytes(BufferKind.DIRECT),
|
||||
new BufferType.Chars(BufferKind.HEAP),
|
||||
new BufferType.Chars(BufferKind.HEAP_VIEW),
|
||||
new BufferType.Chars(BufferKind.DIRECT),
|
||||
new BufferType.Shorts(BufferKind.HEAP),
|
||||
new BufferType.Shorts(BufferKind.HEAP_VIEW),
|
||||
new BufferType.Shorts(BufferKind.DIRECT),
|
||||
new BufferType.Ints(BufferKind.HEAP),
|
||||
new BufferType.Ints(BufferKind.HEAP_VIEW),
|
||||
new BufferType.Ints(BufferKind.DIRECT),
|
||||
new BufferType.Floats(BufferKind.HEAP),
|
||||
new BufferType.Floats(BufferKind.HEAP_VIEW),
|
||||
new BufferType.Floats(BufferKind.DIRECT),
|
||||
new BufferType.Longs(BufferKind.HEAP),
|
||||
new BufferType.Longs(BufferKind.HEAP_VIEW),
|
||||
new BufferType.Longs(BufferKind.DIRECT),
|
||||
new BufferType.Doubles(BufferKind.HEAP),
|
||||
new BufferType.Doubles(BufferKind.HEAP_VIEW),
|
||||
new BufferType.Doubles(BufferKind.DIRECT));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> floatBufferTypesSource() {
|
||||
LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
|
||||
LongFunction<Object> bToD = Double::longBitsToDouble;
|
||||
|
||||
return Stream.of
|
||||
(// canonical and non-canonical NaNs
|
||||
// If conversion is a signalling NaN it may be subject to conversion to a
|
||||
// quiet NaN on some processors, even if a copy is performed
|
||||
// The tests assume that if conversion occurs it does not convert to the
|
||||
// canonical NaN
|
||||
Arguments.of(new BufferType.Floats(BufferKind.HEAP), 0x7fc00000L, 0x7f800001L, bTof),
|
||||
Arguments.of(new BufferType.Floats(BufferKind.HEAP_VIEW), 0x7fc00000L, 0x7f800001L, bTof),
|
||||
Arguments.of(new BufferType.Floats(BufferKind.DIRECT), 0x7fc00000L, 0x7f800001L, bTof),
|
||||
Arguments.of(new BufferType.Doubles(BufferKind.HEAP), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD),
|
||||
Arguments.of(new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD),
|
||||
Arguments.of(new BufferType.Doubles(BufferKind.DIRECT), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD),
|
||||
|
||||
// +0.0 and -0.0
|
||||
Arguments.of(new BufferType.Floats(BufferKind.HEAP), 0x0L, 0x80000000L, bTof),
|
||||
Arguments.of(new BufferType.Floats(BufferKind.HEAP_VIEW), 0x0L, 0x80000000L, bTof),
|
||||
Arguments.of(new BufferType.Floats(BufferKind.DIRECT), 0x0L, 0x80000000L, bTof),
|
||||
Arguments.of(new BufferType.Doubles(BufferKind.HEAP), 0x0L, 0x8000000000000000L, bToD),
|
||||
Arguments.of(new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x0L, 0x8000000000000000L, bToD),
|
||||
Arguments.of(new BufferType.Doubles(BufferKind.DIRECT), 0x0L, 0x8000000000000000L, bToD));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> charBufferTypesSource() {
|
||||
return Stream.of
|
||||
(Arguments.of(new BufferType.Chars(BufferKind.HEAP)),
|
||||
Arguments.of(new BufferType.Chars(BufferKind.HEAP_VIEW)),
|
||||
Arguments.of(new BufferType.Chars(BufferKind.DIRECT)));
|
||||
}
|
||||
|
||||
// Tests all primitive buffers
|
||||
@ParameterizedTest
|
||||
@MethodSource("bufferTypesSource")
|
||||
<E>
|
||||
void testBuffers(BufferType<Buffer, E> bufferType) {
|
||||
// Test with buffers of the same byte order (BE)
|
||||
BiFunction<BufferType<Buffer, E>, Integer, Buffer> constructor = (at, s) -> {
|
||||
Buffer a = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(a, x, x % 8);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
testBufferType(bufferType, constructor, constructor);
|
||||
|
||||
// Test with buffers of different byte order
|
||||
if (bufferType.elementType != byte.class &&
|
||||
(bufferType.k == BufferKind.HEAP_VIEW ||
|
||||
bufferType.k == BufferKind.DIRECT)) {
|
||||
|
||||
BiFunction<BufferType<Buffer, E>, Integer, Buffer> leConstructor = (at, s) -> {
|
||||
Buffer a = at.construct(s, ByteOrder.LITTLE_ENDIAN);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(a, x, x % 8);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
testBufferType(bufferType, constructor, leConstructor);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests float and double buffers with edge-case values (NaN, -0.0, +0.0)
|
||||
@ParameterizedTest
|
||||
@MethodSource("floatBufferTypesSource")
|
||||
public void testFloatBuffers(
|
||||
BufferType<Buffer, Float> bufferType,
|
||||
long rawBitsA, long rawBitsB,
|
||||
LongFunction<Object> bitsToFloat) {
|
||||
Object av = bitsToFloat.apply(rawBitsA);
|
||||
Object bv = bitsToFloat.apply(rawBitsB);
|
||||
|
||||
BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allAs = (at, s) -> {
|
||||
Buffer b = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(b, x, av);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allBs = (at, s) -> {
|
||||
Buffer b = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(b, x, bv);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
BiFunction<BufferType<Buffer, Float>, Integer, Buffer> halfBs = (at, s) -> {
|
||||
Buffer b = at.construct(s);
|
||||
for (int x = 0; x < s / 2; x++) {
|
||||
at.set(b, x, bv);
|
||||
}
|
||||
for (int x = s / 2; x < s; x++) {
|
||||
at.set(b, x, 1);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
// Sanity check
|
||||
int size = arraySizeFor(bufferType.elementType);
|
||||
assertTrue(bufferType.pairWiseEquals(allAs.apply(bufferType, size),
|
||||
allBs.apply(bufferType, size)));
|
||||
assertTrue(bufferType.equals(allAs.apply(bufferType, size),
|
||||
allBs.apply(bufferType, size)));
|
||||
|
||||
testBufferType(bufferType, allAs, allBs);
|
||||
testBufferType(bufferType, allAs, halfBs);
|
||||
}
|
||||
|
||||
// Tests CharBuffer for region sources and CharSequence sources
|
||||
@ParameterizedTest
|
||||
@MethodSource("charBufferTypesSource")
|
||||
public void testCharBuffers(BufferType.Chars charBufferType) {
|
||||
|
||||
BiFunction<BufferType.Chars, Integer, CharBuffer> constructor = (at, s) -> {
|
||||
CharBuffer a = at.construct(s);
|
||||
for (int x = 0; x < s; x++) {
|
||||
at.set(a, x, x % 8);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
BiFunction<BufferType.Chars, Integer, CharBuffer> constructorX = constructor.
|
||||
andThen(charBufferType::transformToStringBuffer);
|
||||
|
||||
testBufferType(charBufferType, constructor, constructorX);
|
||||
}
|
||||
|
||||
<B extends Buffer, E, BT extends BufferType<B, E>>
|
||||
void testBufferType(BT bt,
|
||||
BiFunction<BT, Integer, B> aConstructor,
|
||||
BiFunction<BT, Integer, B> bConstructor) {
|
||||
int n = arraySizeFor(bt.elementType);
|
||||
|
||||
for (boolean dupOtherwiseSlice : new boolean[]{ false, true }) {
|
||||
for (int s : ranges(0, n)) {
|
||||
B a = aConstructor.apply(bt, s);
|
||||
B b = bConstructor.apply(bt, s);
|
||||
|
||||
for (int aFrom : ranges(0, s)) {
|
||||
for (int aTo : ranges(aFrom, s)) {
|
||||
int aLength = aTo - aFrom;
|
||||
|
||||
B as = aLength != s
|
||||
? bt.slice(a, aFrom, aTo, dupOtherwiseSlice)
|
||||
: a;
|
||||
|
||||
for (int bFrom : ranges(0, s)) {
|
||||
for (int bTo : ranges(bFrom, s)) {
|
||||
int bLength = bTo - bFrom;
|
||||
|
||||
B bs = bLength != s
|
||||
? bt.slice(b, bFrom, bTo, dupOtherwiseSlice)
|
||||
: b;
|
||||
|
||||
boolean eq = bt.pairWiseEquals(as, bs);
|
||||
assertEquals(eq, bt.equals(as, bs));
|
||||
assertEquals(eq, bt.equals(bs, as));
|
||||
if (eq) {
|
||||
assertEquals(0, bt.compare(as, bs));
|
||||
assertEquals(0, bt.compare(bs, as));
|
||||
|
||||
// If buffers are equal, there shall be no mismatch
|
||||
assertEquals(-1, bt.mismatch(as, bs));
|
||||
assertEquals(-1, bt.mismatch(bs, as));
|
||||
}
|
||||
else {
|
||||
int aCb = bt.compare(as, bs);
|
||||
int bCa = bt.compare(bs, as);
|
||||
int v = Integer.signum(aCb) * Integer.signum(bCa);
|
||||
assertEquals(-1, v);
|
||||
|
||||
int aMs = bt.mismatch(as, bs);
|
||||
int bMs = bt.mismatch(bs, as);
|
||||
assertNotEquals(-1, aMs);
|
||||
assertEquals(bMs, aMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aLength > 0 && !a.isReadOnly()) {
|
||||
for (int i = aFrom; i < aTo; i++) {
|
||||
B c = aConstructor.apply(bt, a.capacity());
|
||||
B cs = aLength != s
|
||||
? bt.slice(c, aFrom, aTo, dupOtherwiseSlice)
|
||||
: c;
|
||||
|
||||
// Create common prefix with a length of i - aFrom
|
||||
bt.set(c, i, -1);
|
||||
|
||||
assertFalse(bt.equals(c, a));
|
||||
|
||||
int cCa = bt.compare(cs, as);
|
||||
int aCc = bt.compare(as, cs);
|
||||
int v = Integer.signum(cCa) * Integer.signum(aCc);
|
||||
assertEquals(-1, v);
|
||||
|
||||
int cMa = bt.mismatch(cs, as);
|
||||
int aMc = bt.mismatch(as, cs);
|
||||
assertEquals(aMc, cMa);
|
||||
assertEquals(i - aFrom, cMa);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int[] ranges(int from, int to) {
|
||||
int width = to - from;
|
||||
switch (width) {
|
||||
case 0:
|
||||
return new int[]{};
|
||||
case 1:
|
||||
return new int[]{from, to};
|
||||
case 2:
|
||||
return new int[]{from, from + 1, to};
|
||||
case 3:
|
||||
return new int[]{from, from + 1, from + 2, to};
|
||||
default:
|
||||
return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)
|
||||
.filter(i -> i >= from && i <= to)
|
||||
.distinct().toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHashCode() throws IOException {
|
||||
byte[] bytes = "hello world".getBytes(UTF_8);
|
||||
Path path = Files.createTempFile("", "");
|
||||
Files.write(path, bytes);
|
||||
try (FileChannel fc = FileChannel.open(path, READ, DELETE_ON_CLOSE)) {
|
||||
MappedByteBuffer one = fc.map(FileChannel.MapMode.READ_ONLY, 0, bytes.length);
|
||||
ByteBuffer two = ByteBuffer.wrap(bytes);
|
||||
assertEquals(two, one);
|
||||
assertEquals(two.hashCode(), one.hashCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
145
test/jdk/java/nio/Buffer/LimitDirectMemory.java
Normal file
145
test/jdk/java/nio/Buffer/LimitDirectMemory.java
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2025, 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
|
||||
* @bug 4627316 6743526
|
||||
* @summary Test option to limit direct memory allocation
|
||||
* @library /test/lib
|
||||
*
|
||||
* @summary Test: memory is properly limited using multiple buffers
|
||||
* @run main/othervm -XX:MaxDirectMemorySize=10 LimitDirectMemory true 10 1
|
||||
* @run main/othervm -XX:MaxDirectMemorySize=1k LimitDirectMemory true 1k 100
|
||||
* @run main/othervm -XX:MaxDirectMemorySize=10m LimitDirectMemory true 10m 10m
|
||||
*
|
||||
* @summary Test: We can increase the amount of available memory
|
||||
* @run main/othervm -XX:MaxDirectMemorySize=65M LimitDirectMemory false 64M 65M
|
||||
*
|
||||
* @summary Test: Exactly the default amount of memory is available
|
||||
* @run main/othervm LimitDirectMemory false 10 1
|
||||
* @run main/othervm -Xmx64m LimitDirectMemory false 0 DEFAULT
|
||||
* @run main/othervm -Xmx64m LimitDirectMemory true 0 DEFAULT+1
|
||||
*
|
||||
* @summary Test: We should be able to eliminate direct memory allocation entirely
|
||||
* @run main/othervm -XX:MaxDirectMemorySize=0 LimitDirectMemory true 0 1
|
||||
*
|
||||
* @summary Test: Setting the system property should not work so we should be able
|
||||
* to allocate the default amount
|
||||
* @run main/othervm -Dsun.nio.MaxDirectMemorySize=1K -Xmx64m
|
||||
* LimitDirectMemory false DEFAULT-1 DEFAULT/2
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Properties;
|
||||
|
||||
public class LimitDirectMemory {
|
||||
private static final int K = 1024;
|
||||
|
||||
public static void main(String [] args) throws Exception {
|
||||
if (args.length < 2) {
|
||||
throw new IllegalArgumentException("Usage: "
|
||||
+ "java LimitDirectMemory"
|
||||
+ " <OOME_expected(true|false)>"
|
||||
+ " <fill_direct_memory>"
|
||||
+ " <size_per_buffer>");
|
||||
}
|
||||
boolean throwp = parseThrow(args[0]);
|
||||
int size = parseSize(args[1]);
|
||||
int incr = (args.length > 2 ? parseSize(args[2]) : size);
|
||||
|
||||
Properties p = System.getProperties();
|
||||
if (p.getProperty("sun.nio.MaxDirectMemorySize") != null)
|
||||
throw new RuntimeException("sun.nio.MaxDirectMemorySize defined");
|
||||
|
||||
ByteBuffer [] b = new ByteBuffer[K];
|
||||
|
||||
// Fill up most/all of the direct memory
|
||||
int i = 0;
|
||||
while (size >= incr) {
|
||||
b[i++] = ByteBuffer.allocateDirect(incr);
|
||||
size -= incr;
|
||||
}
|
||||
|
||||
if (throwp) {
|
||||
try {
|
||||
b[i] = ByteBuffer.allocateDirect(incr);
|
||||
throw new RuntimeException("OutOfMemoryError not thrown: "
|
||||
+ incr);
|
||||
} catch (OutOfMemoryError e) {
|
||||
e.printStackTrace(System.out);
|
||||
System.out.println("OK - Error thrown as expected ");
|
||||
}
|
||||
} else {
|
||||
b[i] = ByteBuffer.allocateDirect(incr);
|
||||
System.out.println("OK - Error not thrown");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean parseThrow(String s) {
|
||||
if (s.equals("true")) return true;
|
||||
if (s.equals("false")) return false;
|
||||
throw new RuntimeException("Unrecognized expectation: " + s);
|
||||
}
|
||||
|
||||
private static int parseSize(String size) throws Exception {
|
||||
|
||||
if (size.equals("DEFAULT"))
|
||||
return (int)Runtime.getRuntime().maxMemory();
|
||||
if (size.equals("DEFAULT+1"))
|
||||
return (int)Runtime.getRuntime().maxMemory() + 1;
|
||||
if (size.equals("DEFAULT+1M"))
|
||||
return (int)Runtime.getRuntime().maxMemory() + (1 << 20);
|
||||
if (size.equals("DEFAULT-1"))
|
||||
return (int)Runtime.getRuntime().maxMemory() - 1;
|
||||
if (size.equals("DEFAULT/2"))
|
||||
return (int)Runtime.getRuntime().maxMemory() / 2;
|
||||
|
||||
int idx = 0, len = size.length();
|
||||
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (Character.isDigit(size.charAt(i))) idx++;
|
||||
else break;
|
||||
}
|
||||
|
||||
if (idx == 0)
|
||||
throw new RuntimeException("No digits detected: " + size);
|
||||
|
||||
int result = Integer.parseInt(size.substring(0, idx));
|
||||
|
||||
if (idx < len) {
|
||||
for (int i = idx; i < len; i++) {
|
||||
switch(size.charAt(i)) {
|
||||
case 'T': case 't': result *= K; // fall through
|
||||
case 'G': case 'g': result *= K; // fall through
|
||||
case 'M': case 'm': result *= K; // fall through
|
||||
case 'K': case 'k': result *= K;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unrecognized size: " + size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
62
test/jdk/java/nio/Buffer/LimitDirectMemoryNegativeTest.java
Normal file
62
test/jdk/java/nio/Buffer/LimitDirectMemoryNegativeTest.java
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2025, 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
|
||||
* @bug 4627316 6743526
|
||||
* @summary Test option to limit direct memory allocation,
|
||||
* various bad values fail to launch the VM
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Utils
|
||||
* jdk.test.lib.Asserts
|
||||
* jdk.test.lib.JDKToolFinder
|
||||
* jdk.test.lib.JDKToolLauncher
|
||||
* jdk.test.lib.Platform
|
||||
* jdk.test.lib.process.*
|
||||
*
|
||||
* @run main LimitDirectMemoryNegativeTest foo
|
||||
* @run main LimitDirectMemoryNegativeTest 10kmt
|
||||
* @run main LimitDirectMemoryNegativeTest -1
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class LimitDirectMemoryNegativeTest {
|
||||
|
||||
private static final String ERR = "Improperly specified VM option 'MaxDirectMemorySize=";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length != 1) {
|
||||
throw new IllegalArgumentException("missing size argument");
|
||||
}
|
||||
|
||||
int exitCode = ProcessTools.executeTestJava(
|
||||
"-XX:MaxDirectMemorySize=" + args[0],
|
||||
LimitDirectMemoryNegativeTest.class.getName())
|
||||
.shouldContain(ERR + args[0])
|
||||
.getExitValue();
|
||||
if (exitCode != 1) {
|
||||
throw new RuntimeException("Unexpected exit code: " + exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
test/jdk/java/nio/Buffer/Order-X.java.template
Normal file
82
test/jdk/java/nio/Buffer/Order-X.java.template
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2021, 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.
|
||||
*/
|
||||
|
||||
/* Type-specific source code for unit test
|
||||
*
|
||||
* Regenerate the OrderX classes via genOrder.sh whenever this file changes.
|
||||
* We check in the generated source files so that the test tree can be used
|
||||
* independently of the rest of the source tree.
|
||||
*/
|
||||
|
||||
#warn This file is preprocessed before being compiled
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class Order$Type$ extends Order {
|
||||
private static void ck$Type$Buffer($Type$Buffer buf, ByteOrder expected) {
|
||||
ck(buf.asReadOnlyBuffer().order(), expected);
|
||||
ck(buf.duplicate().order(), expected);
|
||||
ck(buf.slice().order(), expected);
|
||||
#if[char]
|
||||
ck(buf.subSequence(buf.position(), buf.remaining()).order(), expected);
|
||||
ck(buf.subSequence(buf.position(), buf.position()).order(), expected);
|
||||
#end[char]
|
||||
}
|
||||
|
||||
static void ck$Type$Buffer() {
|
||||
$type$[] array = new $type$[LENGTH];
|
||||
$Type$Buffer buf = $Type$Buffer.wrap(array);
|
||||
ck(buf.order(), nord);
|
||||
ck$Type$Buffer(buf, nord);
|
||||
|
||||
buf = $Type$Buffer.wrap(array, LENGTH/2, LENGTH/2);
|
||||
ck(buf.order(), nord);
|
||||
ck$Type$Buffer(buf, nord);
|
||||
|
||||
buf = $Type$Buffer.allocate(LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ck$Type$Buffer(buf, nord);
|
||||
#if[char]
|
||||
buf = $Type$Buffer.wrap("abcdefghijk");
|
||||
ck(buf.order(), nord);
|
||||
ck$Type$Buffer(buf, nord);
|
||||
|
||||
buf = $Type$Buffer.wrap("abcdefghijk", 0, 5);
|
||||
ck(buf.order(), nord);
|
||||
ck$Type$Buffer(buf, nord);
|
||||
|
||||
buf = $Type$Buffer.wrap(array).subSequence(0, LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ck$Type$Buffer(buf, nord);
|
||||
|
||||
buf = ByteBuffer.wrap(new byte[LENGTH]).as$Type$Buffer();
|
||||
ck(buf.order(), be);
|
||||
ck$Type$Buffer(buf, be);
|
||||
|
||||
buf = ByteBuffer.wrap(new byte[LENGTH]).order(le).as$Type$Buffer();
|
||||
ck(buf.order(), le);
|
||||
ck$Type$Buffer(buf, le);
|
||||
#end[char]
|
||||
}
|
||||
}
|
||||
|
||||
96
test/jdk/java/nio/Buffer/Order.java
Normal file
96
test/jdk/java/nio/Buffer/Order.java
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2016, 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
|
||||
* @bug 8065570
|
||||
* @summary Unit test for X-Buffer.order methods
|
||||
*/
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
|
||||
public class Order {
|
||||
|
||||
static final ByteOrder be = ByteOrder.BIG_ENDIAN;
|
||||
static final ByteOrder le = ByteOrder.LITTLE_ENDIAN;
|
||||
static final ByteOrder nord = ByteOrder.nativeOrder();
|
||||
|
||||
protected static final int LENGTH = 16;
|
||||
|
||||
static void ck(ByteOrder ord, ByteOrder expected) {
|
||||
if (ord != expected)
|
||||
throw new RuntimeException("Got " + ord + ", expected " + expected);
|
||||
}
|
||||
|
||||
private static void ckViews(ByteBuffer bb) {
|
||||
ck(bb.asCharBuffer().order(), bb.order());
|
||||
ck(bb.asShortBuffer().order(), bb.order());
|
||||
ck(bb.asIntBuffer().order(), bb.order());
|
||||
ck(bb.asLongBuffer().order(), bb.order());
|
||||
ck(bb.asFloatBuffer().order(), bb.order());
|
||||
ck(bb.asDoubleBuffer().order(), bb.order());
|
||||
}
|
||||
|
||||
private static void ckCopyViews(ByteBuffer bb) {
|
||||
ck(bb.asReadOnlyBuffer().order(), be);
|
||||
ck(bb.duplicate().order(), be);
|
||||
ck(bb.slice().order(), be);
|
||||
}
|
||||
|
||||
private static void ckByteBuffer(ByteBuffer bb) {
|
||||
ckViews(bb);
|
||||
ckCopyViews(bb);
|
||||
bb.order(be);
|
||||
ckViews(bb);
|
||||
ckCopyViews(bb);
|
||||
bb.order(le);
|
||||
ckViews(bb);
|
||||
ckCopyViews(bb);
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
|
||||
ck(ByteBuffer.wrap(new byte[LENGTH], LENGTH/2, LENGTH/2).order(), be);
|
||||
ck(ByteBuffer.wrap(new byte[LENGTH]).order(), be);
|
||||
ck(ByteBuffer.wrap(new byte[LENGTH], LENGTH/2, LENGTH/2).order(be).order(), be);
|
||||
ck(ByteBuffer.wrap(new byte[LENGTH]).order(be).order(), be);
|
||||
ck(ByteBuffer.wrap(new byte[LENGTH], LENGTH/2, LENGTH/2).order(le).order(), le);
|
||||
ck(ByteBuffer.wrap(new byte[LENGTH]).order(le).order(), le);
|
||||
ck(ByteBuffer.allocate(LENGTH).order(), be);
|
||||
ck(ByteBuffer.allocateDirect(LENGTH).order(), be);
|
||||
ck(ByteBuffer.allocate(LENGTH).order(be).order(), be);
|
||||
ck(ByteBuffer.allocate(LENGTH).order(le).order(), le);
|
||||
ck(ByteBuffer.allocateDirect(LENGTH).order(be).order(), be);
|
||||
ck(ByteBuffer.allocateDirect(LENGTH).order(le).order(), le);
|
||||
|
||||
ckByteBuffer(ByteBuffer.allocate(LENGTH));
|
||||
ckByteBuffer(ByteBuffer.allocateDirect(LENGTH));
|
||||
|
||||
OrderChar.ckCharBuffer();
|
||||
OrderShort.ckShortBuffer();
|
||||
OrderInt.ckIntBuffer();
|
||||
OrderLong.ckLongBuffer();
|
||||
OrderFloat.ckFloatBuffer();
|
||||
OrderDouble.ckDoubleBuffer();
|
||||
}
|
||||
}
|
||||
82
test/jdk/java/nio/Buffer/OrderChar.java
Normal file
82
test/jdk/java/nio/Buffer/OrderChar.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2021, 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.
|
||||
*/
|
||||
|
||||
/* Type-specific source code for unit test
|
||||
*
|
||||
* Regenerate the OrderX classes via genOrder.sh whenever this file changes.
|
||||
* We check in the generated source files so that the test tree can be used
|
||||
* independently of the rest of the source tree.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class OrderChar extends Order {
|
||||
private static void ckCharBuffer(CharBuffer buf, ByteOrder expected) {
|
||||
ck(buf.asReadOnlyBuffer().order(), expected);
|
||||
ck(buf.duplicate().order(), expected);
|
||||
ck(buf.slice().order(), expected);
|
||||
|
||||
ck(buf.subSequence(buf.position(), buf.remaining()).order(), expected);
|
||||
ck(buf.subSequence(buf.position(), buf.position()).order(), expected);
|
||||
|
||||
}
|
||||
|
||||
static void ckCharBuffer() {
|
||||
char[] array = new char[LENGTH];
|
||||
CharBuffer buf = CharBuffer.wrap(array);
|
||||
ck(buf.order(), nord);
|
||||
ckCharBuffer(buf, nord);
|
||||
|
||||
buf = CharBuffer.wrap(array, LENGTH/2, LENGTH/2);
|
||||
ck(buf.order(), nord);
|
||||
ckCharBuffer(buf, nord);
|
||||
|
||||
buf = CharBuffer.allocate(LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ckCharBuffer(buf, nord);
|
||||
|
||||
buf = CharBuffer.wrap("abcdefghijk");
|
||||
ck(buf.order(), nord);
|
||||
ckCharBuffer(buf, nord);
|
||||
|
||||
buf = CharBuffer.wrap("abcdefghijk", 0, 5);
|
||||
ck(buf.order(), nord);
|
||||
ckCharBuffer(buf, nord);
|
||||
|
||||
buf = CharBuffer.wrap(array).subSequence(0, LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ckCharBuffer(buf, nord);
|
||||
|
||||
buf = ByteBuffer.wrap(new byte[LENGTH]).asCharBuffer();
|
||||
ck(buf.order(), be);
|
||||
ckCharBuffer(buf, be);
|
||||
|
||||
buf = ByteBuffer.wrap(new byte[LENGTH]).order(le).asCharBuffer();
|
||||
ck(buf.order(), le);
|
||||
ckCharBuffer(buf, le);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
82
test/jdk/java/nio/Buffer/OrderDouble.java
Normal file
82
test/jdk/java/nio/Buffer/OrderDouble.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2021, 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.
|
||||
*/
|
||||
|
||||
/* Type-specific source code for unit test
|
||||
*
|
||||
* Regenerate the OrderX classes via genOrder.sh whenever this file changes.
|
||||
* We check in the generated source files so that the test tree can be used
|
||||
* independently of the rest of the source tree.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class OrderDouble extends Order {
|
||||
private static void ckDoubleBuffer(DoubleBuffer buf, ByteOrder expected) {
|
||||
ck(buf.asReadOnlyBuffer().order(), expected);
|
||||
ck(buf.duplicate().order(), expected);
|
||||
ck(buf.slice().order(), expected);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void ckDoubleBuffer() {
|
||||
double[] array = new double[LENGTH];
|
||||
DoubleBuffer buf = DoubleBuffer.wrap(array);
|
||||
ck(buf.order(), nord);
|
||||
ckDoubleBuffer(buf, nord);
|
||||
|
||||
buf = DoubleBuffer.wrap(array, LENGTH/2, LENGTH/2);
|
||||
ck(buf.order(), nord);
|
||||
ckDoubleBuffer(buf, nord);
|
||||
|
||||
buf = DoubleBuffer.allocate(LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ckDoubleBuffer(buf, nord);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
82
test/jdk/java/nio/Buffer/OrderFloat.java
Normal file
82
test/jdk/java/nio/Buffer/OrderFloat.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2021, 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.
|
||||
*/
|
||||
|
||||
/* Type-specific source code for unit test
|
||||
*
|
||||
* Regenerate the OrderX classes via genOrder.sh whenever this file changes.
|
||||
* We check in the generated source files so that the test tree can be used
|
||||
* independently of the rest of the source tree.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class OrderFloat extends Order {
|
||||
private static void ckFloatBuffer(FloatBuffer buf, ByteOrder expected) {
|
||||
ck(buf.asReadOnlyBuffer().order(), expected);
|
||||
ck(buf.duplicate().order(), expected);
|
||||
ck(buf.slice().order(), expected);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void ckFloatBuffer() {
|
||||
float[] array = new float[LENGTH];
|
||||
FloatBuffer buf = FloatBuffer.wrap(array);
|
||||
ck(buf.order(), nord);
|
||||
ckFloatBuffer(buf, nord);
|
||||
|
||||
buf = FloatBuffer.wrap(array, LENGTH/2, LENGTH/2);
|
||||
ck(buf.order(), nord);
|
||||
ckFloatBuffer(buf, nord);
|
||||
|
||||
buf = FloatBuffer.allocate(LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ckFloatBuffer(buf, nord);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
82
test/jdk/java/nio/Buffer/OrderInt.java
Normal file
82
test/jdk/java/nio/Buffer/OrderInt.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2021, 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.
|
||||
*/
|
||||
|
||||
/* Type-specific source code for unit test
|
||||
*
|
||||
* Regenerate the OrderX classes via genOrder.sh whenever this file changes.
|
||||
* We check in the generated source files so that the test tree can be used
|
||||
* independently of the rest of the source tree.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class OrderInt extends Order {
|
||||
private static void ckIntBuffer(IntBuffer buf, ByteOrder expected) {
|
||||
ck(buf.asReadOnlyBuffer().order(), expected);
|
||||
ck(buf.duplicate().order(), expected);
|
||||
ck(buf.slice().order(), expected);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void ckIntBuffer() {
|
||||
int[] array = new int[LENGTH];
|
||||
IntBuffer buf = IntBuffer.wrap(array);
|
||||
ck(buf.order(), nord);
|
||||
ckIntBuffer(buf, nord);
|
||||
|
||||
buf = IntBuffer.wrap(array, LENGTH/2, LENGTH/2);
|
||||
ck(buf.order(), nord);
|
||||
ckIntBuffer(buf, nord);
|
||||
|
||||
buf = IntBuffer.allocate(LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ckIntBuffer(buf, nord);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
82
test/jdk/java/nio/Buffer/OrderLong.java
Normal file
82
test/jdk/java/nio/Buffer/OrderLong.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2021, 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.
|
||||
*/
|
||||
|
||||
/* Type-specific source code for unit test
|
||||
*
|
||||
* Regenerate the OrderX classes via genOrder.sh whenever this file changes.
|
||||
* We check in the generated source files so that the test tree can be used
|
||||
* independently of the rest of the source tree.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class OrderLong extends Order {
|
||||
private static void ckLongBuffer(LongBuffer buf, ByteOrder expected) {
|
||||
ck(buf.asReadOnlyBuffer().order(), expected);
|
||||
ck(buf.duplicate().order(), expected);
|
||||
ck(buf.slice().order(), expected);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void ckLongBuffer() {
|
||||
long[] array = new long[LENGTH];
|
||||
LongBuffer buf = LongBuffer.wrap(array);
|
||||
ck(buf.order(), nord);
|
||||
ckLongBuffer(buf, nord);
|
||||
|
||||
buf = LongBuffer.wrap(array, LENGTH/2, LENGTH/2);
|
||||
ck(buf.order(), nord);
|
||||
ckLongBuffer(buf, nord);
|
||||
|
||||
buf = LongBuffer.allocate(LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ckLongBuffer(buf, nord);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
82
test/jdk/java/nio/Buffer/OrderShort.java
Normal file
82
test/jdk/java/nio/Buffer/OrderShort.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2021, 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.
|
||||
*/
|
||||
|
||||
/* Type-specific source code for unit test
|
||||
*
|
||||
* Regenerate the OrderX classes via genOrder.sh whenever this file changes.
|
||||
* We check in the generated source files so that the test tree can be used
|
||||
* independently of the rest of the source tree.
|
||||
*/
|
||||
|
||||
// -- This file was mechanically generated: Do not edit! -- //
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class OrderShort extends Order {
|
||||
private static void ckShortBuffer(ShortBuffer buf, ByteOrder expected) {
|
||||
ck(buf.asReadOnlyBuffer().order(), expected);
|
||||
ck(buf.duplicate().order(), expected);
|
||||
ck(buf.slice().order(), expected);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void ckShortBuffer() {
|
||||
short[] array = new short[LENGTH];
|
||||
ShortBuffer buf = ShortBuffer.wrap(array);
|
||||
ck(buf.order(), nord);
|
||||
ckShortBuffer(buf, nord);
|
||||
|
||||
buf = ShortBuffer.wrap(array, LENGTH/2, LENGTH/2);
|
||||
ck(buf.order(), nord);
|
||||
ckShortBuffer(buf, nord);
|
||||
|
||||
buf = ShortBuffer.allocate(LENGTH);
|
||||
ck(buf.order(), nord);
|
||||
ckShortBuffer(buf, nord);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
114
test/jdk/java/nio/Buffer/ReachabilityTest.java
Normal file
114
test/jdk/java/nio/Buffer/ReachabilityTest.java
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2026, 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
|
||||
* @bug 8208362
|
||||
* @summary Tests reachability from source to dependent direct byte buffers
|
||||
* @run junit ReachabilityTest
|
||||
*/
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class ReachabilityTest {
|
||||
|
||||
@Test
|
||||
public void testDuplicate() {
|
||||
testReachability(ByteBuffer.allocateDirect(16384),
|
||||
ByteBuffer::duplicate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSlice() {
|
||||
testReachability(ByteBuffer.allocateDirect(16384),
|
||||
ByteBuffer::slice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testViewDuplicate() {
|
||||
testReachability(ByteBuffer.allocateDirect(16384),
|
||||
(Buffer b) -> b instanceof ByteBuffer
|
||||
? ((ByteBuffer) b).asIntBuffer()
|
||||
: b.duplicate()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testViewSlice() {
|
||||
testReachability(ByteBuffer.allocateDirect(16384),
|
||||
(Buffer b) -> b instanceof ByteBuffer
|
||||
? ((ByteBuffer) b).asIntBuffer()
|
||||
: b.slice()
|
||||
);
|
||||
}
|
||||
|
||||
<T> void testReachability(T t, UnaryOperator<T> b) {
|
||||
WeakReference<T> root = new WeakReference<>(t);
|
||||
|
||||
ReferenceQueue<Object> queue = new ReferenceQueue<>();
|
||||
List<WeakReference<T>> refs = new ArrayList<>();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
t = b.apply(t);
|
||||
refs.add(new WeakReference<>(t, queue));
|
||||
}
|
||||
t = b.apply(t);
|
||||
|
||||
boolean collected = false;
|
||||
long timeoutMillis = 100L;
|
||||
try {
|
||||
for (int tries = 0; tries < 3 && !collected; tries++) {
|
||||
System.gc();
|
||||
collected = refs.stream().map(Reference::get).anyMatch(Objects::isNull);
|
||||
if (!collected) {
|
||||
collected = queue.remove(timeoutMillis) != null;
|
||||
timeoutMillis *= 4;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException unexpected) {
|
||||
fail("unexpected InterruptedException");
|
||||
}
|
||||
|
||||
// Some or all of the intermediate values must be GC'ed
|
||||
assertTrue(collected);
|
||||
// The root should never be GC'ed
|
||||
assertNotNull(root.get());
|
||||
|
||||
Reference.reachabilityFence(t);
|
||||
}
|
||||
}
|
||||
178
test/jdk/java/nio/Buffer/StringCharBufferSliceTest.java
Normal file
178
test/jdk/java/nio/Buffer/StringCharBufferSliceTest.java
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
* @bug 4997655 5071718 7000913
|
||||
* @summary (bf) CharBuffer.slice() on wrapped CharSequence results in wrong position
|
||||
*/
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.InvalidMarkException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class StringCharBufferSliceTest {
|
||||
public static void main( String[] args) throws Exception {
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing the slice method...");
|
||||
|
||||
final String in = "for testing";
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing with the position 0.");
|
||||
|
||||
CharBuffer buff = CharBuffer.wrap(in);
|
||||
test(buff, buff.slice());
|
||||
test(buff, buff.slice(0, buff.remaining()));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing with new position.");
|
||||
|
||||
buff.position(2);
|
||||
test(buff, buff.slice());
|
||||
test(buff, buff.slice(2, buff.remaining()));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing with non zero initial position.");
|
||||
|
||||
buff = CharBuffer.wrap(in, 3, in.length());
|
||||
test(buff, buff.slice());
|
||||
test(buff, buff.slice(0, buff.remaining()));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing slice result with get()");
|
||||
buff.position(4);
|
||||
buff.limit(7);
|
||||
BiConsumer<CharBuffer,CharBuffer> bitest = (b, s) -> {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (s.get() != b.get()) {
|
||||
throw new RuntimeException
|
||||
("Wrong characters in slice result.");
|
||||
}
|
||||
}
|
||||
};
|
||||
bitest.accept(buff, buff.slice());
|
||||
buff.position(4);
|
||||
bitest.accept(buff, buff.slice(4, 3));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing slice result with get(int)");
|
||||
buff.position(4);
|
||||
buff.limit(7);
|
||||
bitest = (b, s) -> {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (s.get(i) != b.get(4 + i)) {
|
||||
throw new RuntimeException
|
||||
("Wrong characters in slice result.");
|
||||
}
|
||||
}
|
||||
};
|
||||
bitest.accept(buff, buff.slice());
|
||||
buff.position(4);
|
||||
bitest.accept(buff, buff.slice(4, 3));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing slice with result of slice");
|
||||
buff.position(0);
|
||||
buff.limit(buff.capacity());
|
||||
Consumer<CharBuffer> test = (s) -> {
|
||||
for (int i=0; i<4; i++) {
|
||||
s.position(i);
|
||||
CharBuffer nextSlice = s.slice();
|
||||
if (nextSlice.position() != 0)
|
||||
throw new RuntimeException
|
||||
("New buffer's position should be zero");
|
||||
if (!nextSlice.equals(s))
|
||||
throw new RuntimeException("New buffer should be equal");
|
||||
s = nextSlice;
|
||||
}
|
||||
};
|
||||
test.accept(buff.slice());
|
||||
test.accept(buff.slice(0, buff.capacity()));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing toString.");
|
||||
buff.position(4);
|
||||
buff.limit(7);
|
||||
test = (s) -> {
|
||||
if (!s.toString().equals("tes")) {
|
||||
throw new RuntimeException
|
||||
("bad toString() after slice(): " + s.toString());
|
||||
}
|
||||
};
|
||||
test.accept(buff.slice());
|
||||
test.accept(buff.slice(4, 3));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing subSequence.");
|
||||
buff.position(4);
|
||||
buff.limit(8);
|
||||
test = (s) -> {
|
||||
CharSequence subSeq = s.subSequence(1, 3);
|
||||
if (subSeq.charAt(0) != 'e' || subSeq.charAt(1) != 's') {
|
||||
throw new RuntimeException
|
||||
("bad subSequence() after slice(): '" + subSeq + "'");
|
||||
}
|
||||
};
|
||||
test.accept(buff.slice());
|
||||
test.accept(buff.slice(4, 4));
|
||||
|
||||
System.out.println(
|
||||
">>> StringCharBufferSliceTest-main: testing duplicate.");
|
||||
buff.position(4);
|
||||
buff.limit(8);
|
||||
test = (s) -> {
|
||||
CharBuffer dupe = s.duplicate();
|
||||
if (dupe.charAt(0) != 't' || dupe.charAt(1) != 'e'
|
||||
|| dupe.charAt(2) != 's' || dupe.charAt(3) != 't') {
|
||||
throw new RuntimeException
|
||||
("bad duplicate() after slice(): '" + dupe + "'");
|
||||
}
|
||||
};
|
||||
test.accept(buff.slice());
|
||||
test.accept(buff.slice(4, 4));
|
||||
|
||||
System.out.println(">>> StringCharBufferSliceTest-main: done!");
|
||||
}
|
||||
|
||||
public static void test(CharBuffer buff, CharBuffer slice) throws RuntimeException {
|
||||
boolean marked = false;
|
||||
|
||||
try {
|
||||
slice.reset();
|
||||
|
||||
marked = true;
|
||||
} catch (InvalidMarkException ime) {
|
||||
// expected
|
||||
}
|
||||
|
||||
if (marked ||
|
||||
slice.position() != 0 ||
|
||||
buff.remaining() != slice.limit() ||
|
||||
buff.remaining() != slice.capacity()) {
|
||||
|
||||
throw new RuntimeException(
|
||||
"Calling the CharBuffer.slice method failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
246
test/jdk/java/nio/Buffer/SwapMicroBenchmark.java
Normal file
246
test/jdk/java/nio/Buffer/SwapMicroBenchmark.java
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 2016, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is not a regression test, but a micro-benchmark.
|
||||
* To exercise swap, run with filter=LITTLE_ENDIAN on sparc,
|
||||
* filter=BIG_ENDIAN on x86.
|
||||
*
|
||||
* I have run this as follows:
|
||||
*
|
||||
* for f in -client -server; do mergeBench dolphin . jr -dsa -da $f SwapMicroBenchmark.java filter=LITTLE_ENDIAN; done
|
||||
*
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.nio.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SwapMicroBenchmark {
|
||||
abstract static class Job {
|
||||
private final String name;
|
||||
public Job(String name) { this.name = name; }
|
||||
public String name() { return name; }
|
||||
public abstract void work() throws Throwable;
|
||||
}
|
||||
|
||||
private static void collectAllGarbage() {
|
||||
final java.util.concurrent.CountDownLatch drained
|
||||
= new java.util.concurrent.CountDownLatch(1);
|
||||
try {
|
||||
System.gc(); // enqueue finalizable objects
|
||||
new Object() { protected void finalize() {
|
||||
drained.countDown(); }};
|
||||
System.gc(); // enqueue detector
|
||||
drained.await(); // wait for finalizer queue to drain
|
||||
System.gc(); // cleanup finalized objects
|
||||
} catch (InterruptedException e) { throw new Error(e); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs each job for long enough that all the runtime compilers
|
||||
* have had plenty of time to warm up, i.e. get around to
|
||||
* compiling everything worth compiling.
|
||||
* Returns array of average times per job per run.
|
||||
*/
|
||||
private static long[] time0(Job ... jobs) throws Throwable {
|
||||
final long warmupNanos = 10L * 1000L * 1000L * 1000L;
|
||||
long[] nanoss = new long[jobs.length];
|
||||
for (int i = 0; i < jobs.length; i++) {
|
||||
collectAllGarbage();
|
||||
long t0 = System.nanoTime();
|
||||
long t;
|
||||
int j = 0;
|
||||
do { jobs[i].work(); j++; }
|
||||
while ((t = System.nanoTime() - t0) < warmupNanos);
|
||||
nanoss[i] = t/j;
|
||||
}
|
||||
return nanoss;
|
||||
}
|
||||
|
||||
private static void time(Job ... jobs) throws Throwable {
|
||||
|
||||
long[] warmup = time0(jobs); // Warm up run
|
||||
long[] nanoss = time0(jobs); // Real timing run
|
||||
long[] milliss = new long[jobs.length];
|
||||
double[] ratios = new double[jobs.length];
|
||||
|
||||
final String nameHeader = "Method";
|
||||
final String millisHeader = "Millis";
|
||||
final String ratioHeader = "Ratio";
|
||||
|
||||
int nameWidth = nameHeader.length();
|
||||
int millisWidth = millisHeader.length();
|
||||
int ratioWidth = ratioHeader.length();
|
||||
|
||||
for (int i = 0; i < jobs.length; i++) {
|
||||
nameWidth = Math.max(nameWidth, jobs[i].name().length());
|
||||
|
||||
milliss[i] = nanoss[i]/(1000L * 1000L);
|
||||
millisWidth = Math.max(millisWidth,
|
||||
String.format("%d", milliss[i]).length());
|
||||
|
||||
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
|
||||
ratioWidth = Math.max(ratioWidth,
|
||||
String.format("%.3f", ratios[i]).length());
|
||||
}
|
||||
|
||||
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
|
||||
nameWidth, millisWidth, ratioWidth);
|
||||
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
|
||||
nameWidth, millisWidth, ratioWidth);
|
||||
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
|
||||
|
||||
// Print out absolute and relative times, calibrated against first job
|
||||
for (int i = 0; i < jobs.length; i++)
|
||||
System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
|
||||
}
|
||||
|
||||
private static String keywordValue(String[] args, String keyword) {
|
||||
for (String arg : args)
|
||||
if (arg.startsWith(keyword))
|
||||
return arg.substring(keyword.length() + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int intArg(String[] args, String keyword, int defaultValue) {
|
||||
String val = keywordValue(args, keyword);
|
||||
return val == null ? defaultValue : Integer.parseInt(val);
|
||||
}
|
||||
|
||||
private static Pattern patternArg(String[] args, String keyword) {
|
||||
String val = keywordValue(args, keyword);
|
||||
return val == null ? null : Pattern.compile(val);
|
||||
}
|
||||
|
||||
private static Job[] filter(Pattern filter, Job[] jobs) {
|
||||
if (filter == null) return jobs;
|
||||
Job[] newJobs = new Job[jobs.length];
|
||||
int n = 0;
|
||||
for (Job job : jobs)
|
||||
if (filter.matcher(job.name()).find())
|
||||
newJobs[n++] = job;
|
||||
// Arrays.copyOf not available in JDK 5
|
||||
Job[] ret = new Job[n];
|
||||
System.arraycopy(newJobs, 0, ret, 0, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void deoptimize(int sum) {
|
||||
if (sum == 42)
|
||||
System.out.println("the answer");
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage: [iterations=N] [size=N] [filter=REGEXP]
|
||||
*/
|
||||
public static void main(String[] args) throws Throwable {
|
||||
final int iterations = intArg(args, "iterations", 10000);
|
||||
final int size = intArg(args, "size", 1024);
|
||||
final Pattern filter = patternArg(args, "filter");
|
||||
|
||||
final Random rnd = new Random();
|
||||
|
||||
final ByteBuffer b = ByteBuffer.allocateDirect(8*size);
|
||||
for (int i = 0; i < b.limit(); i++)
|
||||
b.put(i, (byte) rnd.nextInt());
|
||||
|
||||
Job[] jobs = {
|
||||
new Job("swap char BIG_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.BIG_ENDIAN);
|
||||
CharBuffer x = b.asCharBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}},
|
||||
new Job("swap char LITTLE_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
CharBuffer x = b.asCharBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}},
|
||||
new Job("swap short BIG_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.BIG_ENDIAN);
|
||||
ShortBuffer x = b.asShortBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}},
|
||||
new Job("swap short LITTLE_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
ShortBuffer x = b.asShortBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}},
|
||||
new Job("swap int BIG_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.BIG_ENDIAN);
|
||||
IntBuffer x = b.asIntBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}},
|
||||
new Job("swap int LITTLE_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
IntBuffer x = b.asIntBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}},
|
||||
new Job("swap long BIG_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.BIG_ENDIAN);
|
||||
LongBuffer x = b.asLongBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}},
|
||||
new Job("swap long LITTLE_ENDIAN") {
|
||||
public void work() throws Throwable {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
LongBuffer x = b.asLongBuffer();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
int sum = 0;
|
||||
for (int j = 0, end = x.limit(); j < end; j++)
|
||||
sum += x.get(j);
|
||||
deoptimize(sum);}}}
|
||||
};
|
||||
|
||||
time(filter(filter, jobs));
|
||||
}
|
||||
}
|
||||
75
test/jdk/java/nio/Buffer/UnmeteredTempBuffers.java
Normal file
75
test/jdk/java/nio/Buffer/UnmeteredTempBuffers.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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
|
||||
* @bug 8344882
|
||||
* @summary Deallocation failure for temporary buffers
|
||||
* @run junit/othervm -XX:MaxDirectMemorySize=32768 UnmeteredTempBuffers
|
||||
*/
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class UnmeteredTempBuffers {
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {16384, 32768, 32769, 65536})
|
||||
void testFileChannel(int cap) throws IOException {
|
||||
Path file = Files.createTempFile("prefix", "suffix");
|
||||
try (FileChannel ch = FileChannel.open(file, WRITE, DELETE_ON_CLOSE)) {
|
||||
ByteBuffer buf = ByteBuffer.wrap(new byte[cap]);
|
||||
try {
|
||||
ch.write(buf);
|
||||
} catch (OutOfMemoryError oome) {
|
||||
throw new RuntimeException(oome);
|
||||
}
|
||||
} finally {
|
||||
Files.deleteIfExists(file);
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {16384, 32768, 32769, 65536})
|
||||
void testInputStream(int cap) throws IOException {
|
||||
Path file = Files.createTempFile("prefix", "suffix");
|
||||
try {
|
||||
byte[] bytes = new byte[cap];
|
||||
Files.write(file, bytes);
|
||||
try (InputStream in = Files.newInputStream(file)) {
|
||||
in.read(bytes);
|
||||
} catch (OutOfMemoryError oome) {
|
||||
throw new RuntimeException(oome);
|
||||
}
|
||||
} finally {
|
||||
Files.delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
test/jdk/java/nio/Buffer/genBasic.sh
Normal file
40
test/jdk/java/nio/Buffer/genBasic.sh
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#! /bin/sh
|
||||
|
||||
#
|
||||
# Copyright (c) 2000, 2019, 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.
|
||||
#
|
||||
|
||||
javac -d . ../../../../../make/jdk/src/classes/build/tools/spp/Spp.java
|
||||
|
||||
gen() {
|
||||
out=Basic$2.java
|
||||
rm -f $out
|
||||
java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3 -iBasic-X.java.template -o$out
|
||||
}
|
||||
|
||||
gen byte Byte Byte
|
||||
gen char Char Character
|
||||
gen short Short Short
|
||||
gen int Int Integer
|
||||
gen long Long Long
|
||||
gen float Float Float
|
||||
gen double Double Double
|
||||
42
test/jdk/java/nio/Buffer/genCopyDirectMemory.sh
Normal file
42
test/jdk/java/nio/Buffer/genCopyDirectMemory.sh
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#! /bin/sh
|
||||
|
||||
#
|
||||
# Copyright (c) 2002, 2019, 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.
|
||||
#
|
||||
|
||||
javac -d . ../../../../../make/jdk/src/classes/build/tools/spp/Spp.java
|
||||
|
||||
gen() {
|
||||
out=CopyDirect$2Memory.java
|
||||
rm -f $out
|
||||
java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3 -iCopyDirect-X-Memory.java.template -o$out
|
||||
}
|
||||
|
||||
gen byte Byte Byte
|
||||
gen char Char Character
|
||||
gen short Short Short
|
||||
gen int Int Integer
|
||||
gen long Long Long
|
||||
gen float Float Float
|
||||
gen double Double Double
|
||||
|
||||
rm -rf build
|
||||
40
test/jdk/java/nio/Buffer/genOrder.sh
Normal file
40
test/jdk/java/nio/Buffer/genOrder.sh
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#! /bin/sh
|
||||
|
||||
#
|
||||
# Copyright (c) 2002, 2019, 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.
|
||||
#
|
||||
|
||||
javac -d . ../../../../../make/jdk/src/classes/build/tools/spp/Spp.java
|
||||
gen() {
|
||||
out=Order$2.java
|
||||
rm -f $out
|
||||
java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3 -iOrder-X.java.template -o$out
|
||||
}
|
||||
|
||||
gen char Char Character
|
||||
gen short Short Short
|
||||
gen int Int Integer
|
||||
gen long Long Long
|
||||
gen float Float Float
|
||||
gen double Double Double
|
||||
|
||||
rm -rf build
|
||||
49
test/jdk/java/nio/ByteOrder/NativeOrder.java
Normal file
49
test/jdk/java/nio/ByteOrder/NativeOrder.java
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2020, 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
|
||||
* @summary Unit test for ByteOrder.nativeOrder()
|
||||
*/
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
|
||||
public class NativeOrder {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ByteOrder bo = ByteOrder.nativeOrder();
|
||||
System.err.println("ByteOrder.nativeOrder:" + bo);
|
||||
String arch = System.getProperty("os.arch");
|
||||
System.err.println("os.arch:" + arch);
|
||||
if (((arch.equals("i386") && (bo != ByteOrder.LITTLE_ENDIAN))) ||
|
||||
((arch.equals("amd64") && (bo != ByteOrder.LITTLE_ENDIAN))) ||
|
||||
((arch.equals("x86_64") && (bo != ByteOrder.LITTLE_ENDIAN))) ||
|
||||
((arch.equals("ppc64") && (bo != ByteOrder.BIG_ENDIAN))) ||
|
||||
((arch.equals("ppc64le") && (bo != ByteOrder.LITTLE_ENDIAN))) ||
|
||||
((arch.equals("s390x") && (bo != ByteOrder.BIG_ENDIAN)))) {
|
||||
throw new Exception("Wrong byte order");
|
||||
}
|
||||
System.err.println("test is OK");
|
||||
}
|
||||
|
||||
}
|
||||
84
test/jdk/java/nio/MappedByteBuffer/Basic.java
Normal file
84
test/jdk/java/nio/MappedByteBuffer/Basic.java
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2010, 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
|
||||
* @bug 4462336 6799037
|
||||
* @summary Simple MappedByteBuffer tests
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
public class Basic {
|
||||
public static void main(String[] args) throws Exception {
|
||||
byte[] srcData = new byte[20];
|
||||
for (int i=0; i<20; i++)
|
||||
srcData[i] = 3;
|
||||
File blah = File.createTempFile("blah", null);
|
||||
blah.deleteOnExit();
|
||||
FileOutputStream fos = new FileOutputStream(blah);
|
||||
FileChannel fc = fos.getChannel();
|
||||
fc.write(ByteBuffer.wrap(srcData));
|
||||
fc.close();
|
||||
fos.close();
|
||||
|
||||
FileInputStream fis = new FileInputStream(blah);
|
||||
fc = fis.getChannel();
|
||||
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
|
||||
mbb.load();
|
||||
mbb.isLoaded();
|
||||
mbb.force();
|
||||
if (!mbb.isReadOnly())
|
||||
throw new RuntimeException("Incorrect isReadOnly");
|
||||
|
||||
// repeat with unaligned position in file
|
||||
mbb = fc.map(FileChannel.MapMode.READ_ONLY, 1, 10);
|
||||
mbb.load();
|
||||
mbb.isLoaded();
|
||||
mbb.force();
|
||||
fc.close();
|
||||
fis.close();
|
||||
|
||||
RandomAccessFile raf = new RandomAccessFile(blah, "r");
|
||||
fc = raf.getChannel();
|
||||
mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
|
||||
if (!mbb.isReadOnly())
|
||||
throw new RuntimeException("Incorrect isReadOnly");
|
||||
fc.close();
|
||||
raf.close();
|
||||
|
||||
raf = new RandomAccessFile(blah, "rw");
|
||||
fc = raf.getChannel();
|
||||
mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 10);
|
||||
if (mbb.isReadOnly())
|
||||
throw new RuntimeException("Incorrect isReadOnly");
|
||||
fc.close();
|
||||
raf.close();
|
||||
|
||||
// clean-up
|
||||
mbb = null;
|
||||
System.gc();
|
||||
Thread.sleep(500);
|
||||
}
|
||||
}
|
||||
75
test/jdk/java/nio/MappedByteBuffer/Force.java
Normal file
75
test/jdk/java/nio/MappedByteBuffer/Force.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2020, 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
|
||||
* @bug 4625907 8246729
|
||||
* @summary Testing force()
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run main/othervm Force
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import java.util.Random;
|
||||
import jdk.test.lib.RandomFactory;
|
||||
|
||||
public class Force {
|
||||
public static void main(String[] args) throws Exception {
|
||||
test1();
|
||||
test2();
|
||||
}
|
||||
|
||||
private static void test1() throws Exception {
|
||||
Random random = RandomFactory.getRandom();
|
||||
long filesize = random.nextInt(3*1024*1024);
|
||||
int cut = random.nextInt((int)filesize);
|
||||
File file = File.createTempFile("Blah", null);
|
||||
file.deleteOnExit();
|
||||
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
|
||||
raf.setLength(filesize);
|
||||
FileChannel fc = raf.getChannel();
|
||||
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, cut, filesize-cut);
|
||||
mbb.force();
|
||||
}
|
||||
|
||||
// improve chance that mapped buffer will be unmapped
|
||||
System.gc();
|
||||
Thread.sleep(500);
|
||||
}
|
||||
|
||||
private static void test2() throws Exception {
|
||||
var path = Files.createTempFile("test", "map");
|
||||
var channel = FileChannel.open(path, READ, WRITE);
|
||||
MappedByteBuffer buffer =
|
||||
channel.map(FileChannel.MapMode.READ_WRITE, 0, 1000);
|
||||
buffer.putInt(1234);
|
||||
buffer.limit(4);
|
||||
buffer.force();
|
||||
}
|
||||
}
|
||||
75
test/jdk/java/nio/MappedByteBuffer/ForceException.java
Normal file
75
test/jdk/java/nio/MappedByteBuffer/ForceException.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
* @bug 6539707
|
||||
* @summary Test behavior of force() with respect to throwing exceptions
|
||||
* @run main ForceException
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
public class ForceException {
|
||||
public static void main(String[] args) throws IOException {
|
||||
int blockSize = 2048 * 1024;
|
||||
int numberOfBlocks = 200;
|
||||
int fileLength = numberOfBlocks * blockSize;
|
||||
|
||||
File file = new File(".", "test.dat");
|
||||
file.deleteOnExit();
|
||||
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
|
||||
raf.setLength(fileLength);
|
||||
|
||||
int pos = (numberOfBlocks - 1) * blockSize;
|
||||
int size = (int)Math.min(blockSize, fileLength - pos);
|
||||
MappedByteBuffer mbb =
|
||||
raf.getChannel().map(FileChannel.MapMode.READ_WRITE, pos, size);
|
||||
|
||||
System.out.printf("Write region 0x%s..0x%s%n",
|
||||
Long.toHexString(pos), Long.toHexString(size));
|
||||
for (int k = 0; k < mbb.limit(); k++) {
|
||||
mbb.put(k, (byte)65);
|
||||
}
|
||||
|
||||
// Catch and process UncheckedIOException; other Throwables fail
|
||||
try {
|
||||
System.out.println("Force");
|
||||
mbb.force();
|
||||
} catch (UncheckedIOException legal) {
|
||||
System.out.printf("Caught legal exception %s%n", legal);
|
||||
IOException cause = legal.getCause(); // can't be null
|
||||
// Throw the cause if flush failed (should be only on Windows)
|
||||
if (cause.getMessage().startsWith("Flush failed")) {
|
||||
throw cause;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
106
test/jdk/java/nio/MappedByteBuffer/ForceViews.java
Normal file
106
test/jdk/java/nio/MappedByteBuffer/ForceViews.java
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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
|
||||
* @bug 4833719
|
||||
* @summary Verify MappedByteBuffer force on compact, duplicate, and slice views
|
||||
* @run junit ForceViews
|
||||
*/
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.nio.channels.FileChannel.MapMode.*;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ForceViews {
|
||||
|
||||
static record Segment(int position, int length) {}
|
||||
|
||||
public static Stream<Arguments> provider() throws IOException {
|
||||
BiFunction<MappedByteBuffer,Segment,MappedByteBuffer> absSlice =
|
||||
(m, s) -> { return m.slice(s.position, s.length); };
|
||||
BiFunction<MappedByteBuffer,Segment,MappedByteBuffer> relSlice =
|
||||
(m, s) -> { m.position(s.position); m.limit(s.position + s.length);
|
||||
return m.slice(); };
|
||||
BiFunction<MappedByteBuffer,Segment,MappedByteBuffer> duplicate=
|
||||
(m, s) -> { return m.duplicate(); };
|
||||
BiFunction<MappedByteBuffer,Segment,MappedByteBuffer> compact =
|
||||
(m, s) -> { return m.compact(); };
|
||||
|
||||
return Stream.of
|
||||
(Arguments.of("Absolute slice", 256, 512, 128, 128, 32, 32, absSlice),
|
||||
Arguments.of("Relative slice", 256, 512, 0, 128, 32, 32, relSlice),
|
||||
Arguments.of("Duplicate", 256, 512, 0, 256, 32, 32, duplicate),
|
||||
Arguments.of("Compact", 256, 512, 0, 256, 32, 32, compact));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provider")
|
||||
public void test(String tst, int mapPosition, int mapLength,
|
||||
int sliceIndex, int sliceLength, int regionOffset,
|
||||
int regionLength,
|
||||
BiFunction<MappedByteBuffer,Segment,MappedByteBuffer> f)
|
||||
throws Exception {
|
||||
|
||||
Path file = Path.of(".", "junk");
|
||||
try (FileChannel fc = FileChannel.open(file, CREATE, READ, WRITE, DELETE_ON_CLOSE)) {
|
||||
fc.write(ByteBuffer.wrap(new byte[1024]));
|
||||
fc.position(0);
|
||||
|
||||
MappedByteBuffer mbb = fc.map(READ_WRITE, mapPosition, mapLength);
|
||||
mbb = f.apply(mbb, new Segment(sliceIndex, sliceLength));
|
||||
for (int i = regionOffset; i < regionOffset + regionLength; i++) {
|
||||
mbb.put(i, (byte)i);
|
||||
}
|
||||
mbb.force(regionOffset, regionOffset + regionLength);
|
||||
|
||||
int fcPos = mapPosition + sliceIndex + regionOffset;
|
||||
int mbbPos = regionOffset;
|
||||
int length = regionLength;
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(length);
|
||||
fc.position(fcPos);
|
||||
fc.read(buf);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int fcVal = buf.get(i);
|
||||
int mbbVal = mbb.get(mbbPos + i);
|
||||
int val = regionOffset + i;
|
||||
assertEquals(val, fcVal);
|
||||
assertEquals(val, mbbVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
81
test/jdk/java/nio/MappedByteBuffer/MapSyncFail.java
Normal file
81
test/jdk/java/nio/MappedByteBuffer/MapSyncFail.java
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* @summary Test failure paths for MAP_SYNC FileChannel.map of non-DAX files
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @run main MapSyncFail true
|
||||
* @run main MapSyncFail false
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.nio.channels.*;
|
||||
import jdk.nio.mapmode.*;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
public class MapSyncFail {
|
||||
|
||||
public static final int K = 1024;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length != 1) {
|
||||
throw new Exception("Expected true or false as argument");
|
||||
}
|
||||
boolean is_rw = Boolean.valueOf(args[0]);
|
||||
FileChannel.MapMode mode = (is_rw ? ExtendedMapMode.READ_WRITE_SYNC : ExtendedMapMode.READ_ONLY_SYNC);
|
||||
// it is assumed that /tmp is not a DAX file system
|
||||
File file = File.createTempFile("MapSyncFail", null);
|
||||
file.deleteOnExit();
|
||||
long filesize = (8 * K);
|
||||
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
|
||||
raf.setLength(filesize);
|
||||
FileChannel fc = raf.getChannel();
|
||||
MappedByteBuffer mbb = fc.map(mode, 0, filesize);
|
||||
} catch(IOException ioe) {
|
||||
// when writeback is enabled for the current os/cpu
|
||||
// combination the underlying mmap should be attempted and
|
||||
// the map call should fail with IOException
|
||||
if (!Unsafe.isWritebackEnabled()) {
|
||||
throw new Exception("IOException not expected");
|
||||
}
|
||||
System.out.println("caught " + ioe);
|
||||
ioe.printStackTrace();
|
||||
return;
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// when writeback is not enabled for the current os/cpu
|
||||
// combination the mmap should not be attempted and the
|
||||
// map call should fail with UnsupportedOperationException
|
||||
|
||||
if (Unsafe.isWritebackEnabled()) {
|
||||
throw new Exception("UnsupportedOperationException not expected");
|
||||
}
|
||||
System.out.println("caught " + uoe);
|
||||
uoe.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception("expected IOException or UnsupportedOperationException");
|
||||
}
|
||||
}
|
||||
175
test/jdk/java/nio/MappedByteBuffer/PmemTest.java
Normal file
175
test/jdk/java/nio/MappedByteBuffer/PmemTest.java
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2025, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This test is manually run because it requires an NVRAM device to be
|
||||
* mapped as DAX file system or, at least, to be simulated by a
|
||||
* volatile RAM mapped file system. Also, on AArch64 it requires an
|
||||
* ARMV8.2 CPU which implements the dc CVAP instruction (CPU feature
|
||||
* dcpop) and an OS that makes it available from user space.
|
||||
*
|
||||
* If the test runs on such a host without throwing an exception then
|
||||
* that confirms that NVRAM-backed byte buffers can be allocated,
|
||||
* updated and forced via cache line writeback.
|
||||
*/
|
||||
|
||||
/*
|
||||
* How to run this test:
|
||||
*
|
||||
* Ideally this test should be run on a x86_64/amd64 or aarch64 host
|
||||
* fitted with an NVRAM memory device. The NVRAM should appear as
|
||||
* /dev/pmem0 or some equivalent DAX file device. The file device
|
||||
* should be mounted at /mnt/pmem with a directory tmp created
|
||||
* directly under that mount point with a+rwx access.
|
||||
*
|
||||
* It is possible to run the test on x86_64 using a volatile RAM
|
||||
* backed device to simulate NVRAM, even though this does not provide
|
||||
* any guarantee of persistence of data across program runs. For the
|
||||
* latter case the following instructions explain how to set up the
|
||||
* simulated NVRAM device.
|
||||
*
|
||||
* https://developers.redhat.com/blog/2016/12/05/configuring-and-using-persistent-memory-rhel-7-3/
|
||||
* https://nvdimm.wiki.kernel.org/
|
||||
* TL;DR: add "memmap=1G!4G" to /etc/default/grub, eg. GRUB_CMDLINE_LINUX="memmap=1G!4G"
|
||||
* then ("sudo" may required)
|
||||
* for RHEL(BIOS-based): grub2-mkconfig -o /boot/grub2/grub.cfg
|
||||
* for RHEL(UEFI-based): grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
|
||||
* for Ubuntu: update-grub2
|
||||
* finally reboot
|
||||
* after the host been rebooted, a new /dev/pmem{N} device should exist,
|
||||
* naming conversion starts at /dev/pmem0
|
||||
*
|
||||
* Prepare test directory follow below commands, "sudo" may required
|
||||
* (if ndctl or mkfs.xfs not exist, install ndctl or xfsprogs package first)
|
||||
* (for RHEL8, when call mkfs.xfs, specify the -m reflink=0 option to disable reflink feature)
|
||||
*
|
||||
* ndctl create-namespace -f -e namespace0.0 -m memory -M mem
|
||||
* mkdir /mnt/pmem
|
||||
* mkfs.xfs -f /dev/pmem0; mount -o dax /dev/pmem0 /mnt/pmem/
|
||||
* mkdir /mnt/pmem/test; chmod a+rwx /mnt/pmem/test
|
||||
*
|
||||
* Now run the test program
|
||||
*
|
||||
* java PmemTest
|
||||
*
|
||||
* or
|
||||
*
|
||||
* make test TEST=jdk/java/nio/MappedByteBuffer/PmemTest.java
|
||||
*/
|
||||
|
||||
/* @test id=default_architecture_test_case
|
||||
* @summary Testing NVRAM mapped byte buffer support
|
||||
* @run main/manual PmemTest
|
||||
* @requires (os.family == "linux")
|
||||
* @requires ((os.arch == "x86_64")|(os.arch == "amd64"))
|
||||
*/
|
||||
|
||||
/* @test id=other_architectures_test_case
|
||||
* @summary Testing NVRAM mapped byte buffer support
|
||||
* @run main/manual PmemTest
|
||||
* @requires (os.family == "linux")
|
||||
* @requires ((os.arch == "aarch64")|(os.arch == "ppc64le"))
|
||||
* @ignore The test described here is currently disabled on systems that are not
|
||||
* x64-based and lack an external NVRAM memory device. In order to re-enable the
|
||||
* test, you will need to mount the NVRAM device, which will typically appear as
|
||||
* /dev/pmem0, to the directory /mnt/pmem. Once that is done, you can follow the
|
||||
* instructions above to create a test directory and remove the ignore tag.
|
||||
*/
|
||||
import java.io.File;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import jdk.nio.mapmode.ExtendedMapMode;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.BufferPoolMXBean;
|
||||
|
||||
public class PmemTest {
|
||||
|
||||
public static final int K = 1024;
|
||||
public static final int NUM_KBS = 16;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
System.out.println("test");
|
||||
|
||||
String dir = "/tmp"; // mapSync should fail
|
||||
dir = "/mnt/pmem/test"; // mapSync should work, since fs mount is -o dax
|
||||
|
||||
Path path = new File(dir, "pmemtest").toPath();
|
||||
|
||||
FileChannel fileChannel = (FileChannel) Files
|
||||
.newByteChannel(path, EnumSet.of(
|
||||
StandardOpenOption.READ,
|
||||
StandardOpenOption.WRITE,
|
||||
StandardOpenOption.CREATE));
|
||||
|
||||
MappedByteBuffer mappedByteBuffer = fileChannel.map(ExtendedMapMode.READ_WRITE_SYNC, 0, NUM_KBS * K);
|
||||
|
||||
|
||||
dumpBufferPoolBeans();
|
||||
|
||||
// for (int loops = 0; loops < 1000; loops++) {
|
||||
for (int loops = 0; loops < 100; loops++) {
|
||||
int base = K * (loops % NUM_KBS);
|
||||
for (int i = 0; i < K ; i++) {
|
||||
for (int j = 0; j < K ;j++) {
|
||||
testBuffer(mappedByteBuffer, base, (i << 3) + j);
|
||||
commitBuffer(mappedByteBuffer, base);
|
||||
}
|
||||
}
|
||||
}
|
||||
dumpBufferPoolBeans();
|
||||
}
|
||||
|
||||
public static void testBuffer(MappedByteBuffer mappedByteBuffer, int base, int start) {
|
||||
for (int k = 0; k < 8; k++) {
|
||||
int idx = (start + k) % K;
|
||||
byte z = mappedByteBuffer.get(base + idx);
|
||||
z++;
|
||||
mappedByteBuffer.put(base + idx, z);
|
||||
}
|
||||
}
|
||||
|
||||
public static void commitBuffer(MappedByteBuffer mappedByteBuffer, int base)
|
||||
{
|
||||
mappedByteBuffer.force(base, K);
|
||||
}
|
||||
|
||||
public static void dumpBufferPoolBeans()
|
||||
{
|
||||
List<BufferPoolMXBean> beansList = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
|
||||
for (BufferPoolMXBean bean : beansList) {
|
||||
System.out.println("BufferPoolMXBean {" +
|
||||
"\n\tname: " + bean.getName() +
|
||||
"\n\tcount: " + bean.getCount() +
|
||||
"\n\ttotalCapacity: " + bean.getTotalCapacity() +
|
||||
"\n\tmemoryUsed: " + bean.getMemoryUsed() +
|
||||
"\n}");
|
||||
}
|
||||
}
|
||||
}
|
||||
52
test/jdk/java/nio/MappedByteBuffer/SubclassCastUOE.java
Normal file
52
test/jdk/java/nio/MappedByteBuffer/SubclassCastUOE.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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
|
||||
* @bug 8191416
|
||||
* @summary Verify no UnsupportedOperationException for cast subclass
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
|
||||
public class SubclassCastUOE {
|
||||
public static void main(String[] args) throws Exception {
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(37);
|
||||
|
||||
if (!(buf instanceof MappedByteBuffer)) {
|
||||
throw new RuntimeException("Direct buffer not a MappedByteBuffer");
|
||||
}
|
||||
|
||||
if (((MappedByteBuffer)buf).load() != buf) {
|
||||
throw new RuntimeException("load() did not return same buffer");
|
||||
}
|
||||
|
||||
if (!((MappedByteBuffer)buf).isLoaded()) {
|
||||
throw new RuntimeException("isLoaded() returned false");
|
||||
}
|
||||
|
||||
if (((MappedByteBuffer)buf).force() != buf) {
|
||||
throw new RuntimeException("force() did not return same buffer");
|
||||
}
|
||||
}
|
||||
}
|
||||
99
test/jdk/java/nio/MappedByteBuffer/Truncate.java
Normal file
99
test/jdk/java/nio/MappedByteBuffer/Truncate.java
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 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
|
||||
* @bug 6934977
|
||||
* @summary Test MappedByteBuffer operations after mapped bye buffer becomes
|
||||
* inaccessible
|
||||
* @run main/othervm Truncate
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class Truncate {
|
||||
|
||||
static final long INITIAL_FILE_SIZE = 32000L;
|
||||
static final long TRUNCATED_FILE_SIZE = 512L;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
File blah = File.createTempFile("blah", null);
|
||||
blah.deleteOnExit();
|
||||
|
||||
final FileChannel fc = new RandomAccessFile(blah, "rw").getChannel();
|
||||
fc.position(INITIAL_FILE_SIZE).write(ByteBuffer.wrap("THE END".getBytes()));
|
||||
final MappedByteBuffer mbb =
|
||||
fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
|
||||
boolean truncated;
|
||||
try {
|
||||
fc.truncate(TRUNCATED_FILE_SIZE);
|
||||
truncated = true;
|
||||
} catch (IOException ioe) {
|
||||
// probably on Windows where a file cannot be truncated when
|
||||
// there is a file mapping.
|
||||
truncated = false;
|
||||
}
|
||||
if (truncated) {
|
||||
// Test 1: access region that is no longer accessible
|
||||
execute(new Callable<Void>() {
|
||||
public Void call() {
|
||||
mbb.get((int)TRUNCATED_FILE_SIZE + 1);
|
||||
mbb.put((int)TRUNCATED_FILE_SIZE + 2, (byte)123);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
// Test 2: load buffer into memory
|
||||
execute(new Callable<Void>() {
|
||||
public Void call() throws IOException {
|
||||
mbb.load();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
fc.close();
|
||||
}
|
||||
|
||||
// Runs the given task in its own thread. If operating correcting the
|
||||
// the thread will terminate with an InternalError as the mapped buffer
|
||||
// is inaccessible.
|
||||
static void execute(final Callable<?> c) {
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Object ignore = c.call();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
};
|
||||
Thread t = new Thread(r);
|
||||
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
try { t.join(); } catch (InterruptedException ignore) { }
|
||||
}
|
||||
}
|
||||
56
test/jdk/java/nio/MappedByteBuffer/ZeroMap.java
Normal file
56
test/jdk/java/nio/MappedByteBuffer/ZeroMap.java
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2011, 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
|
||||
* @bug 4802340
|
||||
* @summary Testing force(), load() isLoaded() of zero len MBB
|
||||
* @run main/othervm ZeroMap
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
public class ZeroMap {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Random random = new Random();
|
||||
long filesize = random.nextInt(1024*1024);
|
||||
int cut = random.nextInt((int)filesize);
|
||||
File file = File.createTempFile("Blah", null);
|
||||
file.deleteOnExit();
|
||||
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
|
||||
raf.setLength(filesize);
|
||||
FileChannel fc = raf.getChannel();
|
||||
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, cut, 0);
|
||||
mbb.force();
|
||||
mbb.load();
|
||||
mbb.isLoaded();
|
||||
}
|
||||
|
||||
// improve chance that mapped buffer will be unmapped
|
||||
System.gc();
|
||||
Thread.sleep(500);
|
||||
}
|
||||
}
|
||||
785
test/jdk/java/nio/channels/AsyncCloseAndInterrupt.java
Normal file
785
test/jdk/java/nio/channels/AsyncCloseAndInterrupt.java
Normal file
|
|
@ -0,0 +1,785 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 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
|
||||
* @bug 4460583 4470470 4840199 6419424 6710579 6596323 6824135 6395224 7142919
|
||||
* 8151582 8068693 8153209
|
||||
* @library /test/lib
|
||||
* @run main/othervm --enable-native-access=ALL-UNNAMED AsyncCloseAndInterrupt
|
||||
* @key intermittent
|
||||
* @summary Comprehensive test of asynchronous closing and interruption
|
||||
* @author Mark Reinhold
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.lang.foreign.Arena;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.Linker;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.SymbolLookup;
|
||||
import java.lang.foreign.ValueLayout;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
public class AsyncCloseAndInterrupt {
|
||||
|
||||
static PrintStream log = System.err;
|
||||
|
||||
static void sleep(int ms) {
|
||||
try {
|
||||
Thread.sleep(ms);
|
||||
} catch (InterruptedException x) { }
|
||||
}
|
||||
|
||||
private static int mkfifo(String path) throws Throwable {
|
||||
Linker linker = Linker.nativeLinker();
|
||||
SymbolLookup stdlib = linker.defaultLookup();
|
||||
MethodHandle mkfifo = linker.downcallHandle(
|
||||
stdlib.find("mkfifo").orElseThrow(),
|
||||
FunctionDescriptor.of(ValueLayout.JAVA_INT,
|
||||
ValueLayout.ADDRESS, ValueLayout.JAVA_INT)
|
||||
);
|
||||
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment cString = arena.allocateFrom(path);
|
||||
int mode = 0666;
|
||||
int returnValue = (int)mkfifo.invokeExact(cString, mode);
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Wildcard address localized to this machine -- Windoze doesn't allow
|
||||
// connecting to a server socket that was previously bound to a true
|
||||
// wildcard, namely new InetSocketAddress((InetAddress)null, 0).
|
||||
//
|
||||
private static InetSocketAddress wildcardAddress;
|
||||
|
||||
|
||||
// Server socket that blindly accepts all connections
|
||||
|
||||
static ServerSocketChannel acceptor;
|
||||
|
||||
private static void initAcceptor() throws IOException {
|
||||
acceptor = ServerSocketChannel.open();
|
||||
acceptor.socket().bind(wildcardAddress);
|
||||
|
||||
Thread th = new Thread("Acceptor") {
|
||||
public void run() {
|
||||
try {
|
||||
for (;;) {
|
||||
SocketChannel sc = acceptor.accept();
|
||||
}
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
th.setDaemon(true);
|
||||
th.start();
|
||||
}
|
||||
|
||||
|
||||
// Server socket that refuses all connections
|
||||
|
||||
static ServerSocketChannel refuser;
|
||||
|
||||
private static void initRefuser() throws IOException {
|
||||
refuser = ServerSocketChannel.open();
|
||||
refuser.bind(wildcardAddress, 1); // use minimum backlog
|
||||
}
|
||||
|
||||
// Dead pipe source and sink
|
||||
|
||||
static Pipe.SourceChannel deadSource;
|
||||
static Pipe.SinkChannel deadSink;
|
||||
|
||||
private static void initPipes() throws IOException {
|
||||
if (deadSource != null)
|
||||
deadSource.close();
|
||||
deadSource = Pipe.open().source();
|
||||
if (deadSink != null)
|
||||
deadSink.close();
|
||||
deadSink = Pipe.open().sink();
|
||||
}
|
||||
|
||||
|
||||
// Files
|
||||
|
||||
private static File fifoFile = null; // File that blocks on reads and writes
|
||||
private static File diskFile = null; // Disk file
|
||||
|
||||
private static void initFile() throws Exception {
|
||||
|
||||
diskFile = File.createTempFile("aci", ".tmp");
|
||||
diskFile.deleteOnExit();
|
||||
FileChannel fc = new FileOutputStream(diskFile).getChannel();
|
||||
buffer.clear();
|
||||
if (fc.write(buffer) != buffer.capacity())
|
||||
throw new RuntimeException("Cannot create disk file");
|
||||
fc.close();
|
||||
|
||||
if (TestUtil.onWindows()) {
|
||||
log.println("WARNING: Cannot completely test FileChannels on Windows");
|
||||
return;
|
||||
}
|
||||
fifoFile = new File("x.fifo");
|
||||
fifoFile.deleteOnExit();
|
||||
if (fifoFile.exists()) {
|
||||
if (!fifoFile.delete())
|
||||
throw new IOException("Cannot delete existing fifo " + fifoFile);
|
||||
}
|
||||
|
||||
try {
|
||||
if (mkfifo(fifoFile.toString()) != 0) {
|
||||
fifoFile = null;
|
||||
log.println("WARNING: mkfifo failed - cannot completely test FileChannels");
|
||||
return;
|
||||
}
|
||||
} catch (Throwable cause) {
|
||||
throw new IOException(cause);
|
||||
}
|
||||
new RandomAccessFile(fifoFile, "rw").close();
|
||||
}
|
||||
|
||||
|
||||
// Channel factories
|
||||
|
||||
static abstract class ChannelFactory {
|
||||
private final String name;
|
||||
ChannelFactory(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
abstract InterruptibleChannel create() throws IOException;
|
||||
}
|
||||
|
||||
static ChannelFactory socketChannelFactory
|
||||
= new ChannelFactory("SocketChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
return SocketChannel.open();
|
||||
}
|
||||
};
|
||||
|
||||
static ChannelFactory connectedSocketChannelFactory
|
||||
= new ChannelFactory("SocketChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
SocketAddress sa = acceptor.socket().getLocalSocketAddress();
|
||||
return SocketChannel.open(sa);
|
||||
}
|
||||
};
|
||||
|
||||
static ChannelFactory serverSocketChannelFactory
|
||||
= new ChannelFactory("ServerSocketChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
ServerSocketChannel ssc = ServerSocketChannel.open();
|
||||
ssc.socket().bind(wildcardAddress);
|
||||
return ssc;
|
||||
}
|
||||
};
|
||||
|
||||
static ChannelFactory datagramChannelFactory
|
||||
= new ChannelFactory("DatagramChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
DatagramChannel dc = DatagramChannel.open();
|
||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||
dc.bind(new InetSocketAddress(lb, 0));
|
||||
dc.connect(new InetSocketAddress(lb, 80));
|
||||
return dc;
|
||||
}
|
||||
};
|
||||
|
||||
static ChannelFactory pipeSourceChannelFactory
|
||||
= new ChannelFactory("Pipe.SourceChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
// ## arrange to close sink
|
||||
return Pipe.open().source();
|
||||
}
|
||||
};
|
||||
|
||||
static ChannelFactory pipeSinkChannelFactory
|
||||
= new ChannelFactory("Pipe.SinkChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
// ## arrange to close source
|
||||
return Pipe.open().sink();
|
||||
}
|
||||
};
|
||||
|
||||
static ChannelFactory fifoFileChannelFactory
|
||||
= new ChannelFactory("FileChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
return new RandomAccessFile(fifoFile, "rw").getChannel();
|
||||
}
|
||||
};
|
||||
|
||||
static ChannelFactory diskFileChannelFactory
|
||||
= new ChannelFactory("FileChannel") {
|
||||
InterruptibleChannel create() throws IOException {
|
||||
return new RandomAccessFile(diskFile, "rw").getChannel();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// I/O operations
|
||||
|
||||
static abstract class Op {
|
||||
private final String name;
|
||||
protected Op(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
abstract void doIO(InterruptibleChannel ich) throws IOException;
|
||||
void setup() throws IOException { }
|
||||
public String toString() { return name; }
|
||||
}
|
||||
|
||||
static ByteBuffer buffer = ByteBuffer.allocateDirect(1 << 20);
|
||||
|
||||
static ByteBuffer[] buffers = new ByteBuffer[] {
|
||||
ByteBuffer.allocateDirect(1 << 19),
|
||||
ByteBuffer.allocateDirect(1 << 19)
|
||||
};
|
||||
|
||||
static void clearBuffers() {
|
||||
buffers[0].clear();
|
||||
buffers[1].clear();
|
||||
}
|
||||
|
||||
static void show(Channel ch) {
|
||||
log.print("Channel " + (ch.isOpen() ? "open" : "closed"));
|
||||
if (ch.isOpen() && (ch instanceof SocketChannel)) {
|
||||
SocketChannel sc = (SocketChannel)ch;
|
||||
if (sc.socket().isInputShutdown())
|
||||
log.print(", input shutdown");
|
||||
if (sc.socket().isOutputShutdown())
|
||||
log.print(", output shutdown");
|
||||
}
|
||||
log.println();
|
||||
}
|
||||
|
||||
static final Op READ = new Op("read") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
ReadableByteChannel rbc = (ReadableByteChannel)ich;
|
||||
buffer.clear();
|
||||
int n = rbc.read(buffer);
|
||||
log.println("Read returned " + n);
|
||||
show(rbc);
|
||||
if (rbc.isOpen()
|
||||
&& (n == -1)
|
||||
&& (rbc instanceof SocketChannel)
|
||||
&& ((SocketChannel)rbc).socket().isInputShutdown()) {
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("Read succeeded");
|
||||
}
|
||||
};
|
||||
|
||||
static final Op READV = new Op("readv") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
ScatteringByteChannel sbc = (ScatteringByteChannel)ich;
|
||||
clearBuffers();
|
||||
int n = (int)sbc.read(buffers);
|
||||
log.println("Read returned " + n);
|
||||
show(sbc);
|
||||
if (sbc.isOpen()
|
||||
&& (n == -1)
|
||||
&& (sbc instanceof SocketChannel)
|
||||
&& ((SocketChannel)sbc).socket().isInputShutdown()) {
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("Read succeeded");
|
||||
}
|
||||
};
|
||||
|
||||
static final Op RECEIVE = new Op("receive") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
DatagramChannel dc = (DatagramChannel)ich;
|
||||
buffer.clear();
|
||||
dc.receive(buffer);
|
||||
show(dc);
|
||||
throw new RuntimeException("Read succeeded");
|
||||
}
|
||||
};
|
||||
|
||||
static final Op WRITE = new Op("write") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
|
||||
WritableByteChannel wbc = (WritableByteChannel)ich;
|
||||
|
||||
SocketChannel sc = null;
|
||||
if (wbc instanceof SocketChannel)
|
||||
sc = (SocketChannel)wbc;
|
||||
|
||||
int n = 0;
|
||||
for (;;) {
|
||||
buffer.clear();
|
||||
int d = wbc.write(buffer);
|
||||
n += d;
|
||||
if (!wbc.isOpen())
|
||||
break;
|
||||
if ((sc != null) && sc.socket().isOutputShutdown())
|
||||
break;
|
||||
}
|
||||
log.println("Wrote " + n + " bytes");
|
||||
show(wbc);
|
||||
}
|
||||
};
|
||||
|
||||
static final Op WRITEV = new Op("writev") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
|
||||
GatheringByteChannel gbc = (GatheringByteChannel)ich;
|
||||
|
||||
SocketChannel sc = null;
|
||||
if (gbc instanceof SocketChannel)
|
||||
sc = (SocketChannel)gbc;
|
||||
|
||||
int n = 0;
|
||||
for (;;) {
|
||||
clearBuffers();
|
||||
int d = (int)gbc.write(buffers);
|
||||
n += d;
|
||||
if (!gbc.isOpen())
|
||||
break;
|
||||
if ((sc != null) && sc.socket().isOutputShutdown())
|
||||
break;
|
||||
}
|
||||
log.println("Wrote " + n + " bytes");
|
||||
show(gbc);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
static final Op CONNECT = new Op("connect") {
|
||||
void setup() {
|
||||
waitPump("connect waiting for pumping refuser ...");
|
||||
}
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
SocketChannel sc = (SocketChannel)ich;
|
||||
if (sc.connect(refuser.socket().getLocalSocketAddress()))
|
||||
throw new RuntimeException("Connection succeeded");
|
||||
throw new RuntimeException("Connection did not block");
|
||||
}
|
||||
};
|
||||
|
||||
static final Op FINISH_CONNECT = new Op("finishConnect") {
|
||||
void setup() {
|
||||
waitPump("finishConnect waiting for pumping refuser ...");
|
||||
}
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
SocketChannel sc = (SocketChannel)ich;
|
||||
sc.configureBlocking(false);
|
||||
SocketAddress sa = refuser.socket().getLocalSocketAddress();
|
||||
if (sc.connect(sa))
|
||||
throw new RuntimeException("Connection succeeded");
|
||||
sc.configureBlocking(true);
|
||||
if (sc.finishConnect())
|
||||
throw new RuntimeException("Connection succeeded");
|
||||
throw new RuntimeException("Connection did not block");
|
||||
}
|
||||
};
|
||||
|
||||
static final Op ACCEPT = new Op("accept") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
ServerSocketChannel ssc = (ServerSocketChannel)ich;
|
||||
ssc.accept();
|
||||
throw new RuntimeException("Accept succeeded");
|
||||
}
|
||||
};
|
||||
|
||||
// Use only with diskFileChannelFactory
|
||||
static final Op TRANSFER_TO = new Op("transferTo") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
FileChannel fc = (FileChannel)ich;
|
||||
long n = fc.transferTo(0, fc.size(), deadSink);
|
||||
log.println("Transferred " + n + " bytes");
|
||||
show(fc);
|
||||
}
|
||||
};
|
||||
|
||||
// Use only with diskFileChannelFactory
|
||||
static final Op TRANSFER_FROM = new Op("transferFrom") {
|
||||
void doIO(InterruptibleChannel ich) throws IOException {
|
||||
FileChannel fc = (FileChannel)ich;
|
||||
long n = fc.transferFrom(deadSource, 0, 1 << 20);
|
||||
log.println("Transferred " + n + " bytes");
|
||||
show(fc);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Test modes
|
||||
|
||||
static final int TEST_PREINTR = 0; // Interrupt thread before I/O
|
||||
static final int TEST_INTR = 1; // Interrupt thread during I/O
|
||||
static final int TEST_CLOSE = 2; // Close channel during I/O
|
||||
static final int TEST_SHUTI = 3; // Shutdown input during I/O
|
||||
static final int TEST_SHUTO = 4; // Shutdown output during I/O
|
||||
|
||||
static final String[] testName = new String[] {
|
||||
"pre-interrupt", "interrupt", "close",
|
||||
"shutdown-input", "shutdown-output"
|
||||
};
|
||||
|
||||
|
||||
static class Tester extends TestThread {
|
||||
|
||||
private InterruptibleChannel ch;
|
||||
private Op op;
|
||||
private int test;
|
||||
volatile boolean ready = false;
|
||||
|
||||
protected Tester(ChannelFactory cf, InterruptibleChannel ch,
|
||||
Op op, int test)
|
||||
{
|
||||
super(cf + "/" + op + "/" + testName[test]);
|
||||
this.ch = ch;
|
||||
this.op = op;
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
private void caught(Channel ch, IOException x) {
|
||||
String xn = x.getClass().getName();
|
||||
switch (test) {
|
||||
|
||||
case TEST_PREINTR:
|
||||
case TEST_INTR:
|
||||
if (!xn.equals("java.nio.channels.ClosedByInterruptException"))
|
||||
throw new RuntimeException("Wrong exception thrown: " + x);
|
||||
break;
|
||||
|
||||
case TEST_CLOSE:
|
||||
case TEST_SHUTO:
|
||||
if (!xn.equals("java.nio.channels.AsynchronousCloseException"))
|
||||
throw new RuntimeException("Wrong exception thrown: " + x);
|
||||
break;
|
||||
|
||||
case TEST_SHUTI:
|
||||
if (TestUtil.onWindows())
|
||||
break;
|
||||
// FALL THROUGH
|
||||
|
||||
default:
|
||||
throw new Error(x);
|
||||
}
|
||||
|
||||
if (ch.isOpen()) {
|
||||
if (test == TEST_SHUTO) {
|
||||
SocketChannel sc = (SocketChannel)ch;
|
||||
if (!sc.socket().isOutputShutdown())
|
||||
throw new RuntimeException("Output not shutdown");
|
||||
} else if ((test == TEST_INTR || test == TEST_PREINTR)
|
||||
&& (op == TRANSFER_FROM)) {
|
||||
// Let these cases pass -- CBIE applies to other channel
|
||||
} else {
|
||||
throw new RuntimeException("Channel still open");
|
||||
}
|
||||
}
|
||||
|
||||
log.println("Thrown as expected: " + x);
|
||||
}
|
||||
|
||||
final void go() throws Exception {
|
||||
if (test == TEST_PREINTR)
|
||||
Thread.currentThread().interrupt();
|
||||
ready = true;
|
||||
try {
|
||||
op.doIO(ch);
|
||||
} catch (ClosedByInterruptException x) {
|
||||
caught(ch, x);
|
||||
} catch (AsynchronousCloseException x) {
|
||||
caught(ch, x);
|
||||
} finally {
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static volatile boolean pumpDone = false;
|
||||
private static volatile boolean pumpReady = false;
|
||||
|
||||
private static void waitPump(String msg){
|
||||
log.println(msg);
|
||||
while (!pumpReady){
|
||||
sleep(200);
|
||||
}
|
||||
log.println(msg + " done");
|
||||
}
|
||||
|
||||
// Create a pump thread dedicated to saturate refuser's connection backlog
|
||||
private static Future<Integer> pumpRefuser(ExecutorService pumperExecutor) {
|
||||
|
||||
Callable<Integer> pumpTask = new Callable<Integer>() {
|
||||
|
||||
@Override
|
||||
public Integer call() throws IOException {
|
||||
// Can't reliably saturate connection backlog on Windows Server editions
|
||||
assert !TestUtil.onWindows();
|
||||
log.println("Start pumping refuser ...");
|
||||
List<SocketChannel> refuserClients = new ArrayList<>();
|
||||
|
||||
// Saturate the refuser's connection backlog so that further connection
|
||||
// attempts will be blocked
|
||||
pumpReady = false;
|
||||
while (!pumpDone) {
|
||||
SocketChannel sc = SocketChannel.open();
|
||||
sc.configureBlocking(false);
|
||||
boolean connected = sc.connect(refuser.socket().getLocalSocketAddress());
|
||||
|
||||
// Assume that the connection backlog is saturated if a
|
||||
// client cannot connect to the refuser within 50 milliseconds
|
||||
long start = System.currentTimeMillis();
|
||||
while (!pumpReady && !connected
|
||||
&& (System.currentTimeMillis() - start < 50)) {
|
||||
connected = sc.finishConnect();
|
||||
}
|
||||
|
||||
if (connected) {
|
||||
// Retain so that finalizer doesn't close
|
||||
refuserClients.add(sc);
|
||||
} else {
|
||||
sc.close();
|
||||
pumpReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (SocketChannel sc : refuserClients) {
|
||||
sc.close();
|
||||
}
|
||||
refuser.close();
|
||||
|
||||
log.println("Stop pumping refuser ...");
|
||||
return refuserClients.size();
|
||||
}
|
||||
};
|
||||
|
||||
return pumperExecutor.submit(pumpTask);
|
||||
}
|
||||
|
||||
// Test
|
||||
static void test(ChannelFactory cf, Op op, int test) throws Exception {
|
||||
test(cf, op, test, true);
|
||||
}
|
||||
|
||||
static void test(ChannelFactory cf, Op op, int test, boolean extraSleep)
|
||||
throws Exception
|
||||
{
|
||||
log.println();
|
||||
initPipes();
|
||||
InterruptibleChannel ch = cf.create();
|
||||
Tester t = new Tester(cf, ch, op, test);
|
||||
log.println(t);
|
||||
op.setup();
|
||||
t.start();
|
||||
do {
|
||||
sleep(50);
|
||||
} while (!t.ready);
|
||||
|
||||
if (extraSleep) {
|
||||
sleep(100);
|
||||
}
|
||||
|
||||
switch (test) {
|
||||
|
||||
case TEST_INTR:
|
||||
t.interrupt();
|
||||
break;
|
||||
|
||||
case TEST_CLOSE:
|
||||
ch.close();
|
||||
break;
|
||||
|
||||
case TEST_SHUTI:
|
||||
if (TestUtil.onWindows()) {
|
||||
log.println("WARNING: Asynchronous shutdown not working on Windows");
|
||||
ch.close();
|
||||
} else {
|
||||
((SocketChannel)ch).socket().shutdownInput();
|
||||
}
|
||||
break;
|
||||
|
||||
case TEST_SHUTO:
|
||||
if (TestUtil.onWindows()) {
|
||||
log.println("WARNING: Asynchronous shutdown not working on Windows");
|
||||
ch.close();
|
||||
} else {
|
||||
((SocketChannel)ch).socket().shutdownOutput();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
t.finishAndThrow(10000);
|
||||
}
|
||||
|
||||
static void test(ChannelFactory cf, Op op) throws Exception {
|
||||
test(cf, op, true);
|
||||
}
|
||||
|
||||
static void test(ChannelFactory cf, Op op, boolean extraSleep) throws Exception {
|
||||
// Test INTR cases before PREINTER cases since sometimes
|
||||
// interrupted threads can't load classes
|
||||
test(cf, op, TEST_INTR, extraSleep);
|
||||
test(cf, op, TEST_PREINTR, extraSleep);
|
||||
|
||||
// Bugs, see FileChannelImpl for details
|
||||
if (op == TRANSFER_FROM) {
|
||||
log.println("WARNING: transferFrom/close not tested");
|
||||
return;
|
||||
}
|
||||
if ((op == TRANSFER_TO) && !TestUtil.onWindows()) {
|
||||
log.println("WARNING: transferTo/close not tested");
|
||||
return;
|
||||
}
|
||||
|
||||
test(cf, op, TEST_CLOSE, extraSleep);
|
||||
}
|
||||
|
||||
static void test(ChannelFactory cf)
|
||||
throws Exception
|
||||
{
|
||||
InterruptibleChannel ch = cf.create(); // Sample channel
|
||||
ch.close();
|
||||
|
||||
if (ch instanceof ReadableByteChannel) {
|
||||
test(cf, READ);
|
||||
if (ch instanceof SocketChannel)
|
||||
test(cf, READ, TEST_SHUTI);
|
||||
}
|
||||
|
||||
if (ch instanceof ScatteringByteChannel) {
|
||||
test(cf, READV);
|
||||
if (ch instanceof SocketChannel)
|
||||
test(cf, READV, TEST_SHUTI);
|
||||
}
|
||||
|
||||
if (ch instanceof DatagramChannel) {
|
||||
test(cf, RECEIVE);
|
||||
|
||||
// Return here: We can't effectively test writes since, if they
|
||||
// block, they do so only for a fleeting moment unless the network
|
||||
// interface is overloaded.
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (ch instanceof WritableByteChannel) {
|
||||
test(cf, WRITE);
|
||||
if (ch instanceof SocketChannel)
|
||||
test(cf, WRITE, TEST_SHUTO);
|
||||
}
|
||||
|
||||
if (ch instanceof GatheringByteChannel) {
|
||||
test(cf, WRITEV);
|
||||
if (ch instanceof SocketChannel)
|
||||
test(cf, WRITEV, TEST_SHUTO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
wildcardAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
|
||||
initAcceptor();
|
||||
if (!TestUtil.onWindows())
|
||||
initRefuser();
|
||||
initPipes();
|
||||
initFile();
|
||||
|
||||
if (TestUtil.onWindows()) {
|
||||
log.println("WARNING: Cannot test FileChannel transfer operations"
|
||||
+ " on Windows");
|
||||
} else {
|
||||
test(diskFileChannelFactory, TRANSFER_TO);
|
||||
test(diskFileChannelFactory, TRANSFER_FROM);
|
||||
}
|
||||
if (fifoFile != null)
|
||||
test(fifoFileChannelFactory);
|
||||
|
||||
// Testing positional file reads and writes is impractical: It requires
|
||||
// access to a large file soft-mounted via NFS, and even then isn't
|
||||
// completely guaranteed to work.
|
||||
//
|
||||
// Testing map is impractical and arguably unnecessary: It's
|
||||
// unclear under what conditions mmap(2) will actually block.
|
||||
|
||||
test(connectedSocketChannelFactory);
|
||||
|
||||
if (TestUtil.onWindows()) {
|
||||
log.println("WARNING Cannot reliably test connect/finishConnect"
|
||||
+ " operations on this platform");
|
||||
} else {
|
||||
// Only the following tests need refuser's connection backlog
|
||||
// to be saturated
|
||||
ExecutorService pumperExecutor =
|
||||
Executors.newSingleThreadExecutor(
|
||||
new ThreadFactory() {
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("Pumper");
|
||||
return t;
|
||||
}
|
||||
});
|
||||
|
||||
pumpDone = false;
|
||||
try {
|
||||
Future<Integer> pumpFuture = pumpRefuser(pumperExecutor);
|
||||
waitPump("\nWait for initial Pump");
|
||||
|
||||
test(socketChannelFactory, CONNECT, false);
|
||||
test(socketChannelFactory, FINISH_CONNECT, false);
|
||||
|
||||
pumpDone = true;
|
||||
Integer newConn = pumpFuture.get(30, TimeUnit.SECONDS);
|
||||
log.println("Pump " + newConn + " connections.");
|
||||
} finally {
|
||||
pumperExecutor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
test(serverSocketChannelFactory, ACCEPT);
|
||||
test(datagramChannelFactory);
|
||||
test(pipeSourceChannelFactory);
|
||||
test(pipeSinkChannelFactory);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2025, 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
|
||||
* @bug 4607272 8364761
|
||||
* @summary tests tasks can be submitted to a channel group's thread pool.
|
||||
* @run junit AsExecutor
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.AsynchronousChannelGroup;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class AsExecutor {
|
||||
private static ThreadFactory factory;
|
||||
|
||||
@BeforeAll
|
||||
public static void createThreadFactory() {
|
||||
factory = Executors.defaultThreadFactory();
|
||||
}
|
||||
|
||||
private static Stream<Arguments> channelGroups() throws IOException {
|
||||
List<Arguments> list = new ArrayList<Arguments>();
|
||||
list.add(Arguments.of(AsynchronousChannelGroup
|
||||
.withFixedThreadPool(5, factory)));
|
||||
list.add(Arguments.of(AsynchronousChannelGroup
|
||||
.withCachedThreadPool(Executors.newCachedThreadPool(factory), 0)));
|
||||
list.add(Arguments.of(AsynchronousChannelGroup
|
||||
.withThreadPool(Executors.newFixedThreadPool(10, factory))));
|
||||
return list.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("channelGroups")
|
||||
public void simpleTask(AsynchronousChannelGroup group)
|
||||
throws InterruptedException
|
||||
{
|
||||
try {
|
||||
Executor executor = (Executor)group;
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("channelGroups")
|
||||
public void nullTask(AsynchronousChannelGroup group) {
|
||||
Executor executor = (Executor)group;
|
||||
try {
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> executor.execute(null));
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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
|
||||
* @bug 4607272
|
||||
* @summary Unit test for AsynchronousChannelGroup
|
||||
* @build BadProperties
|
||||
* @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.threadFactory BadProperties
|
||||
* @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.threadFactory=Missing BadProperties
|
||||
* @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.initialSize BadProperties
|
||||
* @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.initialSize=NaN BadProperties
|
||||
*/
|
||||
|
||||
import java.nio.channels.AsynchronousSocketChannel;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BadProperties {
|
||||
public static void main(String[] args) throws IOException {
|
||||
AsynchronousSocketChannel.open();
|
||||
}
|
||||
}
|
||||
310
test/jdk/java/nio/channels/AsynchronousChannelGroup/Basic.java
Normal file
310
test/jdk/java/nio/channels/AsynchronousChannelGroup/Basic.java
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2016, 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
|
||||
* @bug 4607272
|
||||
* @summary Unit test for AsynchronousChannelGroup
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Basic {
|
||||
static final Random rand = new Random();
|
||||
static final ThreadFactory threadFactory = (Runnable r) -> {
|
||||
return new Thread(r);
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
shutdownTests();
|
||||
shutdownNowTests();
|
||||
afterShutdownTests();
|
||||
miscTests();
|
||||
}
|
||||
|
||||
static void awaitTermination(AsynchronousChannelGroup group) throws InterruptedException {
|
||||
boolean terminated = group.awaitTermination(20, TimeUnit.SECONDS);
|
||||
if (!terminated)
|
||||
throw new RuntimeException("Group should have terminated");
|
||||
}
|
||||
|
||||
static void testShutdownWithNoChannels(ExecutorService pool,
|
||||
AsynchronousChannelGroup group)
|
||||
throws Exception
|
||||
{
|
||||
group.shutdown();
|
||||
if (!group.isShutdown())
|
||||
throw new RuntimeException("Group should be shutdown");
|
||||
// group should terminate quickly
|
||||
awaitTermination(group);
|
||||
if (pool != null && !pool.isTerminated())
|
||||
throw new RuntimeException("Executor should have terminated");
|
||||
}
|
||||
|
||||
static void testShutdownWithChannels(ExecutorService pool,
|
||||
AsynchronousChannelGroup group)
|
||||
throws Exception
|
||||
{
|
||||
|
||||
// create channel that is bound to group
|
||||
AsynchronousChannel ch;
|
||||
switch (rand.nextInt(2)) {
|
||||
case 0 : ch = AsynchronousSocketChannel.open(group); break;
|
||||
case 1 : ch = AsynchronousServerSocketChannel.open(group); break;
|
||||
default : throw new AssertionError();
|
||||
}
|
||||
group.shutdown();
|
||||
if (!group.isShutdown())
|
||||
throw new RuntimeException("Group should be shutdown");
|
||||
|
||||
// last channel so should terminate after this channel is closed
|
||||
ch.close();
|
||||
|
||||
// group should terminate quickly
|
||||
awaitTermination(group);
|
||||
if (pool != null && !pool.isTerminated())
|
||||
throw new RuntimeException("Executor should have terminated");
|
||||
}
|
||||
|
||||
static void shutdownTests() throws Exception {
|
||||
System.out.println("-- test shutdown --");
|
||||
|
||||
// test shutdown with no channels in groups
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ExecutorService pool = Executors.newCachedThreadPool();
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withCachedThreadPool(pool, rand.nextInt(5));
|
||||
testShutdownWithNoChannels(pool, group);
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int nThreads = 1 + rand.nextInt(8);
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withFixedThreadPool(nThreads, threadFactory);
|
||||
testShutdownWithNoChannels(null, group);
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ExecutorService pool = Executors.newCachedThreadPool();
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withThreadPool(pool);
|
||||
testShutdownWithNoChannels(pool, group);
|
||||
}
|
||||
|
||||
// test shutdown with channel in group
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ExecutorService pool = Executors.newCachedThreadPool();
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withCachedThreadPool(pool, rand.nextInt(10));
|
||||
try {
|
||||
testShutdownWithChannels(pool, group);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int nThreads = 1 + rand.nextInt(8);
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withFixedThreadPool(nThreads, threadFactory);
|
||||
try {
|
||||
testShutdownWithChannels(null, group);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ExecutorService pool = Executors.newCachedThreadPool();
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withThreadPool(pool);
|
||||
try {
|
||||
testShutdownWithChannels(pool, group);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testShutdownNow(ExecutorService pool,
|
||||
AsynchronousChannelGroup group)
|
||||
throws Exception
|
||||
{
|
||||
// I/O in progress
|
||||
AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel
|
||||
.open(group).bind(new InetSocketAddress(0));
|
||||
ch.accept();
|
||||
|
||||
// forceful shutdown
|
||||
group.shutdownNow();
|
||||
|
||||
// shutdownNow is required to close all channels
|
||||
if (ch.isOpen())
|
||||
throw new RuntimeException("Channel should be closed");
|
||||
|
||||
awaitTermination(group);
|
||||
|
||||
if (pool != null && !pool.isTerminated())
|
||||
throw new RuntimeException("Executor should have terminated");
|
||||
}
|
||||
|
||||
static void shutdownNowTests() throws Exception {
|
||||
System.out.println("-- test shutdownNow --");
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ExecutorService pool = pool = Executors.newCachedThreadPool();
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withCachedThreadPool(pool, rand.nextInt(5));
|
||||
try {
|
||||
testShutdownNow(pool, group);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int nThreads = 1 + rand.nextInt(8);
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withFixedThreadPool(nThreads, threadFactory);
|
||||
try {
|
||||
testShutdownNow(null, group);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ExecutorService pool = Executors.newCachedThreadPool();
|
||||
AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withThreadPool(pool);
|
||||
try {
|
||||
testShutdownNow(pool, group);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test creating channels in group after group is shutdown
|
||||
static void afterShutdownTests() throws Exception {
|
||||
System.out.println("-- test operations after group is shutdown --");
|
||||
AsynchronousChannelGroup group =
|
||||
AsynchronousChannelGroup.withFixedThreadPool(1, threadFactory);
|
||||
|
||||
try (AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
|
||||
AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open(group)) {
|
||||
|
||||
// initiate accept
|
||||
listener.bind(new InetSocketAddress(0));
|
||||
Future<AsynchronousSocketChannel> result = listener.accept();
|
||||
|
||||
// shutdown group
|
||||
group.shutdown();
|
||||
if (!group.isShutdown())
|
||||
throw new RuntimeException("Group should be shutdown");
|
||||
|
||||
// attempt to create another channel
|
||||
try {
|
||||
AsynchronousSocketChannel.open(group);
|
||||
throw new RuntimeException("ShutdownChannelGroupException expected");
|
||||
} catch (ShutdownChannelGroupException x) {
|
||||
}
|
||||
try {
|
||||
AsynchronousServerSocketChannel.open(group);
|
||||
throw new RuntimeException("ShutdownChannelGroupException expected");
|
||||
} catch (ShutdownChannelGroupException x) {
|
||||
}
|
||||
|
||||
// attempt to create another channel by connecting. This should cause
|
||||
// the accept operation to fail.
|
||||
InetAddress lh = InetAddress.getLocalHost();
|
||||
int port = ((InetSocketAddress)listener.getLocalAddress()).getPort();
|
||||
InetSocketAddress isa = new InetSocketAddress(lh, port);
|
||||
ch.connect(isa).get();
|
||||
try {
|
||||
result.get();
|
||||
throw new RuntimeException("Connection was accepted");
|
||||
} catch (ExecutionException x) {
|
||||
Throwable cause = x.getCause();
|
||||
if (!(cause instanceof IOException))
|
||||
throw new RuntimeException("Cause should be IOException");
|
||||
cause = cause.getCause();
|
||||
if (!(cause instanceof ShutdownChannelGroupException))
|
||||
throw new RuntimeException("IOException cause should be ShutdownChannelGroupException");
|
||||
}
|
||||
|
||||
// initiate another accept even though channel group is shutdown.
|
||||
Future<AsynchronousSocketChannel> res = listener.accept();
|
||||
try {
|
||||
res.get(3, TimeUnit.SECONDS);
|
||||
throw new RuntimeException("TimeoutException expected");
|
||||
} catch (TimeoutException x) {
|
||||
}
|
||||
// connect to the listener which should cause the accept to complete
|
||||
AsynchronousSocketChannel.open().connect(isa);
|
||||
try {
|
||||
res.get();
|
||||
throw new RuntimeException("Connection was accepted");
|
||||
} catch (ExecutionException x) {
|
||||
Throwable cause = x.getCause();
|
||||
if (!(cause instanceof IOException))
|
||||
throw new RuntimeException("Cause should be IOException");
|
||||
cause = cause.getCause();
|
||||
if (!(cause instanceof ShutdownChannelGroupException))
|
||||
throw new RuntimeException("IOException cause should be ShutdownChannelGroupException");
|
||||
}
|
||||
|
||||
// group should *not* terminate as channels are open
|
||||
boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
|
||||
if (terminated) {
|
||||
throw new RuntimeException("Group should not have terminated");
|
||||
}
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
static void miscTests() throws Exception {
|
||||
System.out.println("-- miscellenous tests --");
|
||||
try {
|
||||
AsynchronousChannelGroup.withFixedThreadPool(1, null);
|
||||
throw new RuntimeException("NPE expected");
|
||||
} catch (NullPointerException x) {
|
||||
}
|
||||
try {
|
||||
AsynchronousChannelGroup.withFixedThreadPool(0, threadFactory);
|
||||
throw new RuntimeException("IAE expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
try {
|
||||
AsynchronousChannelGroup.withCachedThreadPool(null, 0);
|
||||
throw new RuntimeException("NPE expected");
|
||||
} catch (NullPointerException x) {
|
||||
}
|
||||
try {
|
||||
AsynchronousChannelGroup.withThreadPool(null);
|
||||
throw new RuntimeException("NPE expected");
|
||||
} catch (NullPointerException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2016, 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
|
||||
* @bug 4607272 6842687
|
||||
* @summary Unit test for AsynchronousChannelGroup
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This test verifies that a channel or channel group can be closed from a
|
||||
* completion handler when there are no threads available to handle I/O events.
|
||||
*/
|
||||
|
||||
public class GroupOfOne {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final List<AsynchronousSocketChannel> accepted = new ArrayList<>();
|
||||
|
||||
// create listener to accept connections
|
||||
try (final AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open()) {
|
||||
|
||||
listener.bind(new InetSocketAddress(0));
|
||||
listener.accept((Void)null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
|
||||
public void completed(AsynchronousSocketChannel ch, Void att) {
|
||||
synchronized (accepted) {
|
||||
accepted.add(ch);
|
||||
}
|
||||
listener.accept((Void)null, this);
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
|
||||
SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
|
||||
|
||||
test(sa, true, false);
|
||||
test(sa, false, true);
|
||||
test(sa, true, true);
|
||||
} finally {
|
||||
// clean-up
|
||||
synchronized (accepted) {
|
||||
for (AsynchronousSocketChannel ch: accepted) {
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test(SocketAddress sa,
|
||||
final boolean closeChannel,
|
||||
final boolean shutdownGroup)
|
||||
throws Exception
|
||||
{
|
||||
// group with 1 thread
|
||||
final AsynchronousChannelGroup group = AsynchronousChannelGroup
|
||||
.withFixedThreadPool(1, new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(final Runnable r) {
|
||||
return new Thread(r);
|
||||
}});
|
||||
final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
|
||||
try {
|
||||
// the latch counts down when:
|
||||
// 1. The read operation fails (expected)
|
||||
// 2. the close/shutdown completes
|
||||
final CountDownLatch latch = new CountDownLatch(2);
|
||||
|
||||
ch.connect(sa, (Void)null, new CompletionHandler<Void,Void>() {
|
||||
public void completed(Void result, Void att) {
|
||||
System.out.println("Connected");
|
||||
|
||||
// initiate I/O operation that does not complete (successfully)
|
||||
ByteBuffer buf = ByteBuffer.allocate(100);
|
||||
ch.read(buf, (Void)null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer bytesRead, Void att) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
if (!(exc instanceof AsynchronousCloseException))
|
||||
throw new RuntimeException(exc);
|
||||
System.out.println("Read failed (expected)");
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
// close channel or shutdown group
|
||||
try {
|
||||
if (closeChannel) {
|
||||
System.out.print("Close channel ...");
|
||||
ch.close();
|
||||
System.out.println(" done.");
|
||||
}
|
||||
if (shutdownGroup) {
|
||||
System.out.print("Shutdown group ...");
|
||||
group.shutdownNow();
|
||||
System.out.println(" done.");
|
||||
}
|
||||
latch.countDown();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
throw new RuntimeException(exc);
|
||||
}
|
||||
});
|
||||
|
||||
latch.await();
|
||||
} finally {
|
||||
// clean-up
|
||||
group.shutdown();
|
||||
boolean terminated = group.awaitTermination(20, TimeUnit.SECONDS);
|
||||
if (!terminated)
|
||||
throw new RuntimeException("Group did not terminate");
|
||||
}
|
||||
System.out.println("TEST OKAY");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2016, 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
|
||||
* @bug 4607272 6842687
|
||||
* @summary Unit test for AsynchronousChannelGroup
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Tests that the completion handler is invoked by a thread with
|
||||
* the expected identity.
|
||||
*/
|
||||
|
||||
public class Identity {
|
||||
static final Random rand = new Random();
|
||||
static final CountDownLatch done = new CountDownLatch(1);
|
||||
static final AtomicBoolean failed = new AtomicBoolean(false);
|
||||
|
||||
static void fail(String msg) {
|
||||
failed.set(true);
|
||||
done.countDown();
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
// thread-local identifies the thread
|
||||
private static final ThreadLocal<Integer> myGroup =
|
||||
new ThreadLocal<Integer>() {
|
||||
@Override protected Integer initialValue() {
|
||||
return Integer.valueOf(-1);
|
||||
}
|
||||
};
|
||||
|
||||
// creates a ThreadFactory that constructs groups with the given identity
|
||||
static final ThreadFactory createThreadFactory(final int groupId) {
|
||||
return new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(final Runnable r) {
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
myGroup.set(groupId);
|
||||
r.run();
|
||||
}});
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// create 3-10 channels, each in its own group
|
||||
final int groupCount = 3 + rand.nextInt(8);
|
||||
final AsynchronousChannelGroup[] groups = new AsynchronousChannelGroup[groupCount];
|
||||
final AsynchronousSocketChannel[] channels = new AsynchronousSocketChannel[groupCount];
|
||||
|
||||
// create listener to accept connections
|
||||
try (final AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open()) {
|
||||
|
||||
listener.bind(new InetSocketAddress(0));
|
||||
listener.accept((Void)null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
|
||||
public void completed(final AsynchronousSocketChannel ch, Void att) {
|
||||
listener.accept((Void)null, this);
|
||||
final ByteBuffer buf = ByteBuffer.allocate(100);
|
||||
ch.read(buf, ch, new CompletionHandler<Integer,AsynchronousSocketChannel>() {
|
||||
public void completed(Integer bytesRead, AsynchronousSocketChannel ch) {
|
||||
if (bytesRead < 0) {
|
||||
try { ch.close(); } catch (IOException ignore) { }
|
||||
} else {
|
||||
buf.clear();
|
||||
ch.read(buf, ch, this);
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, AsynchronousSocketChannel ch) {
|
||||
try { ch.close(); } catch (IOException ignore) { }
|
||||
}
|
||||
});
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
|
||||
SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
|
||||
|
||||
for (int i=0; i<groupCount; i++) {
|
||||
ThreadFactory factory = createThreadFactory(i);
|
||||
AsynchronousChannelGroup group;
|
||||
if (rand.nextBoolean()) {
|
||||
int nThreads = 1 + rand.nextInt(10);
|
||||
group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, factory);
|
||||
} else {
|
||||
ExecutorService pool = Executors.newCachedThreadPool(factory);
|
||||
group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5));
|
||||
}
|
||||
groups[i] = group;
|
||||
|
||||
// create channel in group and connect it to the server
|
||||
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
|
||||
ch.connect(sa).get();
|
||||
channels[i] = ch;
|
||||
}
|
||||
|
||||
// randomly write to each channel, ensuring that the completion handler
|
||||
// is always invoked by a thread with the right identity.
|
||||
final AtomicInteger writeCount = new AtomicInteger(100);
|
||||
channels[0].write(getBuffer(), 0, new CompletionHandler<Integer,Integer>() {
|
||||
public void completed(Integer bytesWritten, Integer groupId) {
|
||||
if (bytesWritten != 1)
|
||||
fail("Expected 1 byte to be written");
|
||||
if (!myGroup.get().equals(groupId))
|
||||
fail("Handler invoked by thread with the wrong identity");
|
||||
if (writeCount.decrementAndGet() > 0) {
|
||||
int id = rand.nextInt(groupCount);
|
||||
channels[id].write(getBuffer(), id, this);
|
||||
} else {
|
||||
done.countDown();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Integer groupId) {
|
||||
fail(exc.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
// wait until done
|
||||
done.await();
|
||||
} finally {
|
||||
// clean-up
|
||||
for (AsynchronousSocketChannel ch: channels)
|
||||
ch.close();
|
||||
for (AsynchronousChannelGroup group: groups)
|
||||
group.shutdownNow();
|
||||
|
||||
if (failed.get())
|
||||
throw new RuntimeException("Test failed - see log for details");
|
||||
}
|
||||
}
|
||||
|
||||
static ByteBuffer getBuffer() {
|
||||
ByteBuffer buf;
|
||||
if (rand.nextBoolean()) {
|
||||
buf = ByteBuffer.allocateDirect(1);
|
||||
} else {
|
||||
buf = ByteBuffer.allocate(1);
|
||||
}
|
||||
buf.put((byte)0);
|
||||
buf.flip();
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
143
test/jdk/java/nio/channels/AsynchronousChannelGroup/Restart.java
Normal file
143
test/jdk/java/nio/channels/AsynchronousChannelGroup/Restart.java
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2016, 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
|
||||
* @bug 4607272 6842687
|
||||
* @summary Unit test for AsynchronousChannelGroup
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exercise replacement of threads in the thread pool when completion handlers
|
||||
* terminate due to errors or runtime exceptions.
|
||||
*/
|
||||
|
||||
public class Restart {
|
||||
static final Random rand = new Random();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// thread group for thread pools
|
||||
final ThreadGroup tg = new ThreadGroup("test");
|
||||
|
||||
// keep track of the number of threads that terminate
|
||||
final AtomicInteger exceptionCount = new AtomicInteger(0);
|
||||
final Thread.UncaughtExceptionHandler ueh =
|
||||
new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
exceptionCount.incrementAndGet();
|
||||
}
|
||||
};
|
||||
ThreadFactory factory = new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(tg, r);
|
||||
t.setUncaughtExceptionHandler(ueh);
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
// group with fixed thread pool
|
||||
int nThreads = 1 + rand.nextInt(4);
|
||||
AsynchronousChannelGroup group =
|
||||
AsynchronousChannelGroup.withFixedThreadPool(nThreads, factory);
|
||||
try {
|
||||
testRestart(group, 100);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
|
||||
// group with cached thread pool
|
||||
ExecutorService pool = Executors.newCachedThreadPool(factory);
|
||||
group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5));
|
||||
try {
|
||||
testRestart(group, 100);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
|
||||
// group with custom thread pool
|
||||
group = AsynchronousChannelGroup.withThreadPool(
|
||||
Executors.newFixedThreadPool(1+rand.nextInt(5), factory));
|
||||
try {
|
||||
testRestart(group, 100);
|
||||
} finally {
|
||||
group.shutdown();
|
||||
}
|
||||
|
||||
// give time for threads to terminate
|
||||
Thread.sleep(3000);
|
||||
int actual = exceptionCount.get();
|
||||
if (actual != 300)
|
||||
throw new RuntimeException(actual + " exceptions, expected: " + 300);
|
||||
}
|
||||
|
||||
static void testRestart(AsynchronousChannelGroup group, int count)
|
||||
throws Exception
|
||||
{
|
||||
try (AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open(group)) {
|
||||
|
||||
listener.bind(new InetSocketAddress(0));
|
||||
for (int i=0; i<count; i++) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
listener.accept((Void)null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
|
||||
public void completed(AsynchronousSocketChannel ch, Void att) {
|
||||
try {
|
||||
ch.close();
|
||||
} catch (IOException ignore) { }
|
||||
|
||||
latch.countDown();
|
||||
|
||||
// throw error or runtime exception
|
||||
if (rand.nextBoolean()) {
|
||||
throw new Error();
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
// establish loopback connection which should cause completion
|
||||
// handler to be invoked.
|
||||
int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
|
||||
try (AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()) {
|
||||
InetAddress lh = InetAddress.getLocalHost();
|
||||
ch.connect(new InetSocketAddress(lh, port)).get();
|
||||
}
|
||||
|
||||
// wait for handler to be invoked
|
||||
latch.await();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
|
||||
public class SetupJar {
|
||||
public static void main(String args[]) throws Exception {
|
||||
String cp = System.getProperty("test.class.path");
|
||||
Path bootlib = Stream.of(cp.split(File.pathSeparator))
|
||||
.map(Paths::get)
|
||||
.filter(e -> e.endsWith("bootlib")) // file name
|
||||
.findAny()
|
||||
.orElseThrow(() -> new InternalError("bootlib not found"));
|
||||
JarUtils.createJarFile(Paths.get("privileged.jar"), bootlib);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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
|
||||
* @bug 4607272 6842687
|
||||
* @summary Unit test for AsynchronousChannelGroup
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Unbounded {
|
||||
// number of concurrent completion handlers
|
||||
static final int CONCURRENCY_COUNT = 256;
|
||||
|
||||
// set to true if an I/O operation fails
|
||||
static volatile boolean failed;
|
||||
|
||||
// set to true when the test is done
|
||||
static volatile boolean finished;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// create listener to accept connections
|
||||
AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open()
|
||||
.bind(new InetSocketAddress(0));
|
||||
|
||||
// establish connections
|
||||
|
||||
AsynchronousSocketChannel[] clients = new AsynchronousSocketChannel[CONCURRENCY_COUNT];
|
||||
AsynchronousSocketChannel[] peers = new AsynchronousSocketChannel[CONCURRENCY_COUNT];
|
||||
|
||||
int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
|
||||
SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
|
||||
|
||||
for (int i=0; i<CONCURRENCY_COUNT; i++) {
|
||||
clients[i] = AsynchronousSocketChannel.open();
|
||||
Future<Void> result = clients[i].connect(sa);
|
||||
peers[i] = listener.accept().get();
|
||||
result.get();
|
||||
}
|
||||
System.out.println("All connection established.");
|
||||
|
||||
// the barrier where all threads (plus the main thread) wait
|
||||
final CyclicBarrier barrier = new CyclicBarrier(CONCURRENCY_COUNT+1);
|
||||
|
||||
// initiate a read operation on each channel.
|
||||
for (AsynchronousSocketChannel client: clients) {
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(100);
|
||||
client.read(buf, client,
|
||||
new CompletionHandler<Integer,AsynchronousSocketChannel>() {
|
||||
public void completed(Integer bytesRead, AsynchronousSocketChannel ch) {
|
||||
try {
|
||||
ch.close();
|
||||
barrier.await();
|
||||
} catch (Exception x) {
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, AsynchronousSocketChannel ch) {
|
||||
failed = true;
|
||||
System.err.println("read failed: " + exc);
|
||||
completed(0, ch);
|
||||
}
|
||||
});
|
||||
}
|
||||
System.out.println("All read operations outstanding.");
|
||||
|
||||
// write data to each of the accepted connections
|
||||
for (AsynchronousSocketChannel peer: peers) {
|
||||
peer.write(ByteBuffer.wrap("welcome".getBytes())).get();
|
||||
peer.shutdownOutput();
|
||||
peer.close();
|
||||
}
|
||||
|
||||
// wait for all threads to reach the barrier
|
||||
System.out.println("Waiting for all threads to reach barrier");
|
||||
barrier.await();
|
||||
|
||||
// finish up
|
||||
finished = true;
|
||||
listener.close();
|
||||
if (failed)
|
||||
throw new RuntimeException("I/O operation failed, see log for details");
|
||||
}
|
||||
}
|
||||
650
test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java
Normal file
650
test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2025, 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
|
||||
* @bug 4607272 5041655 6822643 6830721 6842687
|
||||
* @summary Unit test for AsynchronousFileChannel
|
||||
* @key randomness
|
||||
* @run main/othervm Basic
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.foreign.Arena;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.AsynchronousFileChannel;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.channels.NonWritableChannelException;
|
||||
import java.nio.channels.OverlappingFileLockException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
public class Basic {
|
||||
|
||||
// Must be indeterministic
|
||||
private static final Random rand = new Random();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
// create temporary file
|
||||
File blah = File.createTempFile("blah", null);
|
||||
blah.deleteOnExit();
|
||||
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel
|
||||
.open(blah.toPath(), READ, WRITE);
|
||||
try {
|
||||
// run tests
|
||||
testUsingCompletionHandlers(ch);
|
||||
testUsingWaitOnResult(ch);
|
||||
testInterruptHandlerThread(ch);
|
||||
} finally {
|
||||
ch.close();
|
||||
}
|
||||
|
||||
// run test that expects channel to be closed
|
||||
testClosedChannel(ch);
|
||||
|
||||
// these tests open the file themselves
|
||||
testLocking(blah.toPath());
|
||||
testCustomThreadPool(blah.toPath());
|
||||
testAsynchronousClose(blah.toPath());
|
||||
testCancel(blah.toPath());
|
||||
testTruncate(blah.toPath());
|
||||
|
||||
// eagerly clean-up
|
||||
blah.delete();
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate buffer with random contents
|
||||
* Writes buffer to file using a CompletionHandler to consume the result
|
||||
* of each write operation
|
||||
* Reads file to EOF to a new buffer using a CompletionHandler to consume
|
||||
* the result of each read operation
|
||||
* Compares buffer contents
|
||||
*/
|
||||
static void testUsingCompletionHandlers(AsynchronousFileChannel ch)
|
||||
throws IOException
|
||||
{
|
||||
System.out.println("testUsingCompletionHandlers");
|
||||
|
||||
ch.truncate(0L);
|
||||
|
||||
// generate buffer with random elements and write it to file
|
||||
ByteBuffer src = genBuffer();
|
||||
writeFully(ch, src, 0L);
|
||||
|
||||
// read to EOF or buffer is full
|
||||
ByteBuffer dst = (rand.nextBoolean()) ?
|
||||
ByteBuffer.allocateDirect(src.capacity()) :
|
||||
ByteBuffer.allocate(src.capacity());
|
||||
readAll(ch, dst, 0L);
|
||||
|
||||
// check buffers are the same
|
||||
src.flip();
|
||||
dst.flip();
|
||||
if (!src.equals(dst)) {
|
||||
throw new RuntimeException("Contents differ");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate buffer with random contents
|
||||
* Writes buffer to file, invoking the Future's get method to wait for
|
||||
* each write operation to complete
|
||||
* Reads file to EOF to a new buffer, invoking the Future's get method to
|
||||
* wait for each write operation to complete
|
||||
* Compares buffer contents
|
||||
*/
|
||||
static void testUsingWaitOnResult(AsynchronousFileChannel ch)
|
||||
throws IOException
|
||||
{
|
||||
System.out.println("testUsingWaitOnResult");
|
||||
|
||||
ch.truncate(0L);
|
||||
|
||||
// generate buffer
|
||||
ByteBuffer src = genBuffer();
|
||||
|
||||
// write buffer completely to file
|
||||
long position = 0L;
|
||||
while (src.hasRemaining()) {
|
||||
Future<Integer> result = ch.write(src, position);
|
||||
try {
|
||||
int n = result.get();
|
||||
// update position
|
||||
position += n;
|
||||
} catch (ExecutionException x) {
|
||||
throw new RuntimeException(x.getCause());
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
// read file into new buffer
|
||||
ByteBuffer dst = (rand.nextBoolean()) ?
|
||||
ByteBuffer.allocateDirect(src.capacity()) :
|
||||
ByteBuffer.allocate(src.capacity());
|
||||
position = 0L;
|
||||
int n;
|
||||
do {
|
||||
Future<Integer> result = ch.read(dst, position);
|
||||
try {
|
||||
n = result.get();
|
||||
|
||||
// update position
|
||||
if (n > 0) position += n;
|
||||
} catch (ExecutionException x) {
|
||||
throw new RuntimeException(x.getCause());
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
} while (n > 0);
|
||||
|
||||
// check buffers are the same
|
||||
src.flip();
|
||||
dst.flip();
|
||||
if (!src.equals(dst)) {
|
||||
throw new RuntimeException("Contents differ");
|
||||
}
|
||||
}
|
||||
|
||||
// exercise lock methods
|
||||
static void testLocking(Path file) throws IOException {
|
||||
System.out.println("testLocking");
|
||||
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel
|
||||
.open(file, READ, WRITE);
|
||||
FileLock fl;
|
||||
try {
|
||||
// test 1 - acquire lock and check that tryLock throws
|
||||
// OverlappingFileLockException
|
||||
try {
|
||||
long pos = rand.nextInt(Integer.MAX_VALUE);
|
||||
fl = ch.lock(pos, 0, false).get();
|
||||
long expectedSize = Long.MAX_VALUE - pos;
|
||||
if(fl.size() != expectedSize)
|
||||
throw new RuntimeException("Lock size " + fl.size() +
|
||||
" != " + expectedSize + " for position " + pos);
|
||||
} catch (ExecutionException x) {
|
||||
throw new RuntimeException(x);
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException("Should not be interrupted");
|
||||
}
|
||||
if (!fl.acquiredBy().equals(ch))
|
||||
throw new RuntimeException("FileLock#acquiredBy returned incorrect channel");
|
||||
try {
|
||||
ch.tryLock();
|
||||
throw new RuntimeException("OverlappingFileLockException expected");
|
||||
} catch (OverlappingFileLockException x) {
|
||||
}
|
||||
fl.release();
|
||||
|
||||
// test 2 - acquire try and check that lock throws OverlappingFileLockException
|
||||
long pos = rand.nextInt(Integer.MAX_VALUE);
|
||||
fl = ch.tryLock(pos, 0, false);
|
||||
long expectedSize = Long.MAX_VALUE - pos;
|
||||
if(fl.size() != expectedSize)
|
||||
throw new RuntimeException("Lock size " + fl.size() + " != " +
|
||||
expectedSize + " for position " + pos);
|
||||
if (fl == null)
|
||||
throw new RuntimeException("Unable to acquire lock");
|
||||
try {
|
||||
ch.lock((Void)null, new CompletionHandler<FileLock,Void> () {
|
||||
public void completed(FileLock result, Void att) {
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
throw new RuntimeException("OverlappingFileLockException expected");
|
||||
} catch (OverlappingFileLockException x) {
|
||||
}
|
||||
} finally {
|
||||
ch.close();
|
||||
}
|
||||
|
||||
// test 3 - channel is closed so FileLock should no longer be valid
|
||||
if (fl.isValid())
|
||||
throw new RuntimeException("FileLock expected to be invalid");
|
||||
}
|
||||
|
||||
// interrupt should not close channel
|
||||
static void testInterruptHandlerThread(final AsynchronousFileChannel ch) {
|
||||
System.out.println("testInterruptHandlerThread");
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(100);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
ch.read(buf, 0L, (Void)null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer result, Void att) {
|
||||
try {
|
||||
Thread.currentThread().interrupt();
|
||||
long size = ch.size();
|
||||
latch.countDown();
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
// wait for handler to complete
|
||||
await(latch);
|
||||
}
|
||||
|
||||
// invoke method on closed channel
|
||||
static void testClosedChannel(AsynchronousFileChannel ch) {
|
||||
System.out.println("testClosedChannel");
|
||||
|
||||
if (ch.isOpen())
|
||||
throw new RuntimeException("Channel should be closed");
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(100);
|
||||
|
||||
// check read fails with ClosedChannelException
|
||||
try {
|
||||
ch.read(buf, 0L).get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("Cause of ClosedChannelException expected");
|
||||
} catch (InterruptedException x) {
|
||||
}
|
||||
|
||||
// check write fails with ClosedChannelException
|
||||
try {
|
||||
ch.write(buf, 0L).get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("Cause of ClosedChannelException expected");
|
||||
} catch (InterruptedException x) {
|
||||
}
|
||||
|
||||
// check lock fails with ClosedChannelException
|
||||
try {
|
||||
ch.lock().get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("Cause of ClosedChannelException expected");
|
||||
} catch (InterruptedException x) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// exercise custom thread pool
|
||||
static void testCustomThreadPool(Path file) throws IOException {
|
||||
System.out.println("testCustomThreadPool");
|
||||
|
||||
// records threads that are created
|
||||
final List<Thread> threads = new ArrayList<Thread>();
|
||||
|
||||
ThreadFactory threadFactory = new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
synchronized (threads) {
|
||||
threads.add(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
// exercise tests with varied number of threads
|
||||
for (int nThreads=1; nThreads<=5; nThreads++) {
|
||||
synchronized (threads) {
|
||||
threads.clear();
|
||||
}
|
||||
ExecutorService executor = Executors.newFixedThreadPool(nThreads, threadFactory);
|
||||
Set<StandardOpenOption> opts = EnumSet.of(WRITE);
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, opts, executor);
|
||||
try {
|
||||
for (int i=0; i<10; i++) {
|
||||
// do I/O operation to see which thread invokes the completion handler
|
||||
final AtomicReference<Thread> invoker = new AtomicReference<Thread>();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
ch.write(genBuffer(), 0L, (Void)null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer result, Void att) {
|
||||
invoker.set(Thread.currentThread());
|
||||
latch.countDown();
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
await(latch);
|
||||
|
||||
// check invoker
|
||||
boolean found = false;
|
||||
synchronized (threads) {
|
||||
for (Thread t: threads) {
|
||||
if (t == invoker.get()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
throw new RuntimeException("Invoker thread not found");
|
||||
}
|
||||
} finally {
|
||||
ch.close();
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// test sharing a thread pool between many channels
|
||||
ExecutorService executor = Executors
|
||||
.newFixedThreadPool(1+rand.nextInt(10), threadFactory);
|
||||
final int n = 50 + rand.nextInt(50);
|
||||
AsynchronousFileChannel[] channels = new AsynchronousFileChannel[n];
|
||||
try {
|
||||
for (int i=0; i<n; i++) {
|
||||
Set<StandardOpenOption> opts = EnumSet.of(WRITE);
|
||||
channels[i] = AsynchronousFileChannel.open(file, opts, executor);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
channels[i].write(genBuffer(), 0L, (Void)null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer result, Void att) {
|
||||
latch.countDown();
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
await(latch);
|
||||
|
||||
// close ~half the channels
|
||||
if (rand.nextBoolean())
|
||||
channels[i].close();
|
||||
}
|
||||
} finally {
|
||||
// close remaining channels
|
||||
for (int i=0; i<n; i++) {
|
||||
if (channels[i] != null) channels[i].close();
|
||||
}
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// exercise asynchronous close
|
||||
static void testAsynchronousClose(Path file) throws IOException {
|
||||
System.out.println("testAsynchronousClose");
|
||||
|
||||
// create file
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel
|
||||
.open(file, WRITE, TRUNCATE_EXISTING);
|
||||
long size = 0L;
|
||||
do {
|
||||
ByteBuffer buf = genBuffer();
|
||||
int n = buf.remaining();
|
||||
writeFully(ch, buf, size);
|
||||
size += n;
|
||||
} while (size < (50L * 1024L * 1024L));
|
||||
|
||||
ch.close();
|
||||
|
||||
ch = AsynchronousFileChannel.open(file, WRITE, SYNC);
|
||||
|
||||
// randomize number of writers, buffer size, and positions
|
||||
|
||||
int nwriters = 1 + rand.nextInt(8);
|
||||
ByteBuffer[] buf = new ByteBuffer[nwriters];
|
||||
long[] position = new long[nwriters];
|
||||
for (int i=0; i<nwriters; i++) {
|
||||
buf[i] = genBuffer();
|
||||
position[i] = rand.nextInt((int)size);
|
||||
}
|
||||
|
||||
// initiate I/O
|
||||
Future[] result = new Future[nwriters];
|
||||
for (int i=0; i<nwriters; i++) {
|
||||
result[i] = ch.write(buf[i], position[i]);
|
||||
}
|
||||
|
||||
// close file
|
||||
ch.close();
|
||||
|
||||
// write operations should complete or fail with AsynchronousCloseException
|
||||
for (int i=0; i<nwriters; i++) {
|
||||
try {
|
||||
result[i].get();
|
||||
} catch (ExecutionException x) {
|
||||
Throwable cause = x.getCause();
|
||||
if (!(cause instanceof AsynchronousCloseException))
|
||||
throw new RuntimeException(cause);
|
||||
} catch (CancellationException x) {
|
||||
throw new RuntimeException(x); // should not happen
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException(x); // should not happen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// exercise cancel method
|
||||
static void testCancel(Path file) throws IOException {
|
||||
System.out.println("testCancel");
|
||||
|
||||
for (int i=0; i<2; i++) {
|
||||
boolean mayInterruptIfRunning = (i == 0) ? false : true;
|
||||
|
||||
// open with SYNC option to improve chances that write will not
|
||||
// complete immediately
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel
|
||||
.open(file, WRITE, SYNC);
|
||||
|
||||
// start write operation
|
||||
Future<Integer> res = ch.write(genBuffer(), 0L);
|
||||
|
||||
// cancel operation
|
||||
boolean cancelled = res.cancel(mayInterruptIfRunning);
|
||||
|
||||
// check post-conditions
|
||||
if (!res.isDone())
|
||||
throw new RuntimeException("isDone should return true");
|
||||
if (res.isCancelled() != cancelled)
|
||||
throw new RuntimeException("isCancelled not consistent");
|
||||
try {
|
||||
res.get();
|
||||
if (cancelled)
|
||||
throw new RuntimeException("CancellationException expected");
|
||||
} catch (CancellationException x) {
|
||||
if (!cancelled)
|
||||
throw new RuntimeException("CancellationException not expected");
|
||||
} catch (ExecutionException x) {
|
||||
throw new RuntimeException(x);
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
try {
|
||||
res.get(1, TimeUnit.SECONDS);
|
||||
if (cancelled)
|
||||
throw new RuntimeException("CancellationException expected");
|
||||
} catch (CancellationException x) {
|
||||
if (!cancelled)
|
||||
throw new RuntimeException("CancellationException not expected");
|
||||
} catch (ExecutionException x) {
|
||||
throw new RuntimeException(x);
|
||||
} catch (TimeoutException x) {
|
||||
throw new RuntimeException(x);
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
// exercise truncate method
|
||||
static void testTruncate(Path file) throws IOException {
|
||||
System.out.println("testTruncate");
|
||||
|
||||
// basic tests
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel
|
||||
.open(file, CREATE, WRITE, TRUNCATE_EXISTING);
|
||||
try {
|
||||
writeFully(ch, genBuffer(), 0L);
|
||||
long size = ch.size();
|
||||
|
||||
// attempt to truncate to a size greater than the current size
|
||||
if (ch.truncate(size + 1L).size() != size)
|
||||
throw new RuntimeException("Unexpected size after truncation");
|
||||
|
||||
// truncate file
|
||||
if (ch.truncate(size - 1L).size() != (size - 1L))
|
||||
throw new RuntimeException("Unexpected size after truncation");
|
||||
|
||||
// invalid size
|
||||
try {
|
||||
ch.truncate(-1L);
|
||||
throw new RuntimeException("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) { }
|
||||
|
||||
} finally {
|
||||
ch.close();
|
||||
}
|
||||
|
||||
// channel is closed
|
||||
try {
|
||||
ch.truncate(0L);
|
||||
throw new RuntimeException("ClosedChannelException expected");
|
||||
} catch (ClosedChannelException e) { }
|
||||
|
||||
// channel is read-only
|
||||
ch = AsynchronousFileChannel.open(file, READ);
|
||||
try {
|
||||
try {
|
||||
ch.truncate(0L);
|
||||
throw new RuntimeException("NonWritableChannelException expected");
|
||||
} catch (NonWritableChannelException e) { }
|
||||
} finally {
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
// returns ByteBuffer with random bytes
|
||||
static ByteBuffer genBuffer() {
|
||||
int size = 1024 + rand.nextInt(16000);
|
||||
byte[] buf = new byte[size];
|
||||
rand.nextBytes(buf);
|
||||
return switch (rand.nextInt(5)) {
|
||||
case 0 -> ByteBuffer.allocateDirect(buf.length)
|
||||
.put(buf)
|
||||
.flip();
|
||||
case 1 -> ByteBuffer.wrap(buf);
|
||||
case 2 -> Arena.global().allocate(buf.length).asByteBuffer()
|
||||
.put(buf)
|
||||
.flip();
|
||||
case 3 -> Arena.ofAuto().allocate(buf.length).asByteBuffer()
|
||||
.put(buf)
|
||||
.flip();
|
||||
case 4 -> Arena.ofShared().allocate(buf.length).asByteBuffer()
|
||||
.put(buf)
|
||||
.flip();
|
||||
default -> throw new InternalError("Should not reach here");
|
||||
};
|
||||
}
|
||||
|
||||
// writes all remaining bytes in the buffer to the given channel at the
|
||||
// given position
|
||||
static void writeFully(final AsynchronousFileChannel ch,
|
||||
final ByteBuffer src,
|
||||
long position)
|
||||
{
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
// use position as attachment
|
||||
ch.write(src, position, position, new CompletionHandler<Integer,Long>() {
|
||||
public void completed(Integer result, Long position) {
|
||||
int n = result;
|
||||
if (src.hasRemaining()) {
|
||||
long p = position + n;
|
||||
ch.write(src, p, p, this);
|
||||
} else {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Long position) {
|
||||
}
|
||||
});
|
||||
|
||||
// wait for writes to complete
|
||||
await(latch);
|
||||
}
|
||||
|
||||
static void readAll(final AsynchronousFileChannel ch,
|
||||
final ByteBuffer dst,
|
||||
long position)
|
||||
{
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
// use position as attachment
|
||||
ch.read(dst, position, position, new CompletionHandler<Integer,Long>() {
|
||||
public void completed(Integer result, Long position) {
|
||||
int n = result;
|
||||
if (n > 0) {
|
||||
long p = position + n;
|
||||
ch.read(dst, p, p, this);
|
||||
} else {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Long position) {
|
||||
}
|
||||
});
|
||||
|
||||
// wait for reads to complete
|
||||
await(latch);
|
||||
}
|
||||
|
||||
static void await(CountDownLatch latch) {
|
||||
// wait until done
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
try {
|
||||
latch.await();
|
||||
done = true;
|
||||
} catch (InterruptedException x) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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
|
||||
* @bug 8374382
|
||||
* @summary Test AsynchronousFileChannel.read/write with ByteBuffers and varied buffer positions
|
||||
* @run junit/othervm BufferPositions
|
||||
*/
|
||||
|
||||
import java.lang.foreign.Arena;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousFileChannel;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Stream;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class BufferPositions {
|
||||
|
||||
private static final int BUF_SIZE = 32;
|
||||
|
||||
/**
|
||||
* The buffers to test.
|
||||
*/
|
||||
static Stream<ByteBuffer> buffers() {
|
||||
List<ByteBuffer> buffers = List.of(
|
||||
ByteBuffer.allocate(BUF_SIZE),
|
||||
ByteBuffer.allocateDirect(BUF_SIZE),
|
||||
ByteBuffer.wrap(new byte[BUF_SIZE]),
|
||||
Arena.global().allocate(BUF_SIZE).asByteBuffer(),
|
||||
Arena.ofAuto().allocate(BUF_SIZE).asByteBuffer(),
|
||||
Arena.ofShared().allocate(BUF_SIZE).asByteBuffer()
|
||||
);
|
||||
Stream<ByteBuffer> slices = buffers.stream()
|
||||
.map(bb -> bb.slice(1, bb.capacity() - 1));
|
||||
return Stream.concat(buffers.stream(), slices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test using an AsynchronousFileChannel to read bytes into the given buffer.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("buffers")
|
||||
void testRead(ByteBuffer bb) throws Exception {
|
||||
Path file = Files.createTempFile(Path.of("."), "test", "dat");
|
||||
|
||||
// populate temp file
|
||||
int size = bb.capacity();
|
||||
byte[] contents = new byte[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
contents[i] = (byte)(i + 1);
|
||||
}
|
||||
Files.write(file, contents);
|
||||
|
||||
// read bytes using the buffer as the destination and all possible buffer positions
|
||||
try (AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, READ)) {
|
||||
for (int filePosition = 0; filePosition < size; filePosition++) {
|
||||
for (int bufPos = 0; bufPos < size; bufPos++) {
|
||||
// read one byte
|
||||
bb.position(bufPos);
|
||||
bb.limit(bufPos + 1);
|
||||
int n = read(ch, filePosition, bb);
|
||||
assertEquals(1, n);
|
||||
assertEquals(bufPos + 1, bb.position());
|
||||
assertEquals(contents[filePosition], bb.get(bufPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test using an AsynchronousFileChannel to write bytes from the given buffer.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("buffers")
|
||||
void testWrite(ByteBuffer bb) throws Exception {
|
||||
Path file = Files.createTempFile(Path.of("."), "test", "dat");
|
||||
|
||||
// populate temp file, all zeros
|
||||
int size = bb.capacity();
|
||||
byte[] contents = new byte[size];
|
||||
Files.write(file, contents);
|
||||
|
||||
// write bytes using the buffer as the source and all possible buffer positions
|
||||
try (AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, READ, WRITE)) {
|
||||
for (int filePosition = 0; filePosition < size; filePosition++) {
|
||||
for (int bufPos = 0; bufPos < size; bufPos++) {
|
||||
// write one byte
|
||||
byte b = (byte) ThreadLocalRandom.current().nextInt();
|
||||
bb.position(bufPos);
|
||||
bb.limit(bufPos + 1);
|
||||
bb.put(bufPos, b);
|
||||
int n = write(ch, filePosition, bb);
|
||||
assertEquals(1, n);
|
||||
assertEquals(bufPos + 1, bb.position());
|
||||
assertEquals(b, bb.get(bufPos));
|
||||
|
||||
// check byte was written at the expected file position
|
||||
ByteBuffer dst = ByteBuffer.allocate(1);
|
||||
int nread = ch.read(dst, filePosition).get();
|
||||
assertEquals(1, nread);
|
||||
assertEquals(b, dst.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte from a channel into the given buffer, at the given file position.
|
||||
*/
|
||||
private int read(AsynchronousFileChannel ch, long position, ByteBuffer bb) throws Exception {
|
||||
if (ThreadLocalRandom.current().nextBoolean()) {
|
||||
return ch.read(bb, position).get();
|
||||
} else {
|
||||
var handler = new Handler<Integer>();
|
||||
ch.read(bb, position, null, handler);
|
||||
return handler.result();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to a channel from the given buffer, at the given file position.
|
||||
*/
|
||||
private int write(AsynchronousFileChannel ch, long position, ByteBuffer bb) throws Exception {
|
||||
if (ThreadLocalRandom.current().nextBoolean()) {
|
||||
return ch.write(bb, position).get();
|
||||
} else {
|
||||
var handler = new Handler<Integer>();
|
||||
ch.write(bb, position, null, handler);
|
||||
return handler.result();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CompletionHandler that defines a method to await the result of an I/O operation.
|
||||
*/
|
||||
private static class Handler<T> implements CompletionHandler<T, Void> {
|
||||
T result;
|
||||
Throwable ex;
|
||||
final CountDownLatch done = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void completed(T result, Void att) {
|
||||
this.result = result;
|
||||
done.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable ex, Void att) {
|
||||
this.ex = ex;
|
||||
done.countDown();
|
||||
}
|
||||
|
||||
T result() throws InterruptedException {
|
||||
done.await();
|
||||
assertNull(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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
|
||||
* @bug 4607272 6842687
|
||||
* @summary Unit test for java.nio.channels.AsynchronousFileChannel
|
||||
* @build CustomThreadPool MyThreadFactory
|
||||
* @run main/othervm -Djava.nio.channels.DefaultThreadPool.threadFactory=MyThreadFactory CustomThreadPool
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class CustomThreadPool {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
File blah = File.createTempFile("blah", null);
|
||||
blah.deleteOnExit();
|
||||
AsynchronousFileChannel ch =
|
||||
AsynchronousFileChannel.open(blah.toPath(), READ, WRITE);
|
||||
ByteBuffer src = ByteBuffer.wrap("Scooby Snacks".getBytes());
|
||||
|
||||
final AtomicReference<Thread> invoker = new AtomicReference<Thread>();
|
||||
ch.write(src, 0, invoker,
|
||||
new CompletionHandler<Integer,AtomicReference<Thread>>() {
|
||||
public void completed(Integer result, AtomicReference<Thread> invoker) {
|
||||
invoker.set(Thread.currentThread());
|
||||
}
|
||||
public void failed(Throwable exc, AtomicReference<Thread> invoker) {
|
||||
}
|
||||
});
|
||||
Thread t;
|
||||
while ((t = invoker.get()) == null) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
ch.close();
|
||||
|
||||
// check handler was run by known thread
|
||||
if (!MyThreadFactory.created(t))
|
||||
throw new RuntimeException("Handler invoked by unknown thread");
|
||||
}
|
||||
}
|
||||
350
test/jdk/java/nio/channels/AsynchronousFileChannel/Lock.java
Normal file
350
test/jdk/java/nio/channels/AsynchronousFileChannel/Lock.java
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2020, 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
|
||||
* @bug 4607272 6814948 6842687
|
||||
* @summary Unit test for AsynchronousFileChannel#lock method
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.*;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import java.nio.channels.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class Lock {
|
||||
|
||||
static final Random rand = new Random();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length > 0 && args[0].equals("-lockworker")) {
|
||||
int port = Integer.parseInt(args[1]);
|
||||
runLockWorker(port);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
LockWorkerMirror worker = startLockWorker();
|
||||
try {
|
||||
|
||||
// create temporary file
|
||||
File blah = File.createTempFile("blah", null);
|
||||
blah.deleteOnExit();
|
||||
|
||||
// run tests
|
||||
testLockProtocol(blah, worker);
|
||||
testAsyncClose(blah, worker);
|
||||
|
||||
// eagerly clean-up
|
||||
blah.delete();
|
||||
|
||||
} finally {
|
||||
worker.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// test locking protocol
|
||||
static void testLockProtocol(File file, LockWorkerMirror worker)
|
||||
throws Exception
|
||||
{
|
||||
FileLock fl;
|
||||
|
||||
// worker VM opens file and acquires exclusive lock
|
||||
worker.open(file.getPath()).lock();
|
||||
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel
|
||||
.open(file.toPath(), READ, WRITE);
|
||||
|
||||
// this VM tries to acquire lock
|
||||
// (lock should not be acquire until released by worker VM)
|
||||
Future<FileLock> result = ch.lock();
|
||||
try {
|
||||
result.get(2, TimeUnit.SECONDS);
|
||||
throw new RuntimeException("Timeout expected");
|
||||
} catch (TimeoutException x) {
|
||||
}
|
||||
|
||||
// worker VM releases lock
|
||||
worker.unlock();
|
||||
|
||||
// this VM should now acquire lock
|
||||
fl = result.get();
|
||||
fl.release();
|
||||
|
||||
// worker VM acquires lock on range
|
||||
worker.lock(0, 10, false);
|
||||
|
||||
// this VM acquires lock on non-overlapping range
|
||||
fl = ch.lock(10, 10, false).get();
|
||||
fl.release();
|
||||
|
||||
// done
|
||||
ch.close();
|
||||
worker.close();
|
||||
}
|
||||
|
||||
// test close of channel with outstanding lock operation
|
||||
static void testAsyncClose(File file, LockWorkerMirror worker) throws Exception {
|
||||
// worker VM opens file and acquires exclusive lock
|
||||
worker.open(file.getPath()).lock();
|
||||
|
||||
for (int i=0; i<100; i++) {
|
||||
AsynchronousFileChannel ch = AsynchronousFileChannel
|
||||
.open(file.toPath(), READ, WRITE);
|
||||
|
||||
// try to lock file (should not complete because file is locked by worker)
|
||||
Future<FileLock> result = ch.lock();
|
||||
try {
|
||||
result.get(rand.nextInt(100), TimeUnit.MILLISECONDS);
|
||||
throw new RuntimeException("Timeout expected");
|
||||
} catch (TimeoutException x) {
|
||||
}
|
||||
|
||||
// close channel with lock operation outstanding
|
||||
ch.close();
|
||||
|
||||
// operation should complete with AsynchronousCloseException
|
||||
try {
|
||||
result.get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof AsynchronousCloseException)) {
|
||||
x.getCause().printStackTrace();
|
||||
throw new RuntimeException("AsynchronousCloseException expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
worker.close();
|
||||
}
|
||||
|
||||
// starts a "lock worker" in another process, returning a mirror object to
|
||||
// control the worker
|
||||
static LockWorkerMirror startLockWorker() throws Exception {
|
||||
ServerSocketChannel ssc = ServerSocketChannel.open()
|
||||
.bind(new InetSocketAddress(0));
|
||||
int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();
|
||||
|
||||
String sep = FileSystems.getDefault().getSeparator();
|
||||
|
||||
String command = System.getProperty("java.home") +
|
||||
sep + "bin" + sep + "java";
|
||||
String testClasses = System.getProperty("test.classes");
|
||||
if (testClasses != null)
|
||||
command += " -cp " + testClasses;
|
||||
command += " Lock -lockworker " + port;
|
||||
|
||||
Process p = Runtime.getRuntime().exec(command);
|
||||
IOHandler.handle(p.getInputStream());
|
||||
IOHandler.handle(p.getErrorStream());
|
||||
|
||||
// wait for worker to connect
|
||||
SocketChannel sc = ssc.accept();
|
||||
return new LockWorkerMirror(sc);
|
||||
}
|
||||
|
||||
// commands that the worker understands
|
||||
static final String OPEN_CMD = "open";
|
||||
static final String CLOSE_CMD = "close";
|
||||
static final String LOCK_CMD = "lock";
|
||||
static final String UNLOCK_CMD = "unlock";
|
||||
static final char TERMINATOR = ';';
|
||||
|
||||
// provides a proxy to a "lock worker"
|
||||
static class LockWorkerMirror {
|
||||
private final SocketChannel sc;
|
||||
|
||||
LockWorkerMirror(SocketChannel sc) {
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
private void sendCommand(String cmd, String... params)
|
||||
throws IOException
|
||||
{
|
||||
for (String s: params) {
|
||||
cmd += " " + s;
|
||||
}
|
||||
cmd += TERMINATOR;
|
||||
|
||||
ByteBuffer buf = Charset.defaultCharset().encode(cmd);
|
||||
while (buf.hasRemaining()) {
|
||||
sc.write(buf);
|
||||
}
|
||||
|
||||
// wait for ack
|
||||
buf = ByteBuffer.allocate(1);
|
||||
int n = sc.read(buf);
|
||||
if (n != 1)
|
||||
throw new RuntimeException("Reply expected");
|
||||
if (buf.get(0) != TERMINATOR)
|
||||
throw new RuntimeException("Terminated expected");
|
||||
}
|
||||
|
||||
LockWorkerMirror open(String file) throws IOException {
|
||||
sendCommand(OPEN_CMD, file);
|
||||
return this;
|
||||
}
|
||||
|
||||
void close() throws IOException {
|
||||
sendCommand(CLOSE_CMD);
|
||||
}
|
||||
|
||||
LockWorkerMirror lock() throws IOException {
|
||||
sendCommand(LOCK_CMD);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
LockWorkerMirror lock(long position, long size, boolean shared)
|
||||
throws IOException
|
||||
{
|
||||
sendCommand(LOCK_CMD, position + "," + size + "," + shared);
|
||||
return this;
|
||||
}
|
||||
|
||||
LockWorkerMirror unlock() throws IOException {
|
||||
sendCommand(UNLOCK_CMD);
|
||||
return this;
|
||||
}
|
||||
|
||||
void shutdown() throws IOException {
|
||||
sc.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class to direct process output to the parent System.out
|
||||
static class IOHandler implements Runnable {
|
||||
private final InputStream in;
|
||||
|
||||
IOHandler(InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
static void handle(InputStream in) {
|
||||
IOHandler handler = new IOHandler(in);
|
||||
Thread thr = new Thread(handler);
|
||||
thr.setDaemon(true);
|
||||
thr.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
byte b[] = new byte[100];
|
||||
for (;;) {
|
||||
int n = in.read(b);
|
||||
if (n < 0) return;
|
||||
for (int i=0; i<n; i++) {
|
||||
System.out.print((char)b[i]);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) { }
|
||||
}
|
||||
}
|
||||
|
||||
// worker process that responds to simple commands a socket connection
|
||||
static void runLockWorker(int port) throws Exception {
|
||||
|
||||
// establish connection to parent
|
||||
SocketChannel sc = SocketChannel.open(new InetSocketAddress(port));
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
|
||||
|
||||
FileChannel fc = null;
|
||||
FileLock fl = null;
|
||||
try {
|
||||
for (;;) {
|
||||
|
||||
// read command (ends with ";")
|
||||
buf.clear();
|
||||
int n, last = 0;
|
||||
do {
|
||||
n = sc.read(buf);
|
||||
if (n < 0)
|
||||
return;
|
||||
if (n == 0)
|
||||
throw new AssertionError();
|
||||
last += n;
|
||||
} while (buf.get(last-1) != TERMINATOR);
|
||||
|
||||
// decode into command and optional parameter
|
||||
buf.flip();
|
||||
String s = Charset.defaultCharset().decode(buf).toString();
|
||||
int sp = s.indexOf(" ");
|
||||
String cmd = (sp < 0) ? s.substring(0, s.length()-1) :
|
||||
s.substring(0, sp);
|
||||
String param = (sp < 0) ? "" : s.substring(sp+1, s.length()-1);
|
||||
|
||||
// execute
|
||||
if (cmd.equals(OPEN_CMD)) {
|
||||
if (fc != null)
|
||||
throw new RuntimeException("File already open");
|
||||
fc = FileChannel.open(Paths.get(param),READ, WRITE);
|
||||
}
|
||||
if (cmd.equals(CLOSE_CMD)) {
|
||||
if (fc == null)
|
||||
throw new RuntimeException("No file open");
|
||||
fc.close();
|
||||
fc = null;
|
||||
fl = null;
|
||||
}
|
||||
if (cmd.equals(LOCK_CMD)) {
|
||||
if (fl != null)
|
||||
throw new RuntimeException("Already holding lock");
|
||||
|
||||
if (param.length() == 0) {
|
||||
fl = fc.lock();
|
||||
} else {
|
||||
String[] values = param.split(",");
|
||||
if (values.length != 3)
|
||||
throw new RuntimeException("Lock parameter invalid");
|
||||
long position = Long.parseLong(values[0]);
|
||||
long size = Long.parseLong(values[1]);
|
||||
boolean shared = Boolean.parseBoolean(values[2]);
|
||||
fl = fc.lock(position, size, shared);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd.equals(UNLOCK_CMD)) {
|
||||
if (fl == null)
|
||||
throw new RuntimeException("Not holding lock");
|
||||
fl.release();
|
||||
fl = null;
|
||||
}
|
||||
|
||||
// send reply
|
||||
byte[] reply = { TERMINATOR };
|
||||
n = sc.write(ByteBuffer.wrap(reply));
|
||||
}
|
||||
|
||||
} finally {
|
||||
sc.close();
|
||||
if (fc != null) fc.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* @bug 8184157
|
||||
* @summary Ensure that correct PendingFuture is used in Iocp completion status event handler
|
||||
* @requires (os.family == "windows")
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousFileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
public class LockReadWriteStressTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Path path = Path.of("blah");
|
||||
ByteBuffer buf = ByteBuffer.allocate(16);
|
||||
for (int i=0; i < 1000; i++) {
|
||||
try (AsynchronousFileChannel ch = AsynchronousFileChannel.open(path,READ, WRITE, CREATE)) {
|
||||
FileLock lock = ch.lock().get();
|
||||
ch.read(buf, 0).get();
|
||||
buf.rewind();
|
||||
ch.write(buf, 0).get();
|
||||
lock.release();
|
||||
buf.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* @bug 6913877
|
||||
* @summary Stress AsynchronousFileChannel.write
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class LotsOfWrites {
|
||||
static final Random rand = new Random();
|
||||
|
||||
/**
|
||||
* Asynchronously writes a known pattern to a file up to a given size,
|
||||
* counting down a latch to release waiters when done.
|
||||
*/
|
||||
static class Writer implements CompletionHandler<Integer,ByteBuffer> {
|
||||
private final File file;
|
||||
private final long size;
|
||||
private final CountDownLatch latch;
|
||||
private final AsynchronousFileChannel channel;
|
||||
|
||||
private volatile long position;
|
||||
private volatile byte nextByte;
|
||||
|
||||
private long updatePosition(long nwrote) {
|
||||
position += nwrote;
|
||||
return position;
|
||||
}
|
||||
|
||||
private ByteBuffer genNextBuffer() {
|
||||
int n = Math.min(8192 + rand.nextInt(8192), (int)(size - position));
|
||||
ByteBuffer buf = ByteBuffer.allocate(n);
|
||||
for (int i=0; i<n; i++) {
|
||||
buf.put(nextByte++);
|
||||
}
|
||||
buf.flip();
|
||||
return buf;
|
||||
}
|
||||
|
||||
// close channel and release any waiters
|
||||
private void done() {
|
||||
try {
|
||||
channel.close();
|
||||
} catch (IOException ignore) { }
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
Writer(File file, long size, CountDownLatch latch) throws IOException {
|
||||
this.file = file;
|
||||
this.size = size;
|
||||
this.latch = latch;
|
||||
this.channel = AsynchronousFileChannel.open(file.toPath(), WRITE);
|
||||
}
|
||||
|
||||
File file() {
|
||||
return file;
|
||||
}
|
||||
|
||||
long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
// initiate first write
|
||||
void start() {
|
||||
ByteBuffer buf = genNextBuffer();
|
||||
channel.write(buf, 0L, buf, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(Integer nwrote, ByteBuffer buf) {
|
||||
long pos = updatePosition(nwrote);
|
||||
if (!buf.hasRemaining()) {
|
||||
// buffer has been completely written; decide if we need to
|
||||
// write more
|
||||
if (position >= size) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
buf = genNextBuffer();
|
||||
}
|
||||
channel.write(buf, pos, buf, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, ByteBuffer buf) {
|
||||
exc.printStackTrace();
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// random number of writers
|
||||
int count = 20 + rand.nextInt(16);
|
||||
Writer[] writers = new Writer[count];
|
||||
CountDownLatch latch = new CountDownLatch(count);
|
||||
|
||||
// initiate writing to each file
|
||||
for (int i=0; i<count; i++) {
|
||||
long size = 512*1024 + rand.nextInt(512*1024);
|
||||
File blah = File.createTempFile("blah", null);
|
||||
blah.deleteOnExit();
|
||||
Writer writer = new Writer(blah, size, latch);
|
||||
writers[i] = writer;
|
||||
writer.start();
|
||||
}
|
||||
|
||||
// wait for writing to complete
|
||||
latch.await();
|
||||
|
||||
// verify content of each file
|
||||
boolean failed = false;
|
||||
byte[] buf = new byte[8192];
|
||||
for (int i=0; i<count ;i++) {
|
||||
Writer writer = writers[i];
|
||||
FileInputStream in = new FileInputStream(writer.file());
|
||||
try {
|
||||
long size = 0L;
|
||||
byte expected = 0;
|
||||
int nread = in.read(buf);
|
||||
while (nread > 0) {
|
||||
for (int j=0; j<nread; j++) {
|
||||
if (buf[j] != expected) {
|
||||
System.err.println("Unexpected contents");
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
expected++;
|
||||
}
|
||||
if (failed)
|
||||
break;
|
||||
size += nread;
|
||||
nread = in.read(buf);
|
||||
}
|
||||
if (!failed && size != writer.size()) {
|
||||
System.err.println("Unexpected size");
|
||||
failed = true;
|
||||
}
|
||||
if (failed)
|
||||
break;
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
// clean-up
|
||||
for (int i=0; i<count; i++) {
|
||||
writers[i].file().delete();
|
||||
}
|
||||
|
||||
if (failed)
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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.
|
||||
*/
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.*;
|
||||
|
||||
public class MyThreadFactory implements ThreadFactory {
|
||||
|
||||
private static final Set<Thread> threads = new HashSet<Thread>();
|
||||
|
||||
static boolean created(Thread t) {
|
||||
synchronized (threads) {
|
||||
return threads.contains(t);
|
||||
}
|
||||
}
|
||||
|
||||
public MyThreadFactory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
synchronized (threads) {
|
||||
threads.add(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2018, 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
|
||||
* @bug 4607272 6842687
|
||||
* @summary Unit test for AsynchronousServerSocketChannel
|
||||
* @modules jdk.net
|
||||
* @run main/timeout=180 Basic
|
||||
*/
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import static java.net.StandardSocketOptions.*;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPCOUNT;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPINTERVAL;
|
||||
|
||||
public class Basic {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testBind();
|
||||
testAccept();
|
||||
testSocketOptions();
|
||||
}
|
||||
|
||||
static void testBind() throws Exception {
|
||||
System.out.println("-- bind --");
|
||||
|
||||
AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel.open();
|
||||
if (ch.getLocalAddress() != null)
|
||||
throw new RuntimeException("Local address should be 'null'");
|
||||
ch.bind(new InetSocketAddress(0), 20);
|
||||
|
||||
// check local address after binding
|
||||
InetSocketAddress local = (InetSocketAddress)ch.getLocalAddress();
|
||||
if (local.getPort() == 0)
|
||||
throw new RuntimeException("Unexpected port");
|
||||
if (!local.getAddress().isAnyLocalAddress())
|
||||
throw new RuntimeException("Not bound to a wildcard address");
|
||||
|
||||
// try to re-bind
|
||||
try {
|
||||
ch.bind(new InetSocketAddress(0));
|
||||
throw new RuntimeException("AlreadyBoundException expected");
|
||||
} catch (AlreadyBoundException x) {
|
||||
}
|
||||
ch.close();
|
||||
|
||||
// check ClosedChannelException
|
||||
ch = AsynchronousServerSocketChannel.open();
|
||||
ch.close();
|
||||
try {
|
||||
ch.bind(new InetSocketAddress(0));
|
||||
throw new RuntimeException("ClosedChannelException expected");
|
||||
} catch (ClosedChannelException x) {
|
||||
}
|
||||
}
|
||||
|
||||
static void testAccept() throws Exception {
|
||||
System.out.println("-- accept --");
|
||||
|
||||
final AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
|
||||
|
||||
InetAddress lh = InetAddress.getLocalHost();
|
||||
int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
|
||||
final InetSocketAddress isa = new InetSocketAddress(lh, port);
|
||||
|
||||
// establish a few loopback connections
|
||||
for (int i=0; i<100; i++) {
|
||||
SocketChannel sc = SocketChannel.open(isa);
|
||||
AsynchronousSocketChannel ch = listener.accept().get();
|
||||
sc.close();
|
||||
ch.close();
|
||||
}
|
||||
|
||||
final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
|
||||
|
||||
// start accepting
|
||||
listener.accept((Void)null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
|
||||
public void completed(AsynchronousSocketChannel ch, Void att) {
|
||||
try {
|
||||
ch.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
exception.set(exc);
|
||||
}
|
||||
});
|
||||
|
||||
// check AcceptPendingException
|
||||
try {
|
||||
listener.accept();
|
||||
throw new RuntimeException("AcceptPendingException expected");
|
||||
} catch (AcceptPendingException x) {
|
||||
}
|
||||
|
||||
// asynchronous close
|
||||
listener.close();
|
||||
while (exception.get() == null)
|
||||
Thread.sleep(100);
|
||||
if (!(exception.get() instanceof AsynchronousCloseException))
|
||||
throw new RuntimeException("AsynchronousCloseException expected");
|
||||
|
||||
// once closed when a further attemt should throw ClosedChannelException
|
||||
try {
|
||||
listener.accept().get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("Cause of ClosedChannelException expected");
|
||||
} catch (InterruptedException x) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void testSocketOptions() throws Exception {
|
||||
System.out.println("-- socket options --");
|
||||
AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel.open();
|
||||
try {
|
||||
// check supported options
|
||||
Set<SocketOption<?>> options = ch.supportedOptions();
|
||||
boolean reuseport = options.contains(SO_REUSEPORT);
|
||||
if (!options.contains(SO_REUSEADDR))
|
||||
throw new RuntimeException("SO_REUSEADDR should be supported");
|
||||
if (!options.contains(SO_REUSEPORT) && reuseport)
|
||||
throw new RuntimeException("SO_REUSEPORT should be supported");
|
||||
if (!options.contains(SO_RCVBUF))
|
||||
throw new RuntimeException("SO_RCVBUF should be supported");
|
||||
|
||||
// allowed to change when not bound
|
||||
ch.setOption(SO_RCVBUF, 256*1024); // can't check
|
||||
int before = ch.getOption(SO_RCVBUF);
|
||||
int after = ch.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
|
||||
if (after < before)
|
||||
throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
|
||||
ch.setOption(SO_REUSEADDR, true);
|
||||
checkOption(ch, SO_REUSEADDR, true);
|
||||
ch.setOption(SO_REUSEADDR, false);
|
||||
checkOption(ch, SO_REUSEADDR, false);
|
||||
|
||||
if (reuseport) {
|
||||
ch.setOption(SO_REUSEPORT, true);
|
||||
checkOption(ch, SO_REUSEPORT, true);
|
||||
ch.setOption(SO_REUSEPORT, false);
|
||||
checkOption(ch, SO_REUSEPORT, false);
|
||||
}
|
||||
List<? extends SocketOption> extOptions = List.of(TCP_KEEPCOUNT,
|
||||
TCP_KEEPIDLE, TCP_KEEPINTERVAL);
|
||||
if (options.containsAll(extOptions)) {
|
||||
ch.setOption(TCP_KEEPIDLE, 1234);
|
||||
checkOption(ch, TCP_KEEPIDLE, 1234);
|
||||
ch.setOption(TCP_KEEPINTERVAL, 123);
|
||||
checkOption(ch, TCP_KEEPINTERVAL, 123);
|
||||
ch.setOption(TCP_KEEPCOUNT, 7);
|
||||
checkOption(ch, TCP_KEEPCOUNT, 7);
|
||||
}
|
||||
} finally {
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
static void checkOption(AsynchronousServerSocketChannel ch,
|
||||
SocketOption name, Object expectedValue)
|
||||
throws IOException
|
||||
{
|
||||
Object value = ch.getOption(name);
|
||||
if (!value.equals(expectedValue))
|
||||
throw new RuntimeException("value not as expected");
|
||||
}
|
||||
}
|
||||
947
test/jdk/java/nio/channels/AsynchronousSocketChannel/Basic.java
Normal file
947
test/jdk/java/nio/channels/AsynchronousSocketChannel/Basic.java
Normal file
|
|
@ -0,0 +1,947 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2020, 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
|
||||
* @bug 4607272 6842687 6878369 6944810 7023403
|
||||
* @summary Unit test for AsynchronousSocketChannel(use -Dseed=X to set PRNG seed)
|
||||
* @library /test/lib
|
||||
* @modules jdk.net
|
||||
* @key randomness intermittent
|
||||
* @build jdk.test.lib.RandomFactory jdk.test.lib.Utils
|
||||
* @run main/othervm/timeout=600 Basic -skipSlowConnectTest
|
||||
*/
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import static java.net.StandardSocketOptions.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import jdk.test.lib.RandomFactory;
|
||||
import java.util.List;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPCOUNT;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPINTERVAL;
|
||||
|
||||
public class Basic {
|
||||
private static final Random RAND = RandomFactory.getRandom();
|
||||
|
||||
static boolean skipSlowConnectTest = false;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (String arg: args) {
|
||||
switch (arg) {
|
||||
case "-skipSlowConnectTest" :
|
||||
skipSlowConnectTest = true;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unrecognized argument: " + arg);
|
||||
}
|
||||
}
|
||||
|
||||
testBind();
|
||||
testSocketOptions();
|
||||
testConnect();
|
||||
testCloseWhenPending();
|
||||
testCancel();
|
||||
testRead1();
|
||||
testRead2();
|
||||
testRead3();
|
||||
testWrite1();
|
||||
testWrite2();
|
||||
// skip timeout tests until 7052549 is fixed
|
||||
if (!System.getProperty("os.name").startsWith("Windows"))
|
||||
testTimeout();
|
||||
testShutdown();
|
||||
}
|
||||
|
||||
static class Server implements Closeable {
|
||||
private final ServerSocketChannel ssc;
|
||||
private final InetSocketAddress address;
|
||||
|
||||
Server() throws IOException {
|
||||
this(0);
|
||||
}
|
||||
|
||||
Server(int recvBufSize) throws IOException {
|
||||
ssc = ServerSocketChannel.open();
|
||||
if (recvBufSize > 0) {
|
||||
ssc.setOption(SO_RCVBUF, recvBufSize);
|
||||
}
|
||||
ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
address = (InetSocketAddress)ssc.getLocalAddress();
|
||||
}
|
||||
|
||||
InetSocketAddress address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
SocketChannel accept() throws IOException {
|
||||
return ssc.accept();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
ssc.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void testBind() throws Exception {
|
||||
System.out.println("-- bind --");
|
||||
|
||||
try (AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()) {
|
||||
if (ch.getLocalAddress() != null)
|
||||
throw new RuntimeException("Local address should be 'null'");
|
||||
ch.bind(new InetSocketAddress(0));
|
||||
|
||||
// check local address after binding
|
||||
InetSocketAddress local = (InetSocketAddress)ch.getLocalAddress();
|
||||
if (local.getPort() == 0)
|
||||
throw new RuntimeException("Unexpected port");
|
||||
if (!local.getAddress().isAnyLocalAddress())
|
||||
throw new RuntimeException("Not bound to a wildcard address");
|
||||
|
||||
// try to re-bind
|
||||
try {
|
||||
ch.bind(new InetSocketAddress(0));
|
||||
throw new RuntimeException("AlreadyBoundException expected");
|
||||
} catch (AlreadyBoundException x) {
|
||||
}
|
||||
}
|
||||
|
||||
// check ClosedChannelException
|
||||
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.close();
|
||||
try {
|
||||
ch.bind(new InetSocketAddress(0));
|
||||
throw new RuntimeException("ClosedChannelException expected");
|
||||
} catch (ClosedChannelException x) {
|
||||
}
|
||||
}
|
||||
|
||||
static void testSocketOptions() throws Exception {
|
||||
System.out.println("-- socket options --");
|
||||
|
||||
try (AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()) {
|
||||
ch.setOption(SO_RCVBUF, 128*1024)
|
||||
.setOption(SO_SNDBUF, 128*1024)
|
||||
.setOption(SO_REUSEADDR, true);
|
||||
|
||||
// check SO_SNDBUF/SO_RCVBUF limits
|
||||
int before, after;
|
||||
before = ch.getOption(SO_SNDBUF);
|
||||
after = ch.setOption(SO_SNDBUF, Integer.MAX_VALUE).getOption(SO_SNDBUF);
|
||||
if (after < before)
|
||||
throw new RuntimeException("setOption caused SO_SNDBUF to decrease");
|
||||
before = ch.getOption(SO_RCVBUF);
|
||||
after = ch.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
|
||||
if (after < before)
|
||||
throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
|
||||
|
||||
ch.bind(new InetSocketAddress(0));
|
||||
|
||||
// default values
|
||||
if (ch.getOption(SO_KEEPALIVE))
|
||||
throw new RuntimeException("Default of SO_KEEPALIVE should be 'false'");
|
||||
if (ch.getOption(TCP_NODELAY))
|
||||
throw new RuntimeException("Default of TCP_NODELAY should be 'false'");
|
||||
|
||||
// set and check
|
||||
if (!ch.setOption(SO_KEEPALIVE, true).getOption(SO_KEEPALIVE))
|
||||
throw new RuntimeException("SO_KEEPALIVE did not change");
|
||||
if (!ch.setOption(TCP_NODELAY, true).getOption(TCP_NODELAY))
|
||||
throw new RuntimeException("SO_KEEPALIVE did not change");
|
||||
|
||||
// read others (can't check as actual value is implementation dependent)
|
||||
ch.getOption(SO_RCVBUF);
|
||||
ch.getOption(SO_SNDBUF);
|
||||
|
||||
Set<SocketOption<?>> options = ch.supportedOptions();
|
||||
boolean reuseport = options.contains(SO_REUSEPORT);
|
||||
if (reuseport) {
|
||||
if (ch.getOption(SO_REUSEPORT))
|
||||
throw new RuntimeException("Default of SO_REUSEPORT should be 'false'");
|
||||
if (!ch.setOption(SO_REUSEPORT, true).getOption(SO_REUSEPORT))
|
||||
throw new RuntimeException("SO_REUSEPORT did not change");
|
||||
}
|
||||
List<? extends SocketOption> extOptions = List.of(TCP_KEEPCOUNT,
|
||||
TCP_KEEPIDLE, TCP_KEEPINTERVAL);
|
||||
if (options.containsAll(extOptions)) {
|
||||
ch.setOption(TCP_KEEPIDLE, 1234);
|
||||
checkOption(ch, TCP_KEEPIDLE, 1234);
|
||||
ch.setOption(TCP_KEEPINTERVAL, 123);
|
||||
checkOption(ch, TCP_KEEPINTERVAL, 123);
|
||||
ch.setOption(TCP_KEEPCOUNT, 7);
|
||||
checkOption(ch, TCP_KEEPCOUNT, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkOption(AsynchronousSocketChannel sc, SocketOption name, Object expectedValue)
|
||||
throws IOException {
|
||||
Object value = sc.getOption(name);
|
||||
if (!value.equals(expectedValue)) {
|
||||
throw new RuntimeException("value not as expected");
|
||||
}
|
||||
}
|
||||
static void testConnect() throws Exception {
|
||||
System.out.println("-- connect --");
|
||||
|
||||
SocketAddress address;
|
||||
|
||||
try (Server server = new Server()) {
|
||||
address = server.address();
|
||||
|
||||
// connect to server and check local/remote addresses
|
||||
try (AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()) {
|
||||
ch.connect(address).get();
|
||||
// check local address
|
||||
if (ch.getLocalAddress() == null)
|
||||
throw new RuntimeException("Not bound to local address");
|
||||
|
||||
// check remote address
|
||||
InetSocketAddress remote = (InetSocketAddress)ch.getRemoteAddress();
|
||||
if (remote.getPort() != server.address().getPort())
|
||||
throw new RuntimeException("Connected to unexpected port");
|
||||
if (!remote.getAddress().equals(server.address().getAddress()))
|
||||
throw new RuntimeException("Connected to unexpected address");
|
||||
|
||||
// try to connect again
|
||||
try {
|
||||
ch.connect(server.address()).get();
|
||||
throw new RuntimeException("AlreadyConnectedException expected");
|
||||
} catch (AlreadyConnectedException x) {
|
||||
}
|
||||
|
||||
// clean-up
|
||||
server.accept().close();
|
||||
}
|
||||
|
||||
// check that connect fails with ClosedChannelException
|
||||
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.close();
|
||||
try {
|
||||
ch.connect(server.address()).get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("Cause of ClosedChannelException expected",
|
||||
x.getCause());
|
||||
}
|
||||
final AtomicReference<Throwable> connectException = new AtomicReference<>();
|
||||
ch.connect(server.address(), (Void)null, new CompletionHandler<Void,Void>() {
|
||||
public void completed(Void result, Void att) {
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
connectException.set(exc);
|
||||
}
|
||||
});
|
||||
while (connectException.get() == null) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
if (!(connectException.get() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("ClosedChannelException expected",
|
||||
connectException.get());
|
||||
}
|
||||
|
||||
// test that failure to connect closes the channel
|
||||
try (AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()) {
|
||||
try {
|
||||
ch.connect(address).get();
|
||||
} catch (ExecutionException x) {
|
||||
// failed to establish connection
|
||||
if (ch.isOpen())
|
||||
throw new RuntimeException("Channel should be closed");
|
||||
}
|
||||
}
|
||||
|
||||
// repeat test by connecting to a (probably) non-existent host. This
|
||||
// improves the chance that the connect will not fail immediately.
|
||||
if (!skipSlowConnectTest) {
|
||||
try (AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()) {
|
||||
try {
|
||||
ch.connect(genSocketAddress()).get();
|
||||
} catch (ExecutionException x) {
|
||||
// failed to establish connection
|
||||
if (ch.isOpen())
|
||||
throw new RuntimeException("Channel should be closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testCloseWhenPending() throws Exception {
|
||||
System.out.println("-- asynchronous close when connecting --");
|
||||
|
||||
AsynchronousSocketChannel ch;
|
||||
|
||||
// asynchronous close while connecting
|
||||
ch = AsynchronousSocketChannel.open();
|
||||
Future<Void> connectResult = ch.connect(genSocketAddress());
|
||||
|
||||
// give time to initiate the connect (SYN)
|
||||
Thread.sleep(50);
|
||||
|
||||
// close
|
||||
ch.close();
|
||||
|
||||
// check that exception is thrown in timely manner
|
||||
try {
|
||||
connectResult.get(5, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException x) {
|
||||
throw new RuntimeException("AsynchronousCloseException not thrown");
|
||||
} catch (ExecutionException x) {
|
||||
// expected
|
||||
}
|
||||
|
||||
System.out.println("-- asynchronous close when reading --");
|
||||
|
||||
try (Server server = new Server(1)) {
|
||||
ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
|
||||
ByteBuffer dst = ByteBuffer.allocateDirect(100);
|
||||
Future<Integer> result = ch.read(dst);
|
||||
|
||||
// attempt a second read - should fail with ReadPendingException
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(100);
|
||||
try {
|
||||
ch.read(buf);
|
||||
throw new RuntimeException("ReadPendingException expected");
|
||||
} catch (ReadPendingException x) {
|
||||
}
|
||||
|
||||
// close channel (should cause initial read to complete)
|
||||
SocketChannel peer = server.accept();
|
||||
ch.close();
|
||||
peer.close();
|
||||
|
||||
// check that AsynchronousCloseException is thrown
|
||||
try {
|
||||
result.get();
|
||||
throw new RuntimeException("Should not read");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof AsynchronousCloseException))
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
|
||||
System.out.println("-- asynchronous close when writing --");
|
||||
|
||||
ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
peer = server.accept();
|
||||
peer.setOption(SO_RCVBUF, 1);
|
||||
|
||||
final AtomicReference<Throwable> writeException =
|
||||
new AtomicReference<Throwable>();
|
||||
|
||||
// write bytes to fill socket buffer
|
||||
final AtomicInteger numCompleted = new AtomicInteger();
|
||||
ch.write(genBuffer(), ch, new CompletionHandler<Integer,AsynchronousSocketChannel>() {
|
||||
public void completed(Integer result, AsynchronousSocketChannel ch) {
|
||||
System.out.println("completed write to async channel: " + result);
|
||||
numCompleted.incrementAndGet();
|
||||
ch.write(genBuffer(), ch, this);
|
||||
System.out.println("started another write to async channel: " + result);
|
||||
}
|
||||
public void failed(Throwable x, AsynchronousSocketChannel ch) {
|
||||
System.out.println("failed write to async channel");
|
||||
writeException.set(x);
|
||||
}
|
||||
});
|
||||
|
||||
// give time for socket buffer to fill up -
|
||||
// take pauses until the handler is no longer being invoked
|
||||
// because all writes are being pended which guarantees that
|
||||
// the internal channel state indicates it is writing
|
||||
int prevNumCompleted = numCompleted.get();
|
||||
do {
|
||||
Thread.sleep((long)(1000 * jdk.test.lib.Utils.TIMEOUT_FACTOR));
|
||||
System.out.println("check if buffer is filled up");
|
||||
if (numCompleted.get() == prevNumCompleted) {
|
||||
break;
|
||||
}
|
||||
prevNumCompleted = numCompleted.get();
|
||||
} while (true);
|
||||
|
||||
// attempt a concurrent write -
|
||||
// should fail with WritePendingException
|
||||
try {
|
||||
System.out.println("concurrent write to async channel");
|
||||
ch.write(genBuffer());
|
||||
System.out.format("prevNumCompleted: %d, numCompleted: %d%n",
|
||||
prevNumCompleted, numCompleted.get());
|
||||
throw new RuntimeException("WritePendingException expected");
|
||||
} catch (WritePendingException x) {
|
||||
}
|
||||
|
||||
// close channel - should cause initial write to complete
|
||||
System.out.println("closing async channel...");
|
||||
ch.close();
|
||||
System.out.println("closed async channel");
|
||||
peer.close();
|
||||
|
||||
// wait for exception
|
||||
while (writeException.get() == null) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
if (!(writeException.get() instanceof AsynchronousCloseException))
|
||||
throw new RuntimeException("AsynchronousCloseException expected",
|
||||
writeException.get());
|
||||
}
|
||||
}
|
||||
|
||||
static void testCancel() throws Exception {
|
||||
System.out.println("-- cancel --");
|
||||
|
||||
try (Server server = new Server()) {
|
||||
for (int i=0; i<2; i++) {
|
||||
boolean mayInterruptIfRunning = (i == 0) ? false : true;
|
||||
|
||||
// establish loopback connection
|
||||
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
SocketChannel peer = server.accept();
|
||||
|
||||
// start read operation
|
||||
ByteBuffer buf = ByteBuffer.allocate(1);
|
||||
Future<Integer> res = ch.read(buf);
|
||||
|
||||
// cancel operation
|
||||
boolean cancelled = res.cancel(mayInterruptIfRunning);
|
||||
|
||||
// check post-conditions
|
||||
if (!res.isDone())
|
||||
throw new RuntimeException("isDone should return true");
|
||||
if (res.isCancelled() != cancelled)
|
||||
throw new RuntimeException("isCancelled not consistent");
|
||||
try {
|
||||
res.get();
|
||||
throw new RuntimeException("CancellationException expected");
|
||||
} catch (CancellationException x) {
|
||||
}
|
||||
try {
|
||||
res.get(1, TimeUnit.SECONDS);
|
||||
throw new RuntimeException("CancellationException expected");
|
||||
} catch (CancellationException x) {
|
||||
}
|
||||
|
||||
// check that the cancel doesn't impact writing to the channel
|
||||
if (!mayInterruptIfRunning) {
|
||||
buf = ByteBuffer.wrap("a".getBytes());
|
||||
ch.write(buf).get();
|
||||
}
|
||||
|
||||
ch.close();
|
||||
peer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testRead1() throws Exception {
|
||||
System.out.println("-- read (1) --");
|
||||
|
||||
try (Server server = new Server()) {
|
||||
final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
|
||||
// read with 0 bytes remaining should complete immediately
|
||||
ByteBuffer buf = ByteBuffer.allocate(1);
|
||||
buf.put((byte)0);
|
||||
int n = ch.read(buf).get();
|
||||
if (n != 0)
|
||||
throw new RuntimeException("0 expected");
|
||||
|
||||
// write bytes and close connection
|
||||
ByteBuffer src = genBuffer();
|
||||
try (SocketChannel sc = server.accept()) {
|
||||
sc.setOption(SO_SNDBUF, src.remaining());
|
||||
while (src.hasRemaining())
|
||||
sc.write(src);
|
||||
}
|
||||
|
||||
// reads should complete immediately
|
||||
final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ch.read(dst, (Void)null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer result, Void att) {
|
||||
int n = result;
|
||||
if (n > 0) {
|
||||
ch.read(dst, (Void)null, this);
|
||||
} else {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
latch.await();
|
||||
|
||||
// check buffers
|
||||
src.flip();
|
||||
dst.flip();
|
||||
if (!src.equals(dst)) {
|
||||
throw new RuntimeException("Contents differ");
|
||||
}
|
||||
|
||||
// close channel
|
||||
ch.close();
|
||||
|
||||
// check read fails with ClosedChannelException
|
||||
try {
|
||||
ch.read(dst).get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("Cause of ClosedChannelException expected",
|
||||
x.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testRead2() throws Exception {
|
||||
System.out.println("-- read (2) --");
|
||||
|
||||
try (Server server = new Server()) {
|
||||
final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
SocketChannel sc = server.accept();
|
||||
|
||||
ByteBuffer src = genBuffer();
|
||||
|
||||
// read until the buffer is full
|
||||
final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity());
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ch.read(dst, (Void)null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer result, Void att) {
|
||||
if (dst.hasRemaining()) {
|
||||
ch.read(dst, (Void)null, this);
|
||||
} else {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
// trickle the writing
|
||||
do {
|
||||
int rem = src.remaining();
|
||||
int size = (rem <= 100) ? rem : 50 + RAND.nextInt(rem - 100);
|
||||
ByteBuffer buf = ByteBuffer.allocate(size);
|
||||
for (int i=0; i<size; i++)
|
||||
buf.put(src.get());
|
||||
buf.flip();
|
||||
Thread.sleep(50 + RAND.nextInt(1500));
|
||||
while (buf.hasRemaining())
|
||||
sc.write(buf);
|
||||
} while (src.hasRemaining());
|
||||
|
||||
// wait until ascynrhonous reading has completed
|
||||
latch.await();
|
||||
|
||||
// check buffers
|
||||
src.flip();
|
||||
dst.flip();
|
||||
if (!src.equals(dst)) {
|
||||
throw new RuntimeException("Contents differ");
|
||||
}
|
||||
|
||||
sc.close();
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
// exercise scattering read
|
||||
static void testRead3() throws Exception {
|
||||
System.out.println("-- read (3) --");
|
||||
|
||||
try (Server server = new Server()) {
|
||||
final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
SocketChannel sc = server.accept();
|
||||
|
||||
ByteBuffer[] dsts = new ByteBuffer[3];
|
||||
for (int i=0; i<dsts.length; i++) {
|
||||
dsts[i] = ByteBuffer.allocateDirect(100);
|
||||
}
|
||||
|
||||
// scattering read that completes ascynhronously
|
||||
final CountDownLatch l1 = new CountDownLatch(1);
|
||||
ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, (Void)null,
|
||||
new CompletionHandler<Long,Void>() {
|
||||
public void completed(Long result, Void att) {
|
||||
long n = result;
|
||||
if (n <= 0)
|
||||
throw new RuntimeException("No bytes read");
|
||||
l1.countDown();
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
// write some bytes
|
||||
sc.write(genBuffer());
|
||||
|
||||
// read should now complete
|
||||
l1.await();
|
||||
|
||||
// write more bytes
|
||||
sc.write(genBuffer());
|
||||
|
||||
// read should complete immediately
|
||||
for (int i=0; i<dsts.length; i++) {
|
||||
dsts[i].rewind();
|
||||
}
|
||||
|
||||
final CountDownLatch l2 = new CountDownLatch(1);
|
||||
ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, (Void)null,
|
||||
new CompletionHandler<Long,Void>() {
|
||||
public void completed(Long result, Void att) {
|
||||
long n = result;
|
||||
if (n <= 0)
|
||||
throw new RuntimeException("No bytes read");
|
||||
l2.countDown();
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
l2.await();
|
||||
|
||||
ch.close();
|
||||
sc.close();
|
||||
}
|
||||
}
|
||||
|
||||
static void testWrite1() throws Exception {
|
||||
System.out.println("-- write (1) --");
|
||||
|
||||
try (Server server = new Server()) {
|
||||
final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
SocketChannel sc = server.accept();
|
||||
|
||||
// write with 0 bytes remaining should complete immediately
|
||||
ByteBuffer buf = ByteBuffer.allocate(1);
|
||||
buf.put((byte)0);
|
||||
int n = ch.write(buf).get();
|
||||
if (n != 0)
|
||||
throw new RuntimeException("0 expected");
|
||||
|
||||
// write all bytes and close connection when done
|
||||
final ByteBuffer src = genBuffer();
|
||||
ch.write(src, (Void)null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer result, Void att) {
|
||||
if (src.hasRemaining()) {
|
||||
ch.write(src, (Void)null, this);
|
||||
} else {
|
||||
try {
|
||||
ch.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
// read to EOF or buffer full
|
||||
ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100);
|
||||
do {
|
||||
n = sc.read(dst);
|
||||
} while (n > 0);
|
||||
sc.close();
|
||||
|
||||
// check buffers
|
||||
src.flip();
|
||||
dst.flip();
|
||||
if (!src.equals(dst)) {
|
||||
throw new RuntimeException("Contents differ");
|
||||
}
|
||||
|
||||
// check write fails with ClosedChannelException
|
||||
try {
|
||||
ch.read(dst).get();
|
||||
throw new RuntimeException("ExecutionException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("Cause of ClosedChannelException expected",
|
||||
x.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// exercise gathering write
|
||||
static void testWrite2() throws Exception {
|
||||
System.out.println("-- write (2) --");
|
||||
|
||||
try (Server server = new Server()) {
|
||||
final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
SocketChannel sc = server.accept();
|
||||
|
||||
// number of bytes written
|
||||
final AtomicLong bytesWritten = new AtomicLong(0);
|
||||
|
||||
// write buffers (should complete immediately)
|
||||
ByteBuffer[] srcs = genBuffers(1);
|
||||
final CountDownLatch l1 = new CountDownLatch(1);
|
||||
ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, (Void)null,
|
||||
new CompletionHandler<Long,Void>() {
|
||||
public void completed(Long result, Void att) {
|
||||
long n = result;
|
||||
if (n <= 0)
|
||||
throw new RuntimeException("No bytes read");
|
||||
bytesWritten.addAndGet(n);
|
||||
l1.countDown();
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
l1.await();
|
||||
|
||||
// set to true to signal that no more buffers should be written
|
||||
final AtomicBoolean continueWriting = new AtomicBoolean(true);
|
||||
|
||||
// write until socket buffer is full so as to create the conditions
|
||||
// for when a write does not complete immediately
|
||||
srcs = genBuffers(1);
|
||||
ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, (Void)null,
|
||||
new CompletionHandler<Long,Void>() {
|
||||
public void completed(Long result, Void att) {
|
||||
long n = result;
|
||||
if (n <= 0)
|
||||
throw new RuntimeException("No bytes written");
|
||||
bytesWritten.addAndGet(n);
|
||||
if (continueWriting.get()) {
|
||||
ByteBuffer[] srcs = genBuffers(8);
|
||||
ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS,
|
||||
(Void)null, this);
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
}
|
||||
});
|
||||
|
||||
// give time for socket buffer to fill up.
|
||||
Thread.sleep(5*1000);
|
||||
|
||||
// signal handler to stop further writing
|
||||
continueWriting.set(false);
|
||||
|
||||
// read until done
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(4096);
|
||||
long total = 0L;
|
||||
do {
|
||||
int n = sc.read(buf);
|
||||
if (n <= 0)
|
||||
throw new RuntimeException("No bytes read");
|
||||
buf.rewind();
|
||||
total += n;
|
||||
} while (total < bytesWritten.get());
|
||||
|
||||
ch.close();
|
||||
sc.close();
|
||||
}
|
||||
}
|
||||
|
||||
static void testShutdown() throws Exception {
|
||||
System.out.println("-- shutdown --");
|
||||
|
||||
try (Server server = new Server();
|
||||
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open())
|
||||
{
|
||||
ch.connect(server.address()).get();
|
||||
try (SocketChannel peer = server.accept()) {
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(1000);
|
||||
int n;
|
||||
|
||||
// check read
|
||||
ch.shutdownInput();
|
||||
n = ch.read(buf).get();
|
||||
if (n != -1)
|
||||
throw new RuntimeException("-1 expected");
|
||||
// check full with full buffer
|
||||
buf.put(new byte[100]);
|
||||
n = ch.read(buf).get();
|
||||
if (n != -1)
|
||||
throw new RuntimeException("-1 expected");
|
||||
|
||||
// check write
|
||||
ch.shutdownOutput();
|
||||
try {
|
||||
ch.write(buf).get();
|
||||
throw new RuntimeException("ClosedChannelException expected");
|
||||
} catch (ExecutionException x) {
|
||||
if (!(x.getCause() instanceof ClosedChannelException))
|
||||
throw new RuntimeException("ClosedChannelException expected",
|
||||
x.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testTimeout() throws Exception {
|
||||
System.out.println("-- timeouts --");
|
||||
testTimeout(Integer.MIN_VALUE, TimeUnit.SECONDS);
|
||||
testTimeout(-1L, TimeUnit.SECONDS);
|
||||
testTimeout(0L, TimeUnit.SECONDS);
|
||||
testTimeout(2L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
static void testTimeout(final long timeout, final TimeUnit unit) throws Exception {
|
||||
System.out.printf("---- timeout: %d ms%n", unit.toMillis(timeout));
|
||||
try (Server server = new Server()) {
|
||||
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(server.address()).get();
|
||||
|
||||
ByteBuffer dst = ByteBuffer.allocate(512);
|
||||
|
||||
final AtomicReference<Throwable> readException = new AtomicReference<Throwable>();
|
||||
|
||||
// this read should timeout if value is > 0
|
||||
ch.read(dst, timeout, unit, null, new CompletionHandler<Integer,Void>() {
|
||||
public void completed(Integer result, Void att) {
|
||||
readException.set(new RuntimeException("Should not complete"));
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
readException.set(exc);
|
||||
}
|
||||
});
|
||||
if (timeout > 0L) {
|
||||
// wait for exception
|
||||
while (readException.get() == null) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
if (!(readException.get() instanceof InterruptedByTimeoutException))
|
||||
throw new RuntimeException("InterruptedByTimeoutException expected",
|
||||
readException.get());
|
||||
|
||||
// after a timeout then further reading should throw unspecified runtime exception
|
||||
boolean exceptionThrown = false;
|
||||
try {
|
||||
ch.read(dst);
|
||||
} catch (RuntimeException x) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
if (!exceptionThrown)
|
||||
throw new RuntimeException("RuntimeException expected after timeout.");
|
||||
} else {
|
||||
Thread.sleep(1000);
|
||||
Throwable exc = readException.get();
|
||||
if (exc != null)
|
||||
throw new RuntimeException(exc);
|
||||
}
|
||||
|
||||
final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>();
|
||||
|
||||
// write bytes to fill socket buffer
|
||||
ch.write(genBuffer(), timeout, unit, ch,
|
||||
new CompletionHandler<Integer,AsynchronousSocketChannel>()
|
||||
{
|
||||
public void completed(Integer result, AsynchronousSocketChannel ch) {
|
||||
ch.write(genBuffer(), timeout, unit, ch, this);
|
||||
}
|
||||
public void failed(Throwable exc, AsynchronousSocketChannel ch) {
|
||||
writeException.set(exc);
|
||||
}
|
||||
});
|
||||
if (timeout > 0) {
|
||||
// wait for exception
|
||||
while (writeException.get() == null) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
if (!(writeException.get() instanceof InterruptedByTimeoutException))
|
||||
throw new RuntimeException("InterruptedByTimeoutException expected",
|
||||
writeException.get());
|
||||
|
||||
// after a timeout then further writing should throw unspecified runtime exception
|
||||
boolean exceptionThrown = false;
|
||||
try {
|
||||
ch.write(genBuffer());
|
||||
} catch (RuntimeException x) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
if (!exceptionThrown)
|
||||
throw new RuntimeException("RuntimeException expected after timeout.");
|
||||
} else {
|
||||
Thread.sleep(1000);
|
||||
Throwable exc = writeException.get();
|
||||
if (exc != null)
|
||||
throw new RuntimeException(exc);
|
||||
}
|
||||
|
||||
// clean-up
|
||||
server.accept().close();
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
// returns ByteBuffer with random bytes
|
||||
static ByteBuffer genBuffer() {
|
||||
int size = 1024 + RAND.nextInt(16000);
|
||||
byte[] buf = new byte[size];
|
||||
RAND.nextBytes(buf);
|
||||
boolean useDirect = RAND.nextBoolean();
|
||||
if (useDirect) {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(buf.length);
|
||||
bb.put(buf);
|
||||
bb.flip();
|
||||
return bb;
|
||||
} else {
|
||||
return ByteBuffer.wrap(buf);
|
||||
}
|
||||
}
|
||||
|
||||
// return ByteBuffer[] with random bytes
|
||||
static ByteBuffer[] genBuffers(int max) {
|
||||
int len = 1;
|
||||
if (max > 1)
|
||||
len += RAND.nextInt(max);
|
||||
ByteBuffer[] bufs = new ByteBuffer[len];
|
||||
for (int i=0; i<len; i++)
|
||||
bufs[i] = genBuffer();
|
||||
return bufs;
|
||||
}
|
||||
|
||||
// return random SocketAddress
|
||||
static SocketAddress genSocketAddress() {
|
||||
StringBuilder sb = new StringBuilder("10.");
|
||||
sb.append(RAND.nextInt(256));
|
||||
sb.append('.');
|
||||
sb.append(RAND.nextInt(256));
|
||||
sb.append('.');
|
||||
sb.append(RAND.nextInt(256));
|
||||
InetAddress rh;
|
||||
try {
|
||||
rh = InetAddress.getByName(sb.toString());
|
||||
} catch (UnknownHostException x) {
|
||||
throw new InternalError("Should not happen");
|
||||
}
|
||||
return new InetSocketAddress(rh, RAND.nextInt(65535)+1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2026, 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
|
||||
* @bug 8202252
|
||||
* @run junit CompletionHandlerRelease
|
||||
* @summary Verify that reference to CompletionHandler is cleared after use
|
||||
*/
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import static java.net.StandardSocketOptions.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousChannelGroup;
|
||||
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||
import java.nio.channels.AsynchronousSocketChannel;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
public class CompletionHandlerRelease {
|
||||
@Test
|
||||
public void testConnect() throws Exception {
|
||||
try (Server server = new Server()) {
|
||||
try (AsynchronousSocketChannel ch =
|
||||
AsynchronousSocketChannel.open(GROUP)) {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Handler<Void,Object> handler =
|
||||
new Handler<Void,Object>("connect", latch);
|
||||
ReferenceQueue queue = new ReferenceQueue<WeakReference>();
|
||||
WeakReference<Object> ref =
|
||||
new WeakReference<Object>(handler, queue);
|
||||
|
||||
ch.connect(server.address(), null, handler);
|
||||
|
||||
try { latch.await(); } catch (InterruptedException ignore) { }
|
||||
|
||||
handler = null;
|
||||
waitForRefToClear(ref, queue);
|
||||
|
||||
server.accept().get().close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite() throws Exception {
|
||||
try (Server server = new Server();
|
||||
AsynchronousSocketChannel ch =
|
||||
AsynchronousSocketChannel.open(GROUP)) {
|
||||
ch.connect(server.address()).get();
|
||||
|
||||
try (AsynchronousSocketChannel sc = server.accept().get()) {
|
||||
ByteBuffer src = ByteBuffer.wrap("hello".getBytes("UTF-8"));
|
||||
sc.setOption(SO_SNDBUF, src.remaining());
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Handler<Integer,Object> handler =
|
||||
new Handler<Integer,Object>("write", latch);
|
||||
ReferenceQueue queue = new ReferenceQueue<WeakReference>();
|
||||
WeakReference<Object> ref =
|
||||
new WeakReference<Object>(handler, queue);
|
||||
|
||||
sc.write(src, null, handler);
|
||||
|
||||
try { latch.await(); } catch (InterruptedException ignore) { }
|
||||
|
||||
handler = null;
|
||||
waitForRefToClear(ref, queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead() throws Exception {
|
||||
try (Server server = new Server();
|
||||
AsynchronousSocketChannel ch =
|
||||
AsynchronousSocketChannel.open(GROUP)) {
|
||||
ch.connect(server.address()).get();
|
||||
|
||||
try (AsynchronousSocketChannel sc = server.accept().get()) {
|
||||
ByteBuffer src = ByteBuffer.wrap("hello".getBytes("UTF-8"));
|
||||
sc.setOption(SO_SNDBUF, src.remaining());
|
||||
sc.write(src).get();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Handler<Integer,Object> handler =
|
||||
new Handler<Integer,Object>("read", latch);
|
||||
ReferenceQueue queue = new ReferenceQueue<WeakReference>();
|
||||
WeakReference<Object> ref =
|
||||
new WeakReference<Object>(handler, queue);
|
||||
|
||||
ByteBuffer dst = ByteBuffer.allocate(64);
|
||||
ch.read(dst, null, handler);
|
||||
|
||||
try { latch.await(); } catch (InterruptedException ignore) { }
|
||||
|
||||
handler = null;
|
||||
waitForRefToClear(ref, queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static AsynchronousChannelGroup GROUP;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws IOException {
|
||||
GROUP = AsynchronousChannelGroup.withFixedThreadPool(2,
|
||||
Executors.defaultThreadFactory());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanup() throws IOException {
|
||||
GROUP.shutdownNow();
|
||||
}
|
||||
|
||||
class Server implements Closeable {
|
||||
private final AsynchronousServerSocketChannel ssc;
|
||||
private final InetSocketAddress address;
|
||||
|
||||
Server() throws IOException {
|
||||
this(0);
|
||||
}
|
||||
|
||||
Server(int recvBufSize) throws IOException {
|
||||
ssc = AsynchronousServerSocketChannel.open(GROUP);
|
||||
if (recvBufSize > 0) {
|
||||
ssc.setOption(SO_RCVBUF, recvBufSize);
|
||||
}
|
||||
ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(),
|
||||
0));
|
||||
address = (InetSocketAddress)ssc.getLocalAddress();
|
||||
}
|
||||
|
||||
InetSocketAddress address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
Future<AsynchronousSocketChannel> accept() throws IOException {
|
||||
return ssc.accept();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
ssc.close();
|
||||
}
|
||||
}
|
||||
|
||||
static class Handler<V,A> implements CompletionHandler<V,A> {
|
||||
private final String name;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
Handler(String name, CountDownLatch latch) {
|
||||
this.name = name;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public void completed(V result, A attachment) {
|
||||
System.out.format("%s completed(%s, %s)%n",
|
||||
name, result, attachment);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
public void failed(Throwable exc, A attachment) {
|
||||
System.out.format("%s failed(%s, %s)%n",
|
||||
name, exc, attachment);
|
||||
exc.printStackTrace();
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitForRefToClear(Reference ref, ReferenceQueue queue)
|
||||
throws InterruptedException {
|
||||
Reference r;
|
||||
while ((r = queue.remove(20)) == null) {
|
||||
System.gc();
|
||||
}
|
||||
assertSame(ref, r);
|
||||
assertNull(r.get());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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
|
||||
* @bug 6842687
|
||||
* @summary Unit test for AsynchronousSocketChannel/AsynchronousServerSocketChannel
|
||||
*/
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Initiates I/O operation on a thread that terminates before the I/O completes.
|
||||
*/
|
||||
|
||||
public class DieBeforeComplete {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
|
||||
|
||||
InetAddress lh = InetAddress.getLocalHost();
|
||||
int port = ((InetSocketAddress) (listener.getLocalAddress())).getPort();
|
||||
final SocketAddress sa = new InetSocketAddress(lh, port);
|
||||
|
||||
// -- accept --
|
||||
|
||||
// initiate accept in a thread that dies before connection is established
|
||||
Future<AsynchronousSocketChannel> r1 =
|
||||
initiateAndDie(new Task<AsynchronousSocketChannel>() {
|
||||
public Future<AsynchronousSocketChannel> run() {
|
||||
return listener.accept();
|
||||
}});
|
||||
|
||||
// establish and accept connection
|
||||
SocketChannel peer = SocketChannel.open(sa);
|
||||
final AsynchronousSocketChannel channel = r1.get();
|
||||
|
||||
// --- read --
|
||||
|
||||
// initiate read in a thread that dies befores bytes are available
|
||||
final ByteBuffer dst = ByteBuffer.allocate(100);
|
||||
Future<Integer> r2 = initiateAndDie(new Task<Integer>() {
|
||||
public Future<Integer> run() {
|
||||
return channel.read(dst);
|
||||
}});
|
||||
|
||||
// send bytes
|
||||
peer.write(ByteBuffer.wrap("hello".getBytes()));
|
||||
int nread = r2.get();
|
||||
if (nread <= 0)
|
||||
throw new RuntimeException("Should have read at least one byte");
|
||||
|
||||
// -- write --
|
||||
|
||||
// initiate writes in threads that dies
|
||||
boolean completedImmediately;
|
||||
Future<Integer> r3;
|
||||
do {
|
||||
final ByteBuffer src = ByteBuffer.wrap(new byte[10000]);
|
||||
r3 = initiateAndDie(new Task<Integer>() {
|
||||
public Future<Integer> run() {
|
||||
return channel.write(src);
|
||||
}});
|
||||
try {
|
||||
int nsent = r3.get(5, TimeUnit.SECONDS);
|
||||
if (nsent <= 0)
|
||||
throw new RuntimeException("Should have wrote at least one byte");
|
||||
completedImmediately = true;
|
||||
} catch (TimeoutException x) {
|
||||
completedImmediately = false;
|
||||
}
|
||||
} while (completedImmediately);
|
||||
|
||||
// drain connection
|
||||
peer.configureBlocking(false);
|
||||
ByteBuffer src = ByteBuffer.allocateDirect(10000);
|
||||
do {
|
||||
src.clear();
|
||||
nread = peer.read(src);
|
||||
if (nread == 0) {
|
||||
Thread.sleep(100);
|
||||
nread = peer.read(src);
|
||||
}
|
||||
} while (nread > 0);
|
||||
|
||||
// write should complete now
|
||||
int nsent = r3.get();
|
||||
if (nsent <= 0)
|
||||
throw new RuntimeException("Should have wrote at least one byte");
|
||||
}
|
||||
|
||||
static interface Task<T> {
|
||||
Future<T> run();
|
||||
}
|
||||
|
||||
static <T> Future<T> initiateAndDie(final Task<T> task) {
|
||||
final AtomicReference<Future<T>> result = new AtomicReference<Future<T>>();
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
result.set(task.run());
|
||||
}
|
||||
};
|
||||
Thread t = new Thread(r);
|
||||
t.start();
|
||||
while (t.isAlive()) {
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException x) {
|
||||
}
|
||||
}
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
134
test/jdk/java/nio/channels/AsynchronousSocketChannel/Leaky.java
Normal file
134
test/jdk/java/nio/channels/AsynchronousSocketChannel/Leaky.java
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 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
|
||||
* @bug 4607272 6999915 7185340
|
||||
* @summary Unit test for AsynchronousSocketChannel
|
||||
* @modules java.management
|
||||
* @run main/othervm -XX:+DisableExplicitGC -XX:MaxDirectMemorySize=75m Leaky
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.lang.management.BufferPoolMXBean;
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
/**
|
||||
* Heap buffers must be substituted with direct buffers when doing I/O. This
|
||||
* test creates a scenario on Windows that challenges the per-thread buffer
|
||||
* cache and quickly leads to an OutOfMemoryError if temporary buffers are
|
||||
* not returned to the native heap.
|
||||
*/
|
||||
|
||||
public class Leaky {
|
||||
|
||||
static final int K = 1024;
|
||||
|
||||
static class Connection {
|
||||
private final AsynchronousSocketChannel client;
|
||||
private final SocketChannel peer;
|
||||
private final ByteBuffer dst;
|
||||
private Future<Integer> readResult;
|
||||
|
||||
Connection(AsynchronousChannelGroup group) throws Exception {
|
||||
ServerSocketChannel ssc =
|
||||
ServerSocketChannel.open().bind(new InetSocketAddress(0));
|
||||
InetAddress lh = InetAddress.getLocalHost();
|
||||
int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();
|
||||
SocketAddress remote = new InetSocketAddress(lh, port);
|
||||
client = AsynchronousSocketChannel.open(group);
|
||||
client.connect(remote).get();
|
||||
peer = ssc.accept();
|
||||
ssc.close();
|
||||
dst = ByteBuffer.allocate(K*K);
|
||||
}
|
||||
|
||||
void startRead() {
|
||||
dst.clear();
|
||||
readResult = client.read(dst);
|
||||
}
|
||||
|
||||
void write() throws Exception {
|
||||
peer.write(ByteBuffer.wrap("X".getBytes()));
|
||||
}
|
||||
|
||||
void finishRead() throws Exception {
|
||||
readResult.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ThreadFactory threadFactory = new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
};
|
||||
AsynchronousChannelGroup group =
|
||||
AsynchronousChannelGroup.withFixedThreadPool(4, threadFactory);
|
||||
|
||||
final int CONNECTION_COUNT = 10;
|
||||
Connection[] connections = new Connection[CONNECTION_COUNT];
|
||||
for (int i=0; i<CONNECTION_COUNT; i++) {
|
||||
connections[i] = new Connection(group);
|
||||
}
|
||||
|
||||
for (int i=0; i<1024; i++) {
|
||||
// initiate reads
|
||||
for (Connection conn: connections) {
|
||||
conn.startRead();
|
||||
}
|
||||
|
||||
// write data so that the read can complete
|
||||
for (Connection conn: connections) {
|
||||
conn.write();
|
||||
}
|
||||
|
||||
// complete read
|
||||
for (Connection conn: connections) {
|
||||
conn.finishRead();
|
||||
}
|
||||
}
|
||||
|
||||
// print summary of buffer pool usage
|
||||
List<BufferPoolMXBean> pools =
|
||||
ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
|
||||
for (BufferPoolMXBean pool: pools)
|
||||
System.out.format(" %8s ", pool.getName());
|
||||
System.out.println();
|
||||
for (int i=0; i<pools.size(); i++)
|
||||
System.out.format("%6s %10s %10s ", "Count", "Capacity", "Memory");
|
||||
System.out.println();
|
||||
for (BufferPoolMXBean pool: pools) {
|
||||
System.out.format("%6d %10d %10d ",
|
||||
pool.getCount(), pool.getTotalCapacity(), pool.getMemoryUsed());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2025, 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
|
||||
* @bug 6834246 6842687
|
||||
* @summary Stress test connections through the loopback interface
|
||||
* @run main StressLoopback
|
||||
* @run main/othervm/timeout=480 -Djdk.net.useFastTcpLoopback StressLoopback
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.net.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Random;
|
||||
import java.io.IOException;
|
||||
|
||||
public class StressLoopback {
|
||||
static final Random rand = new Random();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// setup listener
|
||||
AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
|
||||
int port =((InetSocketAddress)(listener.getLocalAddress())).getPort();
|
||||
InetAddress lh = InetAddress.getLocalHost();
|
||||
SocketAddress remote = new InetSocketAddress(lh, port);
|
||||
|
||||
// create sources and sinks
|
||||
int count = 2 + rand.nextInt(9);
|
||||
Source[] source = new Source[count];
|
||||
Sink[] sink = new Sink[count];
|
||||
for (int i=0; i<count; i++) {
|
||||
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
|
||||
ch.connect(remote).get();
|
||||
source[i] = new Source(ch);
|
||||
sink[i] = new Sink(listener.accept().get());
|
||||
}
|
||||
|
||||
// start the sinks and sources
|
||||
for (int i=0; i<count; i++) {
|
||||
sink[i].start();
|
||||
source[i].start();
|
||||
}
|
||||
|
||||
// let the test run for a while
|
||||
Thread.sleep(20*1000);
|
||||
|
||||
// wait until everyone is done
|
||||
boolean failed = false;
|
||||
long total = 0L;
|
||||
for (int i=0; i<count; i++) {
|
||||
long nwrote = source[i].finish();
|
||||
long nread = sink[i].finish();
|
||||
if (nread != nwrote)
|
||||
failed = true;
|
||||
System.out.format("%d -> %d (%s)\n",
|
||||
nwrote, nread, (failed) ? "FAIL" : "PASS");
|
||||
total += nwrote;
|
||||
}
|
||||
if (failed)
|
||||
throw new RuntimeException("Test failed - see log for details");
|
||||
System.out.format("Total sent %d MB\n", total / (1024L * 1024L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes bytes to a channel until "done". When done the channel is closed.
|
||||
*/
|
||||
static class Source {
|
||||
private final AsynchronousByteChannel channel;
|
||||
private final ByteBuffer sentBuffer;
|
||||
private volatile long bytesSent;
|
||||
private volatile boolean finished;
|
||||
|
||||
Source(AsynchronousByteChannel channel) {
|
||||
this.channel = channel;
|
||||
int size = 1024 + rand.nextInt(10000);
|
||||
this.sentBuffer = (rand.nextBoolean()) ?
|
||||
ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size);
|
||||
}
|
||||
|
||||
void start() {
|
||||
sentBuffer.position(0);
|
||||
sentBuffer.limit(sentBuffer.capacity());
|
||||
channel.write(sentBuffer, (Void)null, new CompletionHandler<Integer,Void> () {
|
||||
public void completed(Integer nwrote, Void att) {
|
||||
bytesSent += nwrote;
|
||||
if (finished) {
|
||||
closeUnchecked(channel);
|
||||
} else {
|
||||
sentBuffer.position(0);
|
||||
sentBuffer.limit(sentBuffer.capacity());
|
||||
channel.write(sentBuffer, (Void)null, this);
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
exc.printStackTrace();
|
||||
closeUnchecked(channel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
long finish() {
|
||||
finished = true;
|
||||
waitUntilClosed(channel);
|
||||
return bytesSent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read bytes from a channel until EOF is received.
|
||||
*/
|
||||
static class Sink {
|
||||
private final AsynchronousByteChannel channel;
|
||||
private final ByteBuffer readBuffer;
|
||||
private volatile long bytesRead;
|
||||
|
||||
Sink(AsynchronousByteChannel channel) {
|
||||
this.channel = channel;
|
||||
int size = 1024 + rand.nextInt(10000);
|
||||
this.readBuffer = (rand.nextBoolean()) ?
|
||||
ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size);
|
||||
}
|
||||
|
||||
void start() {
|
||||
channel.read(readBuffer, (Void)null, new CompletionHandler<Integer,Void> () {
|
||||
public void completed(Integer nread, Void att) {
|
||||
if (nread < 0) {
|
||||
closeUnchecked(channel);
|
||||
} else {
|
||||
bytesRead += nread;
|
||||
readBuffer.clear();
|
||||
channel.read(readBuffer, (Void)null, this);
|
||||
}
|
||||
}
|
||||
public void failed(Throwable exc, Void att) {
|
||||
exc.printStackTrace();
|
||||
closeUnchecked(channel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
long finish() {
|
||||
waitUntilClosed(channel);
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
static void waitUntilClosed(Channel c) {
|
||||
while (c.isOpen()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ignore) { }
|
||||
}
|
||||
}
|
||||
|
||||
static void closeUnchecked(Channel c) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
160
test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java
Normal file
160
test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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
|
||||
* @bug 8361495
|
||||
* @summary Test for AsynchronousCloseException from uninterruptible FileChannel
|
||||
* @run junit AsyncCloseStreams
|
||||
*/
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class AsyncCloseStreams {
|
||||
private static final Closeable STOP = () -> { };
|
||||
|
||||
private static Thread startCloseThread(LinkedTransferQueue<Closeable> q) {
|
||||
return Thread.ofPlatform().start(() -> {
|
||||
try {
|
||||
Closeable c;
|
||||
while((c = q.take()) != STOP) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void available() throws InterruptedException, IOException {
|
||||
var close = new LinkedTransferQueue<Closeable>();
|
||||
Thread closeThread = startCloseThread(close);
|
||||
|
||||
try {
|
||||
Path path = Files.createTempFile(Path.of("."), "foo", "bar");
|
||||
path.toFile().deleteOnExit();
|
||||
|
||||
do {
|
||||
InputStream in = Files.newInputStream(path);
|
||||
close.offer(in);
|
||||
int available = 0;
|
||||
try {
|
||||
available = in.available();
|
||||
} catch (AsynchronousCloseException ace) {
|
||||
System.err.println("AsynchronousCloseException caught");
|
||||
break;
|
||||
} catch (ClosedChannelException ignored) {
|
||||
continue;
|
||||
} catch (Throwable t) {
|
||||
fail("Unexpected error", t);
|
||||
}
|
||||
if (available < 0) {
|
||||
fail("FAILED: available < 0");
|
||||
}
|
||||
} while (true);
|
||||
} finally {
|
||||
close.offer(STOP);
|
||||
closeThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read() throws InterruptedException, IOException {
|
||||
var close = new LinkedTransferQueue<Closeable>();
|
||||
Thread closeThread = startCloseThread(close);
|
||||
|
||||
try {
|
||||
Path path = Files.createTempFile(Path.of("."), "foo", "bar");
|
||||
path.toFile().deleteOnExit();
|
||||
byte[] bytes = new byte[100_000];
|
||||
Arrays.fill(bytes, (byte)27);
|
||||
Files.write(path, bytes);
|
||||
|
||||
do {
|
||||
InputStream in = Files.newInputStream(path);
|
||||
close.offer(in);
|
||||
int value = 0;
|
||||
try {
|
||||
value = in.read();
|
||||
} catch (AsynchronousCloseException ace) {
|
||||
System.err.println("AsynchronousCloseException caught");
|
||||
break;
|
||||
} catch (ClosedChannelException ignored) {
|
||||
continue;
|
||||
} catch (Throwable t) {
|
||||
fail("Unexpected error", t);
|
||||
}
|
||||
if (value < 0) {
|
||||
fail("FAILED: value < 0");
|
||||
}
|
||||
} while (true);
|
||||
} finally {
|
||||
close.offer(STOP);
|
||||
closeThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void write() throws InterruptedException, IOException {
|
||||
var close = new LinkedTransferQueue<Closeable>();
|
||||
Thread closeThread = startCloseThread(close);
|
||||
|
||||
try {
|
||||
Path path = Files.createTempFile(Path.of("."), "foo", "bar");
|
||||
path.toFile().deleteOnExit();
|
||||
byte[] bytes = new byte[100_000];
|
||||
Arrays.fill(bytes, (byte)27);
|
||||
|
||||
do {
|
||||
OutputStream out = Files.newOutputStream(path);
|
||||
close.offer(out);
|
||||
try {
|
||||
out.write(bytes);
|
||||
} catch (AsynchronousCloseException ace) {
|
||||
System.err.println("AsynchronousCloseException caught");
|
||||
break;
|
||||
} catch (ClosedChannelException ignored) {
|
||||
} catch (Throwable t) {
|
||||
fail("Write error", t);
|
||||
}
|
||||
} while (true);
|
||||
} finally {
|
||||
close.offer(STOP);
|
||||
closeThread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
514
test/jdk/java/nio/channels/Channels/Basic.java
Normal file
514
test/jdk/java/nio/channels/Channels/Basic.java
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2021, 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
|
||||
* @bug 4417152 4481572 6248930 6725399 6884800 8220477 8275149
|
||||
* @summary Test Channels basic functionality
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.charset.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
public class Basic {
|
||||
|
||||
static String message;
|
||||
|
||||
static String encoding;
|
||||
|
||||
static File blah;
|
||||
|
||||
static int ITERATIONS = 500;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
message = "ascii data for a test";
|
||||
encoding = "ISO-8859-1";
|
||||
test();
|
||||
message = "\ucafe\ubabe\ucafe\ubabe\ucafe\ubabe";
|
||||
encoding = "UTF-8";
|
||||
test();
|
||||
}
|
||||
|
||||
static void failNpeExpected() {
|
||||
throw new RuntimeException("Did not get the expected NullPointerException.");
|
||||
}
|
||||
|
||||
private static void test() throws Exception {
|
||||
//Test if methods of Channels throw NPE with null argument(s)
|
||||
try {
|
||||
Channels.newInputStream((ReadableByteChannel)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newOutputStream((WritableByteChannel)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
ReadableByteChannel channel = Channels.newChannel((InputStream)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException ne) {} // OK. As expected.
|
||||
|
||||
try {
|
||||
WritableByteChannel channel = Channels.newChannel((OutputStream)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException ne) {} // OK. As expected.
|
||||
|
||||
WritableByteChannel wbc = new WritableByteChannel() {
|
||||
public int write(ByteBuffer src) { return 0; }
|
||||
public void close() throws IOException { }
|
||||
public boolean isOpen() { return true; }
|
||||
};
|
||||
|
||||
ReadableByteChannel rbc = new ReadableByteChannel() {
|
||||
public int read(ByteBuffer dst) { return 0; }
|
||||
public void close() {}
|
||||
public boolean isOpen() { return true; }
|
||||
};
|
||||
|
||||
try {
|
||||
Channels.newReader((ReadableByteChannel)null,
|
||||
Charset.defaultCharset().newDecoder(),
|
||||
-1);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newReader(rbc, (CharsetDecoder)null, -1);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newReader((ReadableByteChannel)null,
|
||||
Charset.defaultCharset().name());
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newReader(rbc, (String)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
|
||||
try {
|
||||
Channels.newReader(null, (String)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newReader(rbc, (Charset)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
|
||||
try {
|
||||
Channels.newReader(null, (Charset)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter((WritableByteChannel)null,
|
||||
Charset.defaultCharset().newEncoder(),
|
||||
-1);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter(null, null, -1);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter(wbc, null, -1);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter((WritableByteChannel)null,
|
||||
Charset.defaultCharset().name());
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter(wbc, (String)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter(null, (String)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter(wbc, (Charset)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
Channels.newWriter(null, (Charset)null);
|
||||
failNpeExpected();
|
||||
} catch (NullPointerException npe) {}
|
||||
|
||||
try {
|
||||
blah = File.createTempFile("blah", null);
|
||||
|
||||
testNewOutputStream(blah);
|
||||
readAndCheck(blah);
|
||||
blah.delete();
|
||||
|
||||
writeOut(blah, ITERATIONS);
|
||||
testNewInputStream(blah);
|
||||
blah.delete();
|
||||
|
||||
testNewChannelOut(blah);
|
||||
readAndCheck(blah);
|
||||
blah.delete();
|
||||
|
||||
testNewChannelWriteAfterClose(blah);
|
||||
|
||||
testNewChannelReadAfterClose(blah);
|
||||
blah.delete();
|
||||
|
||||
writeOut(blah, ITERATIONS);
|
||||
testNewChannelIn(blah);
|
||||
test4481572(blah);
|
||||
blah.delete();
|
||||
|
||||
testNewWriter(blah);
|
||||
readAndCheck(blah);
|
||||
blah.delete();
|
||||
|
||||
writeOut(blah, ITERATIONS);
|
||||
testNewReader(blah);
|
||||
|
||||
testNewWriterClose();
|
||||
testNewReaderClose();
|
||||
} finally {
|
||||
blah.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void readAndCheck(File blah) throws Exception {
|
||||
FileInputStream fis = new FileInputStream(blah);
|
||||
int messageSize = message.length() * ITERATIONS * 3 + 1;
|
||||
byte bb[] = new byte[messageSize];
|
||||
int bytesRead = 0;
|
||||
int totalRead = 0;
|
||||
while (bytesRead != -1) {
|
||||
totalRead += bytesRead;
|
||||
bytesRead = fis.read(bb, totalRead, messageSize - totalRead);
|
||||
}
|
||||
String result = new String(bb, 0, totalRead, encoding);
|
||||
int len = message.length();
|
||||
for (int i=0; i<ITERATIONS; i++) {
|
||||
String segment = result.substring(i++ * len, i * len);
|
||||
if (!segment.equals(message))
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
fis.close();
|
||||
}
|
||||
|
||||
private static void writeOut(File blah, int limit) throws Exception {
|
||||
FileOutputStream fos = new FileOutputStream(blah);
|
||||
for (int i=0; i<limit; i++)
|
||||
fos.write(message.getBytes(encoding));
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private static void testNewOutputStream(File blah) throws Exception {
|
||||
FileOutputStream fos = new FileOutputStream(blah);
|
||||
FileChannel fc = fos.getChannel();
|
||||
WritableByteChannel wbc = (WritableByteChannel)fc;
|
||||
OutputStream os = Channels.newOutputStream(wbc);
|
||||
for (int i=0; i<ITERATIONS; i++)
|
||||
os.write(message.getBytes(encoding));
|
||||
os.close();
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private static void testNewInputStream(File blah) throws Exception {
|
||||
FileInputStream fis = new FileInputStream(blah);
|
||||
FileChannel fc = fis.getChannel();
|
||||
InputStream is = Channels.newInputStream(fc);
|
||||
int messageSize = message.length() * ITERATIONS * 3 + 1;
|
||||
byte bb[] = new byte[messageSize];
|
||||
|
||||
int bytesRead = 0;
|
||||
int totalRead = 0;
|
||||
while (bytesRead != -1) {
|
||||
totalRead += bytesRead;
|
||||
long rem = Math.min(fc.size() - totalRead, (long)Integer.MAX_VALUE);
|
||||
if (is.available() != (int)rem)
|
||||
throw new RuntimeException("available not useful or not maximally useful");
|
||||
bytesRead = is.read(bb, totalRead, messageSize - totalRead);
|
||||
}
|
||||
if (is.available() != 0)
|
||||
throw new RuntimeException("available() should return 0 at EOF");
|
||||
|
||||
String result = new String(bb, 0, totalRead, encoding);
|
||||
int len = message.length();
|
||||
for (int i=0; i<ITERATIONS; i++) {
|
||||
String segment = result.substring(i++ * len, i * len);
|
||||
if (!segment.equals(message))
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
is.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
private static void testNewChannelOut(File blah) throws Exception {
|
||||
ExtendedFileOutputStream fos = new ExtendedFileOutputStream(blah);
|
||||
WritableByteChannel wbc = Channels.newChannel(fos);
|
||||
|
||||
for (int i=0; i<ITERATIONS; i++)
|
||||
wbc.write(ByteBuffer.wrap(message.getBytes(encoding)));
|
||||
wbc.close();
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private static void testNewChannelIn(File blah) throws Exception {
|
||||
ExtendedFileInputStream fis = new ExtendedFileInputStream(blah);
|
||||
ReadableByteChannel rbc = Channels.newChannel(fis);
|
||||
|
||||
int messageSize = message.length() * ITERATIONS * 3;
|
||||
byte data[] = new byte[messageSize+1];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
|
||||
try {
|
||||
rbc.read(bb.asReadOnlyBuffer());
|
||||
throw new RuntimeException("IllegalArgumentException not thrown");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
int bytesRead = 0;
|
||||
int totalRead = 0;
|
||||
while (bytesRead != -1) {
|
||||
totalRead += bytesRead;
|
||||
bytesRead = rbc.read(bb);
|
||||
}
|
||||
|
||||
String result = new String(data, 0, totalRead, encoding);
|
||||
int len = message.length();
|
||||
for (int i=0; i<ITERATIONS; i++) {
|
||||
String segment = result.substring(i++ * len, i * len);
|
||||
if (!segment.equals(message))
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
rbc.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
private static void testNewChannelWriteAfterClose(File blah)
|
||||
throws Exception {
|
||||
try (ExtendedFileOutputStream fos =
|
||||
new ExtendedFileOutputStream(blah)) {
|
||||
WritableByteChannel wbc = Channels.newChannel(fos);
|
||||
|
||||
wbc.close();
|
||||
try {
|
||||
wbc.write(ByteBuffer.allocate(0));
|
||||
throw new RuntimeException
|
||||
("No ClosedChannelException on WritableByteChannel::write");
|
||||
} catch (ClosedChannelException expected) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testNewChannelReadAfterClose(File blah)
|
||||
throws Exception {
|
||||
try (ExtendedFileInputStream fis = new ExtendedFileInputStream(blah)) {
|
||||
ReadableByteChannel rbc = Channels.newChannel(fis);
|
||||
|
||||
rbc.close();
|
||||
try {
|
||||
rbc.read(ByteBuffer.allocate(0));
|
||||
throw new RuntimeException
|
||||
("No ClosedChannelException on ReadableByteChannel::read");
|
||||
} catch (ClosedChannelException expected) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Causes BufferOverflowException if bug 4481572 is present.
|
||||
private static void test4481572(File blah) throws Exception {
|
||||
ExtendedFileInputStream fis = new ExtendedFileInputStream(blah);
|
||||
ReadableByteChannel rbc = Channels.newChannel(fis);
|
||||
|
||||
byte data[] = new byte[9000];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
|
||||
int bytesRead = 1;
|
||||
int totalRead = 0;
|
||||
while (bytesRead > 0) {
|
||||
totalRead += bytesRead;
|
||||
bytesRead = rbc.read(bb);
|
||||
}
|
||||
rbc.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
private static void testNewWriter(File blah) throws Exception {
|
||||
FileOutputStream fos = new FileOutputStream(blah);
|
||||
WritableByteChannel wbc = (WritableByteChannel)fos.getChannel();
|
||||
Writer w = Channels.newWriter(wbc, encoding);
|
||||
char data[] = new char[40];
|
||||
message.getChars(0, message.length(), data, 0);
|
||||
for (int i=0; i<ITERATIONS; i++)
|
||||
w.write(data, 0, message.length());
|
||||
w.flush();
|
||||
w.close();
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private static void testNewReader(File blah) throws Exception {
|
||||
FileInputStream fis = new FileInputStream(blah);
|
||||
ReadableByteChannel rbc = (ReadableByteChannel)fis.getChannel();
|
||||
Reader r = Channels.newReader(rbc, encoding);
|
||||
|
||||
int messageSize = message.length() * ITERATIONS;
|
||||
char data[] = new char[messageSize];
|
||||
|
||||
int totalRead = 0;
|
||||
int charsRead = 0;
|
||||
while (totalRead < messageSize) {
|
||||
totalRead += charsRead;
|
||||
charsRead = r.read(data, totalRead, messageSize - totalRead);
|
||||
}
|
||||
String result = new String(data, 0, totalRead);
|
||||
int len = message.length();
|
||||
for (int i=0; i<ITERATIONS; i++) {
|
||||
String segment = result.substring(i++ * len, i * len);
|
||||
if (!segment.equals(message))
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
r.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
private static void testNewWriterClose() throws Exception {
|
||||
Writer writer = null;
|
||||
try {
|
||||
WritableByteChannel channel = new WritableByteChannel() {
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
};
|
||||
writer = Channels.newWriter(channel,
|
||||
StandardCharsets.UTF_8.newEncoder(), -1);
|
||||
writer.close();
|
||||
} catch (IOException ioe) {
|
||||
Exception theException = null;
|
||||
try {
|
||||
writer.write(1);
|
||||
writer.flush();
|
||||
} catch (Exception e) {
|
||||
theException = e;
|
||||
} finally {
|
||||
if (theException == null) {
|
||||
throw new RuntimeException("IOException not thrown");
|
||||
} else if (!(theException instanceof IOException)) {
|
||||
throw new RuntimeException("Exception not an IOException: "
|
||||
+ theException);
|
||||
} else {
|
||||
String message = theException.getMessage();
|
||||
if (!message.equals("Stream closed")) {
|
||||
throw new RuntimeException("Unexpected message "
|
||||
+ message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testNewReaderClose() throws Exception {
|
||||
Reader reader = null;
|
||||
try {
|
||||
ReadableByteChannel channel = new ReadableByteChannel() {
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
dst.put((byte)7);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
};
|
||||
reader = Channels.newReader(channel,
|
||||
StandardCharsets.UTF_8.newDecoder(), -1);
|
||||
reader.close();
|
||||
} catch (IOException ioe) {
|
||||
Exception theException = null;
|
||||
try {
|
||||
reader.read();
|
||||
} catch (Exception e) {
|
||||
theException = e;
|
||||
} finally {
|
||||
if (theException == null) {
|
||||
throw new RuntimeException("IOException not thrown");
|
||||
} else if (!(theException instanceof IOException)) {
|
||||
throw new RuntimeException("Exception not an IOException: "
|
||||
+ theException);
|
||||
} else {
|
||||
String message = theException.getMessage();
|
||||
if (!message.equals("Stream closed")) {
|
||||
throw new RuntimeException("Unexpected message "
|
||||
+ message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExtendedFileInputStream extends java.io.FileInputStream {
|
||||
ExtendedFileInputStream(File file) throws FileNotFoundException {
|
||||
super(file);
|
||||
}
|
||||
}
|
||||
|
||||
class ExtendedFileOutputStream extends java.io.FileOutputStream {
|
||||
ExtendedFileOutputStream(File file) throws FileNotFoundException {
|
||||
super(file);
|
||||
}
|
||||
}
|
||||
176
test/jdk/java/nio/channels/Channels/Basic2.java
Normal file
176
test/jdk/java/nio/channels/Channels/Basic2.java
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2010, 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
|
||||
* @bug 4607272
|
||||
* @summary Test Channels methods for interoperability between streams and
|
||||
* asynchronous byte channels
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Random;
|
||||
|
||||
public class Basic2 {
|
||||
|
||||
static final Random rand = new Random();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// establish loopback connection
|
||||
AsynchronousServerSocketChannel listener =
|
||||
AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
|
||||
int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
|
||||
InetSocketAddress isa =
|
||||
new InetSocketAddress(InetAddress.getLocalHost(), port);
|
||||
AsynchronousSocketChannel ch1 = AsynchronousSocketChannel.open();
|
||||
ch1.connect(isa).get();
|
||||
AsynchronousSocketChannel ch2 = listener.accept().get();
|
||||
|
||||
// start thread to write to stream
|
||||
Writer writer = new Writer(Channels.newOutputStream(ch1));
|
||||
Thread writerThread = new Thread(writer);
|
||||
writerThread.start();
|
||||
|
||||
// start thread to read from stream
|
||||
Reader reader = new Reader(Channels.newInputStream(ch2));
|
||||
Thread readerThread = new Thread(reader);
|
||||
readerThread.start();
|
||||
|
||||
// wait for threads to complete
|
||||
writerThread.join();
|
||||
readerThread.join();
|
||||
|
||||
// shutdown listener
|
||||
listener.close();
|
||||
|
||||
// check that reader received what we expected
|
||||
if (reader.total() != writer.total())
|
||||
throw new RuntimeException("Unexpected number of bytes read");
|
||||
if (reader.hash() != writer.hash())
|
||||
throw new RuntimeException("Hash incorrect for bytes read");
|
||||
|
||||
// channels should be closed
|
||||
if (ch1.isOpen() || ch2.isOpen())
|
||||
throw new RuntimeException("Channels should be closed");
|
||||
}
|
||||
|
||||
static class Reader implements Runnable {
|
||||
private final InputStream in;
|
||||
private volatile int total;
|
||||
private volatile int hash;
|
||||
|
||||
Reader(InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
int n;
|
||||
do {
|
||||
// random offset/len
|
||||
byte[] buf = new byte[128 + rand.nextInt(128)];
|
||||
int len, off;
|
||||
if (rand.nextBoolean()) {
|
||||
len = buf.length;
|
||||
off = 0;
|
||||
n = in.read(buf);
|
||||
} else {
|
||||
len = 1 + rand.nextInt(64);
|
||||
off = rand.nextInt(64);
|
||||
n = in.read(buf, off, len);
|
||||
}
|
||||
if (n > len)
|
||||
throw new RuntimeException("Too many bytes read");
|
||||
if (n > 0) {
|
||||
total += n;
|
||||
for (int i=0; i<n; i++) {
|
||||
int value = buf[off + i];
|
||||
hash = hash ^ value;
|
||||
}
|
||||
}
|
||||
} while (n > 0);
|
||||
in.close();
|
||||
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
int total() { return total; }
|
||||
int hash() { return hash; }
|
||||
}
|
||||
|
||||
static class Writer implements Runnable {
|
||||
private final OutputStream out;
|
||||
private final int total;
|
||||
private volatile int hash;
|
||||
|
||||
Writer(OutputStream out) {
|
||||
this.out = out;
|
||||
this.total = 50*1000 + rand.nextInt(50*1000);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
hash = 0;
|
||||
int rem = total;
|
||||
try {
|
||||
do {
|
||||
byte[] buf = new byte[1 + rand.nextInt(rem)];
|
||||
int off, len;
|
||||
|
||||
// write random bytes
|
||||
if (rand.nextBoolean()) {
|
||||
off = 0;
|
||||
len = buf.length;
|
||||
} else {
|
||||
off = rand.nextInt(buf.length);
|
||||
int r = buf.length - off;
|
||||
len = (r <= 1) ? 1 : (1 + rand.nextInt(r));
|
||||
}
|
||||
for (int i=0; i<len; i++) {
|
||||
byte value = (byte)rand.nextInt(256);
|
||||
buf[off + i] = value;
|
||||
hash = hash ^ value;
|
||||
}
|
||||
if ((off == 0) && (len == buf.length)) {
|
||||
out.write(buf);
|
||||
} else {
|
||||
out.write(buf, off, len);
|
||||
}
|
||||
rem -= len;
|
||||
} while (rem > 0);
|
||||
|
||||
// close stream when done
|
||||
out.close();
|
||||
|
||||
} catch (IOException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
int total() { return total; }
|
||||
int hash() { return hash; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* @bug 8136895
|
||||
* @summary Verify channel closed after write error in StreamEncoder::implClose
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class CloseWriterOnFailedFlush {
|
||||
private static final String STR_IOE = "Test"; // IOException
|
||||
private static final String STR_MIE = "\ud83c"; // MalformedInputException
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
boolean failed = false;
|
||||
|
||||
for (String s : new String[] {STR_IOE, STR_MIE}) {
|
||||
System.out.println("string: " + s);
|
||||
ErroringByteChannel channel = new ErroringByteChannel();
|
||||
try (Writer writer = Channels.newWriter
|
||||
(channel, StandardCharsets.UTF_8.newEncoder(), -1 )) {
|
||||
writer.write(s);
|
||||
} catch (IOException ex) {
|
||||
Class exClass = ex.getClass();
|
||||
if (s.equals(STR_IOE) && exClass != IOException.class ||
|
||||
s.equals(STR_MIE) && exClass != MalformedInputException.class)
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (channel.isOpen()) {
|
||||
System.err.println("Channel is STILL open");
|
||||
failed = true;
|
||||
} else {
|
||||
System.out.println("Channel is closed");
|
||||
}
|
||||
}
|
||||
|
||||
if (failed)
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
|
||||
private static class ErroringByteChannel implements WritableByteChannel {
|
||||
private boolean open = true;
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
open = false;
|
||||
System.out.println("Closing");
|
||||
}
|
||||
}
|
||||
}
|
||||
210
test/jdk/java/nio/channels/Channels/ClosedNetworkChannels.java
Normal file
210
test/jdk/java/nio/channels/Channels/ClosedNetworkChannels.java
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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
|
||||
* @bug 8329190
|
||||
* @summary Test that I/O operations on a closed network channel throw ClosedChannelException
|
||||
* and not AsynchronousCloseException
|
||||
* @run junit ClosedNetworkChannels
|
||||
*/
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ClosedNetworkChannels {
|
||||
|
||||
/**
|
||||
* An operation that does not return a result but may throw an exception.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface ThrowingRunnable {
|
||||
void run() throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given operation throws ClosedChannelException.
|
||||
*/
|
||||
private void assertThrowsCCE(ThrowingRunnable op) throws Exception {
|
||||
try {
|
||||
op.run();
|
||||
fail();
|
||||
} catch (AsynchronousCloseException e) {
|
||||
fail(e + " thrown");
|
||||
} catch (ClosedChannelException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the given SocketChannel and checks that I/O ops throw ClosedChannelException.
|
||||
*/
|
||||
private void testSocketChannel(SocketChannel sc) throws Exception {
|
||||
sc.close();
|
||||
|
||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||
SocketAddress target = new InetSocketAddress(lb, 7777); // any port will do
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(100);
|
||||
ByteBuffer[] bufs = new ByteBuffer[] { bb };
|
||||
|
||||
assertThrowsCCE(() -> sc.connect(target));
|
||||
assertThrowsCCE(() -> sc.finishConnect());
|
||||
assertThrowsCCE(() -> sc.read(bb));
|
||||
assertThrowsCCE(() -> sc.read(bufs));
|
||||
assertThrowsCCE(() -> sc.read(bufs, 0, 1));
|
||||
assertThrowsCCE(() -> sc.write(bb));
|
||||
assertThrowsCCE(() -> sc.write(bufs));
|
||||
assertThrowsCCE(() -> sc.write(bufs, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that I/O operations on a closed (but previously unconnected) SocketChannel
|
||||
* throw ClosedChannelException.
|
||||
*/
|
||||
@Test
|
||||
void testUnconnectedSocketChannel() throws Exception {
|
||||
SocketChannel sc = SocketChannel.open();
|
||||
testSocketChannel(sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that I/O operations on a closed (but previously connected) SocketChannel
|
||||
* throw ClosedChannelException.
|
||||
*/
|
||||
@Test
|
||||
void testConnectedSocketChannel() throws Exception {
|
||||
try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
|
||||
ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
try (SocketChannel sc = SocketChannel.open(ssc.getLocalAddress());
|
||||
SocketChannel peer = ssc.accept()) {
|
||||
testSocketChannel(sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the accept operation on a closed (but previously unbound) ServerSocketChannel
|
||||
* throws ClosedChannelException.
|
||||
*/
|
||||
@Test
|
||||
void testUnboundServerSocketChannel() throws Exception {
|
||||
ServerSocketChannel ssc = ServerSocketChannel.open();
|
||||
ssc.close();
|
||||
assertThrowsCCE(() -> ssc.accept());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the accept operation on a closed (but previously bound) ServerSocketChannel
|
||||
* throws ClosedChannelException.
|
||||
*/
|
||||
@Test
|
||||
void testBoundServerSocketChannel() throws Exception {
|
||||
try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
|
||||
ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
ssc.close();
|
||||
assertThrowsCCE(() -> ssc.accept());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that I/O operations on a closed Pipe.SourceChannel and Pipe.SinkChannel
|
||||
* throw ClosedChannelException.
|
||||
*/
|
||||
@Test
|
||||
void testSourceAndSinkChannels() throws Exception {
|
||||
Pipe p = Pipe.open();
|
||||
try (Pipe.SourceChannel source = p.source();
|
||||
Pipe.SinkChannel sink = p.sink()) {
|
||||
source.close();
|
||||
sink.close();
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(100);
|
||||
ByteBuffer[] bufs = new ByteBuffer[]{bb};
|
||||
|
||||
assertThrowsCCE(() -> source.read(bb));
|
||||
assertThrowsCCE(() -> source.read(bufs));
|
||||
assertThrowsCCE(() -> source.read(bufs, 0, 1));
|
||||
assertThrowsCCE(() -> sink.write(bb));
|
||||
assertThrowsCCE(() -> sink.write(bufs));
|
||||
assertThrowsCCE(() -> sink.write(bufs, 0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the given DatagramChannel and checks that I/O ops throw ClosedChannelException.
|
||||
*/
|
||||
private void testDatagramChannel(DatagramChannel dc) throws Exception {
|
||||
dc.close();
|
||||
|
||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||
SocketAddress target = new InetSocketAddress(lb, 7777); // any port will do
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(100);
|
||||
ByteBuffer[] bufs = new ByteBuffer[] { bb };
|
||||
|
||||
assertThrowsCCE(() -> dc.send(bb, target));
|
||||
assertThrowsCCE(() -> dc.receive(bb));
|
||||
assertThrowsCCE(() -> dc.read(bb));
|
||||
assertThrowsCCE(() -> dc.read(bufs));
|
||||
assertThrowsCCE(() -> dc.read(bufs, 0, 1));
|
||||
assertThrowsCCE(() -> dc.write(bb));
|
||||
assertThrowsCCE(() -> dc.write(bufs));
|
||||
assertThrowsCCE(() -> dc.write(bufs, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that I/O operations on a closed (but previously unconnected) DatagramChannel
|
||||
* throw ClosedChannelException.
|
||||
*/
|
||||
@Test
|
||||
void testUnconnectedDatagramChannel() throws Exception {
|
||||
DatagramChannel dc = DatagramChannel.open();
|
||||
testDatagramChannel(dc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that I/O operations on a closed (but previously connected) DatagramChannel
|
||||
* throw ClosedChannelException.
|
||||
*/
|
||||
@Test
|
||||
void testConnectedDatagramChannel() throws Exception {
|
||||
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||
dc.bind(new InetSocketAddress(lb, 0));
|
||||
dc.connect(new InetSocketAddress(lb, 7777)); // any port will do
|
||||
testDatagramChannel(dc);
|
||||
}
|
||||
}
|
||||
}
|
||||
271
test/jdk/java/nio/channels/Channels/EncodingTest.java
Normal file
271
test/jdk/java/nio/channels/Channels/EncodingTest.java
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8183743
|
||||
* @summary Test to verify the new overload method with Charset functions the same
|
||||
* as the existing method that takes a charset name.
|
||||
* @run junit EncodingTest
|
||||
*/
|
||||
public class EncodingTest {
|
||||
static final int ITERATIONS = 2;
|
||||
public static final String CS_UTF8 = StandardCharsets.UTF_8.name();
|
||||
public static final String CS_ISO8859 = StandardCharsets.ISO_8859_1.name();
|
||||
static String USER_DIR = System.getProperty("user.dir", ".");
|
||||
|
||||
// malformed input: a high surrogate without the low surrogate
|
||||
static char[] illChars = {
|
||||
'\u00fa', '\ud800'
|
||||
};
|
||||
|
||||
static byte[] data = getData();
|
||||
|
||||
static byte[] getData() {
|
||||
try {
|
||||
String str1 = "A string that contains ";
|
||||
String str2 = " , an invalid character for UTF-8.";
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(str1.getBytes());
|
||||
baos.write(0xFA);
|
||||
baos.write(str2.getBytes());
|
||||
return baos.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
return null; //shouldn't happen
|
||||
}
|
||||
}
|
||||
|
||||
static String testFile = Paths.get(USER_DIR, "channelsEncodingTest.txt").toString();
|
||||
static String testIllegalInput = Paths.get(USER_DIR, "channelsIllegalInputTest.txt").toString();
|
||||
static String testIllegalOutput = Paths.get(USER_DIR, "channelsIllegalOutputTest.txt").toString();
|
||||
|
||||
|
||||
/*
|
||||
* DataProvider for read and write test.
|
||||
* Writes and reads with the same encoding
|
||||
*/
|
||||
public static Stream<Arguments> writeAndRead() {
|
||||
return Stream.of
|
||||
(Arguments.of(testFile, StandardCharsets.ISO_8859_1.name(), null,
|
||||
StandardCharsets.ISO_8859_1.name(), StandardCharsets.ISO_8859_1),
|
||||
Arguments.of(testFile, null, StandardCharsets.ISO_8859_1,
|
||||
StandardCharsets.ISO_8859_1.name(), StandardCharsets.ISO_8859_1),
|
||||
Arguments.of(testFile, StandardCharsets.UTF_8.name(), null,
|
||||
StandardCharsets.UTF_8.name(), StandardCharsets.UTF_8),
|
||||
Arguments.of(testFile, null, StandardCharsets.UTF_8,
|
||||
StandardCharsets.UTF_8.name(), StandardCharsets.UTF_8)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* DataProvider for illegal input test
|
||||
* Writes the data in ISO8859 and reads with UTF8, expects MalformedInputException
|
||||
*/
|
||||
public static Stream<Arguments> illegalInput() {
|
||||
return Stream.of
|
||||
(Arguments.of(testIllegalInput, StandardCharsets.ISO_8859_1.name(), null, StandardCharsets.UTF_8.name(), null),
|
||||
Arguments.of(testIllegalInput, StandardCharsets.ISO_8859_1.name(), null, null, StandardCharsets.UTF_8),
|
||||
Arguments.of(testIllegalInput, null, StandardCharsets.ISO_8859_1, StandardCharsets.UTF_8.name(), null),
|
||||
Arguments.of(testIllegalInput, null, StandardCharsets.ISO_8859_1, null, StandardCharsets.UTF_8)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* DataProvider for illegal output test
|
||||
* Attemps to write some malformed chars, expects MalformedInputException
|
||||
*/
|
||||
public static Stream<Arguments> illegalOutput() {
|
||||
return Stream.of
|
||||
(Arguments.of(testIllegalOutput, StandardCharsets.UTF_8.name(), null),
|
||||
Arguments.of(testIllegalOutput, null, StandardCharsets.UTF_8)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the Readers created with the following methods are
|
||||
* equivalent:
|
||||
* newReader(ReadableByteChannel ch, String csName)
|
||||
* newReader(ReadableByteChannel ch, Charset charset)
|
||||
*
|
||||
* The verification follows the following steps:
|
||||
* Writes a file with a writer created with the specified charset
|
||||
* Reads it with a reader created with newReader using the same charset;
|
||||
* Compares that the results are the same.
|
||||
*
|
||||
* @param file the file name
|
||||
* @param csnWriter the charset name for creating the writer
|
||||
* @param charsetWriter the charset for creating the writer
|
||||
* @param csnReader the charset name for creating the reader
|
||||
* @param charsetReader the charset for creating the reader
|
||||
* @throws Exception
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("writeAndRead")
|
||||
public void testWriteAndRead(String file, String csnWriter, Charset charsetWriter,
|
||||
String csnReader, Charset charsetReader) throws Exception {
|
||||
writeToFile(data, file, csnWriter, charsetWriter);
|
||||
// read using charset name
|
||||
String result1 = readFileToString(file, csnReader, null);
|
||||
String result2 = readFileToString(file, null, charsetReader);
|
||||
|
||||
assertEquals(result1, result2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that MalformedInputException is thrown when an input byte sequence
|
||||
* is illegal for given charset that is configured for the reader.
|
||||
*
|
||||
* @param file the file to be read
|
||||
* @param csnWriter the charset name for creating the writer
|
||||
* @param charsetWriter the charset for creating the writer
|
||||
* @param csnReader the charset name for creating the reader
|
||||
* @param charsetReader the charset for creating the reader
|
||||
* @throws Exception
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource( "illegalInput")
|
||||
void testMalformedInput(String file, String csnWriter, Charset charsetWriter,
|
||||
String csnReader, Charset charsetReader)
|
||||
throws Exception {
|
||||
writeToFile(data, file, csnWriter, charsetWriter);
|
||||
assertThrows(MalformedInputException.class,
|
||||
() -> readFileToString(file, csnReader, charsetReader));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to write illegal characters using a writer created by calling
|
||||
* the newWriter method and expects a MalformedInputException.
|
||||
*
|
||||
* @param fileName the file name
|
||||
* @param csn the charset name
|
||||
* @param charset the charset
|
||||
* @throws Exception
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("illegalOutput")
|
||||
public void testMalformedOutput(String fileName, String csn, Charset charset)
|
||||
throws Exception {
|
||||
try (FileOutputStream fos = new FileOutputStream(fileName);
|
||||
WritableByteChannel wbc = (WritableByteChannel) fos.getChannel();) {
|
||||
Charset cs = (csn != null) ? Charset.forName(csn) : charset;
|
||||
Writer writer = Channels.newWriter(wbc, cs);
|
||||
assertThrows(MalformedInputException.class, () -> {
|
||||
try (writer) {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
writer.write(illChars);
|
||||
}
|
||||
writer.flush();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data to a file using a writer created by calling the newWriter
|
||||
* method.
|
||||
*
|
||||
* @param data the data to be written
|
||||
* @param fileName the file name
|
||||
* @param csn the charset name
|
||||
* @param charset the charset
|
||||
* @throws Exception
|
||||
*/
|
||||
private void writeToFile(byte[] data, String fileName, String csn, Charset charset) throws Exception {
|
||||
try (FileOutputStream fos = new FileOutputStream(fileName);
|
||||
WritableByteChannel wbc = (WritableByteChannel) fos.getChannel()) {
|
||||
Writer writer;
|
||||
String temp;
|
||||
if (csn != null) {
|
||||
writer = Channels.newWriter(wbc, csn);
|
||||
temp = new String(data, csn);
|
||||
} else {
|
||||
writer = Channels.newWriter(wbc, charset);
|
||||
temp = new String(data, charset);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
writer.write(temp);
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a file into a String.
|
||||
*
|
||||
* @param file the file to be read
|
||||
* @param csn the charset name
|
||||
* @param charset the charset
|
||||
* @throws Exception
|
||||
*/
|
||||
String readFileToString(String file, String csn, Charset charset) throws Exception {
|
||||
String result;
|
||||
try (FileInputStream fis = new FileInputStream(file);
|
||||
ReadableByteChannel rbc = (ReadableByteChannel) fis.getChannel()) {
|
||||
Reader reader;
|
||||
if (csn != null) {
|
||||
reader = Channels.newReader(rbc, csn);
|
||||
} else {
|
||||
reader = Channels.newReader(rbc, charset);
|
||||
}
|
||||
|
||||
int messageSize = data.length * ITERATIONS;
|
||||
char data1[] = new char[messageSize];
|
||||
int totalRead = 0;
|
||||
int charsRead = 0;
|
||||
while (totalRead < messageSize) {
|
||||
totalRead += charsRead;
|
||||
charsRead = reader.read(data1, totalRead, messageSize - totalRead);
|
||||
}
|
||||
|
||||
result = new String(data1, 0, totalRead);
|
||||
reader.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
101
test/jdk/java/nio/channels/Channels/NewWriter.java
Normal file
101
test/jdk/java/nio/channels/Channels/NewWriter.java
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8295797
|
||||
* @summary Test behavior of Channels.newWriter for WritableByteChannels
|
||||
* @run junit NewWriter
|
||||
*/
|
||||
public class NewWriter {
|
||||
private static final String STRING = "test";
|
||||
private static final int COUNT = 5;
|
||||
private static final int EXPECTED = COUNT*STRING.length();
|
||||
private int actual = 0;
|
||||
|
||||
@Test
|
||||
public void customWritableByteChannel() throws IOException {
|
||||
try (Writer writer = Channels.newWriter(new WritableByteChannel() {
|
||||
@Override
|
||||
public int write(ByteBuffer src) {
|
||||
System.out.print((char) src.get());
|
||||
actual++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}, StandardCharsets.UTF_8)) {
|
||||
for (int i = 1; i <= COUNT; i++) {
|
||||
writer.write(STRING);
|
||||
writer.flush();
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
assertEquals(EXPECTED, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void socketChannel() throws IOException {
|
||||
Throwable thrown = assertThrows(IllegalBlockingModeException.class,
|
||||
() -> {
|
||||
try (ServerSocket ss = new ServerSocket();
|
||||
SocketChannel sc = SocketChannel.open()) {
|
||||
|
||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||
ss.bind(new InetSocketAddress(lb, 0));
|
||||
sc.connect(ss.getLocalSocketAddress());
|
||||
sc.configureBlocking(false);
|
||||
try (Writer writer = Channels.newWriter(sc,
|
||||
StandardCharsets.UTF_8)) {
|
||||
for (int i = 1; i < Integer.MAX_VALUE; i++) {
|
||||
writer.write("test" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
57
test/jdk/java/nio/channels/Channels/ReadByte.java
Normal file
57
test/jdk/java/nio/channels/Channels/ReadByte.java
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 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
|
||||
* @bug 4773447
|
||||
* @summary Test Channels.newInputStream.read() method
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.Channels;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ReadByte {
|
||||
public static void main(String[] args) throws IOException {
|
||||
ReadableByteChannel channel = new ReadableByteChannel() {
|
||||
public int read(ByteBuffer dst) {
|
||||
dst.put((byte) 129);
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
};
|
||||
|
||||
InputStream in = Channels.newInputStream(channel);
|
||||
int data = in.read();
|
||||
if (data < 0)
|
||||
throw new RuntimeException(
|
||||
"InputStream.read() spec'd to return 0-255");
|
||||
}
|
||||
}
|
||||
56
test/jdk/java/nio/channels/Channels/ReadOffset.java
Normal file
56
test/jdk/java/nio/channels/Channels/ReadOffset.java
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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
|
||||
* @bug 6545054
|
||||
* @summary Channels.newInputStream.read throws IAE when invoked with
|
||||
* different offsets.
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.Channels;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ReadOffset {
|
||||
public static void main(String[] args) throws IOException {
|
||||
ReadableByteChannel rbc = new ReadableByteChannel() {
|
||||
public int read(ByteBuffer dst) {
|
||||
dst.put((byte)0);
|
||||
return 1;
|
||||
}
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
public void close() {
|
||||
}
|
||||
};
|
||||
|
||||
InputStream in = Channels.newInputStream(rbc);
|
||||
|
||||
byte[] b = new byte[3];
|
||||
in.read(b, 0, 1);
|
||||
in.read(b, 2, 1); // throws IAE
|
||||
}
|
||||
}
|
||||
360
test/jdk/java/nio/channels/Channels/ReadXBytes.java
Normal file
360
test/jdk/java/nio/channels/Channels/ReadXBytes.java
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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
|
||||
* @bug 8268435 8274780
|
||||
* @summary Verify ChannelInputStream methods readAllBytes and readNBytes
|
||||
* @requires (sun.arch.data.model == "64" & os.maxMemory >= 16g)
|
||||
* @library ..
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @run junit/othervm/timeout=900 -Xmx12g ReadXBytes
|
||||
* @key randomness
|
||||
*/
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.IntStream;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import jdk.test.lib.RandomFactory;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ReadXBytes {
|
||||
|
||||
private static final Random RAND = RandomFactory.getRandom();
|
||||
|
||||
// The largest source from which to read all bytes
|
||||
private static final int BIG_LENGTH = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
|
||||
|
||||
// A length greater than a 32-bit integer can accommodate
|
||||
private static final long HUGE_LENGTH = Integer.MAX_VALUE + 27L;
|
||||
|
||||
// Current directory
|
||||
private static final Path DIR = Path.of(System.getProperty("test.dir", "."));
|
||||
|
||||
// --- Framework ---
|
||||
|
||||
// Create a temporary file path
|
||||
static Path createFilePath() {
|
||||
String name = String.format("ReadXBytes%d.tmp", System.nanoTime());
|
||||
return DIR.resolve(name);
|
||||
}
|
||||
|
||||
// Creates a temporary file of a specified length with undefined content
|
||||
static Path createFile(long length) throws IOException {
|
||||
Path path = createFilePath();
|
||||
path.toFile().deleteOnExit();
|
||||
try (FileChannel fc = FileChannel.open(path, CREATE_NEW, SPARSE, WRITE)) {
|
||||
if (length > 0) {
|
||||
fc.position(length - 1);
|
||||
fc.write(ByteBuffer.wrap(new byte[] {27}));
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// Creates a temporary file of a specified length with random content
|
||||
static Path createFileWithRandomContent(long length) throws IOException {
|
||||
Path file = createFile(length);
|
||||
try (FileChannel fc = FileChannel.open(file, WRITE)) {
|
||||
if (length < 65536) {
|
||||
// if the length is less than 64k, write the entire file
|
||||
byte[] buf = new byte[(int)length];
|
||||
RAND.nextBytes(buf);
|
||||
ByteBuffer bb = ByteBuffer.wrap(buf);
|
||||
while (bb.hasRemaining()) {
|
||||
fc.write(bb);
|
||||
}
|
||||
} else {
|
||||
// write the first and the last 32k only
|
||||
byte[] buf = new byte[32768];
|
||||
RAND.nextBytes(buf);
|
||||
ByteBuffer bb = ByteBuffer.wrap(buf);
|
||||
while (bb.hasRemaining()) {
|
||||
fc.write(bb);
|
||||
}
|
||||
bb.clear();
|
||||
fc.position(length - buf.length);
|
||||
RAND.nextBytes(buf);
|
||||
while (bb.hasRemaining()) {
|
||||
fc.write(bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
// Creates a file of a specified length
|
||||
@FunctionalInterface
|
||||
interface FileCreator {
|
||||
Path create(long length) throws IOException;
|
||||
}
|
||||
|
||||
// Performs a test for checking edge cases
|
||||
@FunctionalInterface
|
||||
interface EdgeTest {
|
||||
void test(long length, InputStream source) throws IOException;
|
||||
}
|
||||
|
||||
// Performs a test for evaluating correctness of content
|
||||
@FunctionalInterface
|
||||
interface DataTest {
|
||||
void test(long length, InputStream source, InputStream reference)
|
||||
throws IOException;
|
||||
}
|
||||
|
||||
// Construct for testing zero length, EOF, and IAE
|
||||
public void edgeTest(long length, FileCreator c, EdgeTest f)
|
||||
throws IOException {
|
||||
Path file = c.create(length);
|
||||
try (FileChannel fc = FileChannel.open(file, READ);
|
||||
InputStream cis = Channels.newInputStream(fc)) {
|
||||
f.test(length, cis);
|
||||
} finally {
|
||||
Files.delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct for testing correctness of content
|
||||
public void dataTest(long length, FileCreator c, DataTest f)
|
||||
throws IOException {
|
||||
Path file = c.create(length);
|
||||
try {
|
||||
for (boolean seekable : List.of(false, true)) {
|
||||
try (FileInputStream fis = new FileInputStream(file.toFile())) {
|
||||
ReadableByteChannel ch;
|
||||
if (seekable) {
|
||||
ch = FileChannel.open(file, READ);
|
||||
} else {
|
||||
InputStream fis2 = new FileInputStream(file.toFile());
|
||||
ch = Channels.newChannel(new FilterInputStream(fis2) {});
|
||||
assertFalse(ch instanceof SeekableByteChannel);
|
||||
}
|
||||
try (InputStream cis = Channels.newInputStream(ch)) {
|
||||
f.test(length, cis, fis);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Files.delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
// --- readAllBytes tests ---
|
||||
|
||||
// Verifies readAllBytes() behavior for an empty file
|
||||
@Test
|
||||
public void readAllBytesFromEmptyFile() throws IOException {
|
||||
edgeTest(0L, (length) -> createFile(length),
|
||||
(length, cis) -> {
|
||||
byte[] bytes = cis.readAllBytes();
|
||||
assertNotNull(bytes);
|
||||
assertEquals(0, bytes.length);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readAllBytes() behavior at EOF
|
||||
@Test
|
||||
public void readAllBytesAtEOF() throws IOException {
|
||||
edgeTest(RAND.nextInt(Short.MAX_VALUE), (length) -> createFile(length),
|
||||
(length, cis) -> {
|
||||
cis.skipNBytes(length);
|
||||
byte[] bytes = cis.readAllBytes();
|
||||
assertNotNull(bytes);
|
||||
assertEquals(0, bytes.length);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readAllBytes() behavior for a maximal length source
|
||||
@Test
|
||||
public void readAllBytesFromMaxLengthFile() throws IOException {
|
||||
dataTest(BIG_LENGTH, (length) -> createFileWithRandomContent(length),
|
||||
(length, cis, fis) -> {
|
||||
byte[] cisBytes = cis.readAllBytes();
|
||||
assertNotNull(cisBytes);
|
||||
assertEquals(length, cisBytes.length);
|
||||
byte[] fisBytes = fis.readAllBytes();
|
||||
assertArrayEquals(fisBytes, cisBytes);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readAllBytes() throws OOME if the source is too large
|
||||
@Test
|
||||
public void readAllBytesFromBeyondMaxLengthFile() throws IOException {
|
||||
dataTest(HUGE_LENGTH, (length) -> createFile(length),
|
||||
(length, cis, fis) -> {
|
||||
assertThrows(OutOfMemoryError.class,
|
||||
() -> {cis.readAllBytes();});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Provides a stream of lengths
|
||||
public static IntStream fileLengths() throws IOException {
|
||||
return IntStream.of
|
||||
(1 + RAND.nextInt(1),
|
||||
1 + RAND.nextInt(Byte.MAX_VALUE),
|
||||
1 + RAND.nextInt(Short.MAX_VALUE),
|
||||
1 + RAND.nextInt(1_000_000),
|
||||
1 + RAND.nextInt(BIG_LENGTH));
|
||||
}
|
||||
|
||||
// Verifies readAllBytes() accuracy for random lengths and initial positions
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileLengths")
|
||||
public void readAllBytes(int len) throws IOException {
|
||||
dataTest(len, (length) -> createFileWithRandomContent(length),
|
||||
(length, cis, fis) -> {
|
||||
long position = RAND.nextInt(Math.toIntExact(length));
|
||||
cis.skipNBytes(position);
|
||||
byte[] cisBytes = cis.readAllBytes();
|
||||
assertNotNull(cisBytes);
|
||||
assertEquals(length - position, cisBytes.length);
|
||||
fis.skipNBytes(position);
|
||||
byte[] fisBytes = fis.readAllBytes();
|
||||
assertArrayEquals(fisBytes, cisBytes);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// --- readNBytes tests ---
|
||||
|
||||
// Verifies readNBytes() behavior for a negative length
|
||||
@Test
|
||||
public void readNBytesWithNegativeLength() throws IOException {
|
||||
edgeTest(0L, (length) -> createFile(length),
|
||||
(length, cis) -> {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> {cis.readNBytes(-1);});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readNBytes() for an empty file
|
||||
@Test
|
||||
public void readNBytesFromEmptyFile() throws IOException {
|
||||
edgeTest(0L, (length) -> createFile(length),
|
||||
(length, cis) -> {
|
||||
byte[] bytes = cis.readNBytes(1);
|
||||
assertNotNull(bytes);
|
||||
assertEquals(0, bytes.length);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readNBytes() behavior at EOF
|
||||
@Test
|
||||
public void readNBytesAtEOF() throws IOException {
|
||||
edgeTest(RAND.nextInt(Short.MAX_VALUE), (length) -> createFile(length),
|
||||
(length, cis) -> {
|
||||
cis.skipNBytes(length);
|
||||
byte[] bytes = cis.readNBytes(1);
|
||||
assertNotNull(bytes);
|
||||
assertEquals(0, bytes.length);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readNBytes() behavior for a maximal length source
|
||||
@Test
|
||||
public void readNBytesFromMaxLengthFile() throws IOException {
|
||||
dataTest(BIG_LENGTH, (length) -> createFileWithRandomContent(length),
|
||||
(length, cis, fis) -> {
|
||||
byte[] cisBytes = cis.readNBytes(BIG_LENGTH);
|
||||
assertNotNull(cisBytes);
|
||||
assertEquals(length, cisBytes.length);
|
||||
byte[] fisBytes = fis.readNBytes(BIG_LENGTH);
|
||||
assertArrayEquals(fisBytes, cisBytes);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readNBytes() beyond the maximum length source
|
||||
@Test
|
||||
public void readNBytesFromBeyondMaxLengthFile() throws IOException {
|
||||
dataTest(HUGE_LENGTH, (length) -> createFileWithRandomContent(length),
|
||||
(length, cis, fis) -> {
|
||||
assertTrue(BIG_LENGTH < length, length + " >= " + HUGE_LENGTH);
|
||||
int n = Math.toIntExact(length - BIG_LENGTH);
|
||||
cis.skipNBytes(BIG_LENGTH);
|
||||
byte[] cisBytes = cis.readNBytes(n);
|
||||
assertNotNull(cisBytes);
|
||||
assertEquals(n, cisBytes.length);
|
||||
fis.skipNBytes(BIG_LENGTH);
|
||||
byte[] fisBytes = fis.readNBytes(n);
|
||||
assertArrayEquals(fisBytes, cisBytes);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Verifies readNBytes() accuracy for random lengths and initial positions
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileLengths")
|
||||
public void readNBytes(int len) throws IOException {
|
||||
dataTest(len, (length) -> createFileWithRandomContent(length),
|
||||
(length, cis, fis) -> {
|
||||
int ilen = Math.toIntExact(len);
|
||||
int position = RAND.nextInt(ilen);
|
||||
int n = RAND.nextInt(ilen - position);
|
||||
cis.skipNBytes(position);
|
||||
byte[] cisBytes = cis.readNBytes(n);
|
||||
assertNotNull(cisBytes);
|
||||
assertEquals(n, cisBytes.length);
|
||||
fis.skipNBytes(position);
|
||||
byte[] fisBytes = fis.readNBytes(n);
|
||||
assertArrayEquals(fisBytes, cisBytes);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
84
test/jdk/java/nio/channels/Channels/ShortWrite.java
Normal file
84
test/jdk/java/nio/channels/Channels/ShortWrite.java
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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
|
||||
* @bug 6448457
|
||||
* @summary Test Channels.newOutputStream returns OutputStream that handles
|
||||
* short writes from the underlying channel
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Random;
|
||||
|
||||
public class ShortWrite {
|
||||
|
||||
static Random rand = new Random();
|
||||
static int bytesWritten = 0;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
WritableByteChannel wbc = new WritableByteChannel() {
|
||||
public int write(ByteBuffer src) {
|
||||
int rem = src.remaining();
|
||||
if (rem > 0) {
|
||||
// short write
|
||||
int n = rand.nextInt(rem) + 1;
|
||||
src.position(src.position() + n);
|
||||
bytesWritten += n;
|
||||
return n;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public void close() throws IOException {
|
||||
throw new RuntimeException("not implemented");
|
||||
}
|
||||
public boolean isOpen() {
|
||||
throw new RuntimeException("not implemented");
|
||||
}
|
||||
};
|
||||
|
||||
// wrap Channel with OutputStream
|
||||
OutputStream out = Channels.newOutputStream(wbc);
|
||||
|
||||
|
||||
// write 100, 99, 98, ... 1
|
||||
// and check that the expected number of bytes is written
|
||||
int expected = 0;
|
||||
byte[] buf = new byte[100];
|
||||
for (int i=0; i<buf.length; i++) {
|
||||
int len = buf.length-i;
|
||||
out.write(buf, i, len);
|
||||
expected += len;
|
||||
}
|
||||
System.out.format("Bytes written: %d, expected: %d\n", bytesWritten,
|
||||
expected);
|
||||
if (bytesWritten != expected)
|
||||
throw new RuntimeException("incorrect number of bytes written");
|
||||
|
||||
}
|
||||
}
|
||||
566
test/jdk/java/nio/channels/Channels/SocketChannelStreams.java
Normal file
566
test/jdk/java/nio/channels/Channels/SocketChannelStreams.java
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2026, 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
|
||||
* @bug 8279339 8371718
|
||||
* @summary Exercise InputStream/OutputStream returned by Channels.newXXXStream
|
||||
* when channel is a SocketChannel
|
||||
* @run junit SocketChannelStreams
|
||||
*/
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ByteChannel;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class SocketChannelStreams {
|
||||
// Maximum size of internal temporary buffer
|
||||
private static final int MAX_BUFFER_SIZE = 128*1024;
|
||||
|
||||
private static ScheduledExecutorService executor;
|
||||
|
||||
@BeforeAll()
|
||||
public static void init() {
|
||||
executor = Executors.newSingleThreadScheduledExecutor();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void finish() {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read when bytes are available.
|
||||
*/
|
||||
@Test
|
||||
public void testRead1() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
write(peer, 99);
|
||||
int n = Channels.newInputStream(sc).read();
|
||||
assertEquals(99, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read blocking before bytes are available.
|
||||
*/
|
||||
@Test
|
||||
public void testRead2() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
scheduleWrite(peer, 99, 1000);
|
||||
int n = Channels.newInputStream(sc).read();
|
||||
assertEquals(99, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read after peer has closed connection.
|
||||
*/
|
||||
@Test
|
||||
public void testRead3() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
peer.close();
|
||||
int n = Channels.newInputStream(sc).read();
|
||||
assertEquals(-1, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read blocking before peer closes connection.
|
||||
*/
|
||||
@Test
|
||||
public void testRead4() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
scheduleClose(peer, 1000);
|
||||
int n = Channels.newInputStream(sc).read();
|
||||
assertEquals(-1, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test async close of channel when thread blocked in read.
|
||||
*/
|
||||
@Test
|
||||
public void testRead5() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
scheduleClose(sc, 2000);
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
assertThrows(IOException.class, () -> in.read());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test async close of input stream, when thread blocked in read.
|
||||
*/
|
||||
@Test
|
||||
public void testRead6() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
scheduleClose(in, 2000);
|
||||
assertThrows(IOException.class, () -> in.read());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test interrupted status set before read.
|
||||
*/
|
||||
@Test
|
||||
public void testRead7() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
Thread.currentThread().interrupt();
|
||||
try {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
assertThrows(IOException.class, () -> in.read());
|
||||
} finally {
|
||||
Thread.interrupted(); // clear interrupt
|
||||
}
|
||||
assertFalse(sc.isOpen());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test interrupt of thread blocked in read.
|
||||
*/
|
||||
@Test
|
||||
public void testRead8() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
Future<?> interrupter = scheduleInterrupt(Thread.currentThread(), 2000);
|
||||
try {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
assertThrows(IOException.class, () -> in.read());
|
||||
} finally {
|
||||
interrupter.cancel(true);
|
||||
Thread.interrupted(); // clear interrupt
|
||||
}
|
||||
assertFalse(sc.isOpen());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that read is untimed when SO_TIMEOUT is set on the Socket adaptor.
|
||||
*/
|
||||
@Test
|
||||
public void testRead9() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
sc.socket().setSoTimeout(100);
|
||||
scheduleWrite(peer, 99, 2000);
|
||||
// read should block until bytes are available
|
||||
int b = Channels.newInputStream(sc).read();
|
||||
assertEquals(99, b);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test write.
|
||||
*/
|
||||
@Test
|
||||
public void testWrite1() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
out.write(99);
|
||||
int n = read(peer);
|
||||
assertEquals(99, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test async close of channel when thread blocked in write.
|
||||
*/
|
||||
@Test
|
||||
public void testWrite2() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
scheduleClose(sc, 2000);
|
||||
assertThrows(IOException.class, () -> {
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
byte[] data = new byte[64*1000];
|
||||
while (true) {
|
||||
out.write(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test async close of output stream when thread blocked in write.
|
||||
*/
|
||||
@Test
|
||||
public void testWrite3() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
scheduleClose(out, 2000);
|
||||
assertThrows(IOException.class, () -> {
|
||||
byte[] data = new byte[64*1000];
|
||||
while (true) {
|
||||
out.write(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test interrupted status set before write.
|
||||
*/
|
||||
@Test
|
||||
public void testWrite4() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
Thread.currentThread().interrupt();
|
||||
try {
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
assertThrows(IOException.class, () -> out.write(99));
|
||||
} finally {
|
||||
Thread.interrupted(); // clear interrupt
|
||||
}
|
||||
assertFalse(sc.isOpen());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test interrupt of thread blocked in write.
|
||||
*/
|
||||
@Test
|
||||
public void testWrite5() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
Future<?> interrupter = scheduleInterrupt(Thread.currentThread(), 2000);
|
||||
try {
|
||||
assertThrows(IOException.class, () -> {
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
byte[] data = new byte[64*1000];
|
||||
while (true) {
|
||||
out.write(data);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
interrupter.cancel(true);
|
||||
Thread.interrupted(); // clear interrupt
|
||||
}
|
||||
assertFalse(sc.isOpen());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read when another thread is blocked in write. The read should
|
||||
* complete immediately.
|
||||
*/
|
||||
@Test
|
||||
public void testConcurrentReadWrite1() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
|
||||
// block thread in write
|
||||
fork(() -> {
|
||||
var data = new byte[64*1024];
|
||||
for (;;) {
|
||||
out.write(data);
|
||||
}
|
||||
});
|
||||
Thread.sleep(1000); // give writer time to block
|
||||
|
||||
// test read, should not be blocked by writer thread
|
||||
write(peer, 99);
|
||||
int n = in.read();
|
||||
assertEquals(99, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read when another thread is blocked in write. The read should
|
||||
* block until bytes are available.
|
||||
*/
|
||||
@Test
|
||||
public void testConcurrentReadWrite2() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
|
||||
// block thread in write
|
||||
fork(() -> {
|
||||
var data = new byte[64*1024];
|
||||
for (;;) {
|
||||
out.write(data);
|
||||
}
|
||||
});
|
||||
Thread.sleep(1000); // give writer time to block
|
||||
|
||||
// test read, should not be blocked by writer thread
|
||||
scheduleWrite(peer, 99, 500);
|
||||
int n = in.read();
|
||||
assertEquals(99, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writing when another thread is blocked in read.
|
||||
*/
|
||||
@Test
|
||||
public void testConcurrentReadWrite3() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
|
||||
// block thread in read
|
||||
fork(() -> {
|
||||
in.read();
|
||||
});
|
||||
Thread.sleep(100); // give reader time to block
|
||||
|
||||
// test write, should not be blocked by reader thread
|
||||
out.write(99);
|
||||
int n = read(peer);
|
||||
assertEquals(99, n);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test read/write when channel configured non-blocking.
|
||||
*/
|
||||
@Test
|
||||
public void testIllegalBlockingMode() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
|
||||
sc.configureBlocking(false);
|
||||
assertThrows(IllegalBlockingModeException.class, () -> in.read());
|
||||
assertThrows(IllegalBlockingModeException.class, () -> out.write(99));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test NullPointerException.
|
||||
*/
|
||||
@Test
|
||||
public void testNullPointerException() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
|
||||
assertThrows(NullPointerException.class, () -> in.read(null));
|
||||
assertThrows(NullPointerException.class, () -> in.read(null, 0, 0));
|
||||
|
||||
assertThrows(NullPointerException.class, () -> out.write(null));
|
||||
assertThrows(NullPointerException.class, () -> out.write(null, 0, 0));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test IndexOutOfBoundsException.
|
||||
*/
|
||||
@Test
|
||||
public void testIndexOutOfBoundsException() throws Exception {
|
||||
withConnection((sc, peer) -> {
|
||||
InputStream in = Channels.newInputStream(sc);
|
||||
OutputStream out = Channels.newOutputStream(sc);
|
||||
byte[] ba = new byte[100];
|
||||
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> in.read(ba, -1, 1));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> in.read(ba, 0, -1));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> in.read(ba, 0, 1000));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> in.read(ba, 1, 100));
|
||||
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> out.write(ba, -1, 1));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> out.write(ba, 0, -1));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> out.write(ba, 0, 1000));
|
||||
assertThrows(IndexOutOfBoundsException.class, () -> out.write(ba, 1, 100));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that internal buffers have at most MAX_BUFFER_SIZE bytes remaining.
|
||||
*/
|
||||
@Test
|
||||
public void testReadLimit() throws IOException {
|
||||
InputStream in = Channels.newInputStream(new TestChannel());
|
||||
byte[] b = new byte[3*MAX_BUFFER_SIZE];
|
||||
int n = in.read(b, 0, b.length);
|
||||
assertEquals(MAX_BUFFER_SIZE, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that internal buffers have at most MAX_BUFFER_SIZE bytes remaining.
|
||||
*/
|
||||
@Test
|
||||
public void testWriteLimit() throws IOException {
|
||||
OutputStream out = Channels.newOutputStream(new TestChannel());
|
||||
byte[] b = new byte[3*MAX_BUFFER_SIZE];
|
||||
out.write(b, 0, b.length);
|
||||
}
|
||||
|
||||
// -- test infrastructure --
|
||||
|
||||
private interface ThrowingTask {
|
||||
void run() throws Exception;
|
||||
}
|
||||
|
||||
private interface ThrowingBiConsumer<T, U> {
|
||||
void accept(T t, U u) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the consumer with a connected pair of socket channels.
|
||||
*/
|
||||
private static void withConnection(ThrowingBiConsumer<SocketChannel, SocketChannel> consumer)
|
||||
throws Exception
|
||||
{
|
||||
var loopback = InetAddress.getLoopbackAddress();
|
||||
try (ServerSocketChannel listener = ServerSocketChannel.open()) {
|
||||
listener.bind(new InetSocketAddress(loopback, 0));
|
||||
try (SocketChannel sc = SocketChannel.open(listener.getLocalAddress())) {
|
||||
try (SocketChannel peer = listener.accept()) {
|
||||
consumer.accept(sc, peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forks a thread to execute the given task.
|
||||
*/
|
||||
private Future<?> fork(ThrowingTask task) {
|
||||
ExecutorService pool = Executors.newFixedThreadPool(1);
|
||||
try {
|
||||
return pool.submit(() -> {
|
||||
task.run();
|
||||
return null;
|
||||
});
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte from the given socket channel.
|
||||
*/
|
||||
private int read(SocketChannel sc) throws IOException {
|
||||
return sc.socket().getInputStream().read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a byte to the given socket channel.
|
||||
*/
|
||||
private void write(SocketChannel sc, int b) throws IOException {
|
||||
sc.socket().getOutputStream().write(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given data to the socket channel after a delay.
|
||||
*/
|
||||
private Future<?> scheduleWrite(SocketChannel sc, byte[] data, long delay) {
|
||||
return schedule(() -> {
|
||||
try {
|
||||
sc.socket().getOutputStream().write(data);
|
||||
} catch (IOException ioe) { }
|
||||
}, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the socket channel after a delay.
|
||||
*/
|
||||
private Future<?> scheduleWrite(SocketChannel sc, int b, long delay) {
|
||||
return scheduleWrite(sc, new byte[] { (byte)b }, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the given object after a delay.
|
||||
*/
|
||||
private Future<?> scheduleClose(Closeable c, long delay) {
|
||||
return schedule(() -> {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException ioe) { }
|
||||
}, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupts the given Thread after a delay.
|
||||
*/
|
||||
private Future<?> scheduleInterrupt(Thread t, long delay) {
|
||||
return schedule(() -> t.interrupt(), delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the given task to run after a delay.
|
||||
*/
|
||||
private Future<?> schedule(Runnable task, long delay) {
|
||||
return executor.schedule(task, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* ByteChannel that throws if more than 128k bytes remain
|
||||
* in the buffer supplied for reading or writing.
|
||||
*/
|
||||
private static class TestChannel implements ByteChannel {
|
||||
@Override
|
||||
public int read(ByteBuffer bb) throws IOException {
|
||||
int rem = bb.remaining();
|
||||
if (rem > MAX_BUFFER_SIZE) {
|
||||
throw new IOException("too big");
|
||||
}
|
||||
bb.position(bb.limit());
|
||||
return rem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer bb) throws IOException {
|
||||
int rem = bb.remaining();
|
||||
if (rem > MAX_BUFFER_SIZE) {
|
||||
throw new IOException("too big");
|
||||
}
|
||||
bb.position(bb.limit());
|
||||
return rem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
53
test/jdk/java/nio/channels/Channels/TinyBuffers.java
Normal file
53
test/jdk/java/nio/channels/Channels/TinyBuffers.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 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
|
||||
* @bug 4654722
|
||||
* @summary Ensure that ridiculously tiny buffers work with
|
||||
* Channels.newReader
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.charset.*;
|
||||
|
||||
|
||||
public class TinyBuffers {
|
||||
|
||||
private static Charset cs = Charset.forName("UTF-16");
|
||||
|
||||
private static void test(int sz) throws Exception {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(new byte[100]);
|
||||
ReadableByteChannel ch = Channels.newChannel(bis);
|
||||
Reader r = Channels.newReader(ch, cs.newDecoder(), sz);
|
||||
char [] arr = new char[100];
|
||||
System.out.println(r.read(arr, 0, arr.length));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (int i = -2; i < 10; i++)
|
||||
test(i);
|
||||
}
|
||||
|
||||
}
|
||||
207
test/jdk/java/nio/channels/Channels/TransferTo.java
Normal file
207
test/jdk/java/nio/channels/Channels/TransferTo.java
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run junit/othervm/timeout=720 TransferTo
|
||||
* @bug 8265891
|
||||
* @summary Tests whether sun.nio.ChannelInputStream.transferTo conforms to the
|
||||
* InputStream.transferTo specification
|
||||
* @key randomness
|
||||
*/
|
||||
public class TransferTo extends TransferToBase {
|
||||
|
||||
/*
|
||||
* Provides test scenarios, i.e., combinations of input and output streams
|
||||
* to be tested.
|
||||
*/
|
||||
public static Stream<Arguments> streamCombinations() {
|
||||
return Stream.of
|
||||
(// tests FileChannel.transferTo(FileChannel) optimized case
|
||||
Arguments.of(fileChannelInput(), fileChannelOutput()),
|
||||
|
||||
// tests FileChannel.transferTo(SelectableChannelOutput)
|
||||
// optimized case
|
||||
Arguments.of(fileChannelInput(), selectableChannelOutput()),
|
||||
|
||||
// tests FileChannel.transferTo(WritableByteChannelOutput)
|
||||
// optimized case
|
||||
Arguments.of(fileChannelInput(), writableByteChannelOutput()),
|
||||
|
||||
// tests InputStream.transferTo(OutputStream) default case
|
||||
Arguments.of(readableByteChannelInput(), defaultOutput()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Input streams to be tested.
|
||||
*/
|
||||
public static Stream<Arguments> inputStreamProviders() {
|
||||
return Stream.of(Arguments.of(fileChannelInput()),
|
||||
Arguments.of(readableByteChannelInput()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing API compliance: input stream must throw NullPointerException
|
||||
* when parameter "out" is null.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("inputStreamProviders")
|
||||
public void testNullPointerException(InputStreamProvider inputStreamProvider) {
|
||||
assertNullPointerException(inputStreamProvider);
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing API compliance: complete content of input stream must be
|
||||
* transferred to output stream.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("streamCombinations")
|
||||
public void testStreamContents(InputStreamProvider inputStreamProvider,
|
||||
OutputStreamProvider outputStreamProvider) throws Exception {
|
||||
assertStreamContents(inputStreamProvider, outputStreamProvider);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special test whether selectable channel based transfer throws blocking mode exception.
|
||||
*/
|
||||
@Test
|
||||
public void testIllegalBlockingMode() throws IOException {
|
||||
Pipe pipe = Pipe.open();
|
||||
try {
|
||||
// testing arbitrary input (here: empty file) to non-blocking
|
||||
// selectable output
|
||||
try (FileChannel fc = FileChannel.open(Files.createTempFile(CWD, "testIllegalBlockingMode", null));
|
||||
InputStream is = Channels.newInputStream(fc);
|
||||
SelectableChannel sc = pipe.sink().configureBlocking(false);
|
||||
OutputStream os = Channels.newOutputStream((WritableByteChannel) sc)) {
|
||||
|
||||
// IllegalBlockingMode must be thrown when trying to perform
|
||||
// a transfer
|
||||
assertThrows(IllegalBlockingModeException.class, () -> is.transferTo(os));
|
||||
}
|
||||
|
||||
// testing non-blocking selectable input to arbitrary output
|
||||
// (here: byte array)
|
||||
try (SelectableChannel sc = pipe.source().configureBlocking(false);
|
||||
InputStream is = Channels.newInputStream((ReadableByteChannel) sc);
|
||||
OutputStream os = new ByteArrayOutputStream()) {
|
||||
|
||||
// IllegalBlockingMode must be thrown when trying to perform
|
||||
// a transfer
|
||||
assertThrows(IllegalBlockingModeException.class, () -> is.transferTo(os));
|
||||
}
|
||||
} finally {
|
||||
pipe.source().close();
|
||||
pipe.sink().close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a provider for an output stream which does not wrap a channel
|
||||
*/
|
||||
private static OutputStreamProvider defaultOutput() {
|
||||
return spy -> {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
spy.accept(outputStream::toByteArray);
|
||||
return outputStream;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a provider for an input stream which wraps a file channel
|
||||
*/
|
||||
private static InputStreamProvider fileChannelInput() {
|
||||
return bytes -> {
|
||||
Path path = Files.createTempFile(CWD, "fileChannelInput", null);
|
||||
Files.write(path, bytes);
|
||||
FileChannel fileChannel = FileChannel.open(path);
|
||||
return Channels.newInputStream(fileChannel);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a provider for an output stream which wraps a selectable channel
|
||||
*/
|
||||
private static OutputStreamProvider selectableChannelOutput() {
|
||||
return spy -> {
|
||||
Pipe pipe = Pipe.open();
|
||||
Future<byte[]> bytes = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
InputStream is = Channels.newInputStream(pipe.source());
|
||||
return is.readAllBytes();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError("Exception while asserting content", e);
|
||||
}
|
||||
});
|
||||
final OutputStream os = Channels.newOutputStream(pipe.sink());
|
||||
spy.accept(() -> {
|
||||
try {
|
||||
os.close();
|
||||
return bytes.get();
|
||||
} catch (IOException | InterruptedException | ExecutionException e) {
|
||||
throw new AssertionError("Exception while asserting content", e);
|
||||
}
|
||||
});
|
||||
return os;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a provider for an output stream which wraps a writable byte channel but is not a file channel
|
||||
*/
|
||||
private static OutputStreamProvider writableByteChannelOutput() {
|
||||
return spy -> {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
spy.accept(outputStream::toByteArray);
|
||||
return Channels.newOutputStream(Channels.newChannel(outputStream));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
106
test/jdk/java/nio/channels/Channels/TransferTo2.java
Normal file
106
test/jdk/java/nio/channels/Channels/TransferTo2.java
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run junit/othervm/timeout=180 TransferTo2
|
||||
* @bug 8278268
|
||||
* @summary Tests FileChannel.transferFrom() optimized case
|
||||
* @key randomness
|
||||
*/
|
||||
public class TransferTo2 extends TransferToBase {
|
||||
|
||||
/*
|
||||
* Provides test scenarios, i.e., combinations of input and output streams
|
||||
* to be tested.
|
||||
*/
|
||||
public static Stream<Arguments> streamCombinations() {
|
||||
return Stream.of
|
||||
(// tests FileChannel.transferFrom(SelectableChannelOutput) optimized case
|
||||
Arguments.of(selectableChannelInput(), fileChannelOutput()),
|
||||
|
||||
// tests FileChannel.transferFrom(ReadableByteChannelInput) optimized case
|
||||
Arguments.of(readableByteChannelInput(), fileChannelOutput()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Input streams to be tested.
|
||||
*/
|
||||
public static Stream<Arguments> inputStreamProviders() {
|
||||
return Stream.of(Arguments.of(selectableChannelInput()),
|
||||
Arguments.of(readableByteChannelInput()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing API compliance: input stream must throw NullPointerException
|
||||
* when parameter "out" is null.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("inputStreamProviders")
|
||||
public void testNullPointerException(InputStreamProvider inputStreamProvider) {
|
||||
assertNullPointerException(inputStreamProvider);
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing API compliance: complete content of input stream must be
|
||||
* transferred to output stream.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("streamCombinations")
|
||||
public void testStreamContents(InputStreamProvider inputStreamProvider,
|
||||
OutputStreamProvider outputStreamProvider) throws Exception {
|
||||
assertStreamContents(inputStreamProvider, outputStreamProvider);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a provider for an input stream which wraps a selectable channel
|
||||
*/
|
||||
private static InputStreamProvider selectableChannelInput() {
|
||||
return bytes -> {
|
||||
Pipe pipe = Pipe.open();
|
||||
new Thread(() -> {
|
||||
try (OutputStream os = Channels.newOutputStream(pipe.sink())) {
|
||||
os.write(bytes);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).start();
|
||||
return Channels.newInputStream(pipe.source());
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
255
test/jdk/java/nio/channels/Channels/TransferToBase.java
Normal file
255
test/jdk/java/nio/channels/Channels/TransferToBase.java
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.ToLongBiFunction;
|
||||
|
||||
import jdk.test.lib.RandomFactory;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class TransferToBase {
|
||||
static final int MIN_SIZE = 10_000;
|
||||
static final int MAX_SIZE_INCR = 100_000_000 - MIN_SIZE;
|
||||
|
||||
static final int ITERATIONS = 10;
|
||||
|
||||
static final int NUM_WRITES = 3*1024;
|
||||
static final int BYTES_PER_WRITE = 1024*1024;
|
||||
static final long BYTES_WRITTEN = (long) NUM_WRITES*BYTES_PER_WRITE;
|
||||
|
||||
static final Random RND = RandomFactory.getRandom();
|
||||
|
||||
static final Path CWD = Path.of(".");
|
||||
|
||||
/*
|
||||
* Asserts that the transferred content is correct, i.e., compares the bytes
|
||||
* actually transferred to those expected. The position of the input and
|
||||
* output streams before the transfer are zero (BOF).
|
||||
*/
|
||||
static void checkTransferredContents(InputStreamProvider inputStreamProvider,
|
||||
OutputStreamProvider outputStreamProvider, byte[] inBytes) throws Exception {
|
||||
checkTransferredContents(inputStreamProvider, outputStreamProvider, inBytes, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Asserts that the transferred content is correct, i.e. compares the bytes
|
||||
* actually transferred to those expected. The positions of the input and
|
||||
* output streams before the transfer are provided by the caller.
|
||||
*/
|
||||
static void checkTransferredContents(InputStreamProvider inputStreamProvider,
|
||||
OutputStreamProvider outputStreamProvider, byte[] inBytes, int posIn, int posOut) throws Exception {
|
||||
AtomicReference<Supplier<byte[]>> recorder = new AtomicReference<>();
|
||||
try (InputStream in = inputStreamProvider.input(inBytes);
|
||||
OutputStream out = outputStreamProvider.output(recorder::set)) {
|
||||
// skip bytes until starting position
|
||||
in.skipNBytes(posIn);
|
||||
out.write(new byte[posOut]);
|
||||
|
||||
long reported = in.transferTo(out);
|
||||
int count = inBytes.length - posIn;
|
||||
|
||||
assertEquals(count, reported);
|
||||
|
||||
byte[] outBytes = recorder.get().get();
|
||||
assertTrue(Arrays.equals(inBytes, posIn, posIn + count, outBytes, posOut, posOut + count),
|
||||
format("inBytes.length=%d, outBytes.length=%d", count, outBytes.length));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates an array of random size (between min and min + maxRandomAdditive)
|
||||
* filled with random bytes
|
||||
*/
|
||||
static byte[] createRandomBytes(int min, int maxRandomAdditive) {
|
||||
byte[] bytes = new byte[min + (maxRandomAdditive == 0 ? 0 : RND.nextInt(maxRandomAdditive))];
|
||||
RND.nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
interface InputStreamProvider {
|
||||
InputStream input(byte... bytes) throws Exception;
|
||||
}
|
||||
|
||||
interface OutputStreamProvider {
|
||||
OutputStream output(Consumer<Supplier<byte[]>> spy) throws Exception;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a provider for an input stream which wraps a readable byte
|
||||
* channel but is not a file channel
|
||||
*/
|
||||
static InputStreamProvider readableByteChannelInput() {
|
||||
return bytes -> Channels.newInputStream(Channels.newChannel(new ByteArrayInputStream(bytes)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a provider for an output stream which wraps a file channel
|
||||
*/
|
||||
static OutputStreamProvider fileChannelOutput() {
|
||||
return spy -> {
|
||||
Path path = Files.createTempFile(CWD, "fileChannelOutput", null);
|
||||
FileChannel fileChannel = FileChannel.open(path, WRITE);
|
||||
spy.accept(() -> {
|
||||
try {
|
||||
return Files.readAllBytes(path);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError("Failed to verify output file", e);
|
||||
}
|
||||
});
|
||||
return Channels.newOutputStream(fileChannel);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing API compliance: input stream must throw NullPointerException
|
||||
* when parameter "out" is null.
|
||||
*/
|
||||
static void assertNullPointerException(InputStreamProvider inputStreamProvider) {
|
||||
// tests empty input stream
|
||||
assertThrows(NullPointerException.class, () -> inputStreamProvider.input().transferTo(null));
|
||||
|
||||
// tests single-byte input stream
|
||||
assertThrows(NullPointerException.class, () -> inputStreamProvider.input((byte) 1).transferTo(null));
|
||||
|
||||
// tests dual-byte input stream
|
||||
assertThrows(NullPointerException.class, () -> inputStreamProvider.input((byte) 1, (byte) 2).transferTo(null));
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing API compliance: complete content of input stream must be
|
||||
* transferred to output stream.
|
||||
*/
|
||||
static void assertStreamContents(InputStreamProvider inputStreamProvider,
|
||||
OutputStreamProvider outputStreamProvider) throws Exception {
|
||||
// tests empty input stream
|
||||
checkTransferredContents(inputStreamProvider, outputStreamProvider, new byte[0]);
|
||||
|
||||
// tests input stream with a length between 1k and 4k
|
||||
checkTransferredContents(inputStreamProvider, outputStreamProvider, createRandomBytes(1024, 4096));
|
||||
|
||||
// tests input stream with several data chunks, as 16k is more than a
|
||||
// single chunk can hold
|
||||
checkTransferredContents(inputStreamProvider, outputStreamProvider, createRandomBytes(16384, 16384));
|
||||
|
||||
// tests randomly chosen starting positions within source and
|
||||
// target stream
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
byte[] inBytes = createRandomBytes(MIN_SIZE, MAX_SIZE_INCR);
|
||||
int posIn = RND.nextInt(inBytes.length);
|
||||
int posOut = RND.nextInt(MIN_SIZE);
|
||||
checkTransferredContents(inputStreamProvider, outputStreamProvider, inBytes, posIn, posOut);
|
||||
}
|
||||
|
||||
// tests reading beyond source EOF (must not transfer any bytes)
|
||||
checkTransferredContents(inputStreamProvider, outputStreamProvider, createRandomBytes(4096, 0), 4096, 0);
|
||||
|
||||
// tests writing beyond target EOF (must extend output stream)
|
||||
checkTransferredContents(inputStreamProvider, outputStreamProvider, createRandomBytes(4096, 0), 0, 4096);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special test for stream-to-file / file-to-stream transfer of more than 2 GB.
|
||||
*/
|
||||
static void testMoreThanTwoGB(String direction, BiFunction<Path, Path, InputStream> inputStreamProvider,
|
||||
BiFunction<Path, Path, OutputStream> outputStreamProvider,
|
||||
ToLongBiFunction<InputStream, OutputStream> transfer) throws IOException {
|
||||
// prepare two temporary files to be compared at the end of the test
|
||||
// set the source file name
|
||||
String sourceName = String.format("test3GBSource_transfer%s%s.tmp", direction,
|
||||
RND.nextInt(Integer.MAX_VALUE));
|
||||
Path sourceFile = CWD.resolve(sourceName);
|
||||
|
||||
try {
|
||||
// set the target file name
|
||||
String targetName = String.format("test3GBTarget_transfer%s%s.tmp", direction,
|
||||
RND.nextInt(Integer.MAX_VALUE));
|
||||
Path targetFile = CWD.resolve(targetName);
|
||||
|
||||
try {
|
||||
// calculate initial position to be just short of 2GB
|
||||
final long initPos = 2047*BYTES_PER_WRITE;
|
||||
|
||||
// create the source file with a hint to be sparse
|
||||
try (FileChannel fc = FileChannel.open(sourceFile, CREATE_NEW, SPARSE, WRITE, APPEND)) {
|
||||
// set initial position to avoid writing nearly 2GB
|
||||
fc.position(initPos);
|
||||
|
||||
// Add random bytes to the remainder of the file
|
||||
long pos = initPos;
|
||||
while (pos < BYTES_WRITTEN) {
|
||||
int len = Math.toIntExact(BYTES_WRITTEN - pos);
|
||||
if (len > BYTES_PER_WRITE)
|
||||
len = BYTES_PER_WRITE;
|
||||
byte[] rndBytes = createRandomBytes(len, 0);
|
||||
ByteBuffer src = ByteBuffer.wrap(rndBytes);
|
||||
pos += fc.write(src);
|
||||
}
|
||||
}
|
||||
|
||||
// create the target file with a hint to be sparse
|
||||
try (FileChannel fc = FileChannel.open(targetFile, CREATE_NEW, WRITE, SPARSE)) {
|
||||
}
|
||||
|
||||
// performing actual transfer, effectively by multiple invocations of
|
||||
// FileChannel.transferFrom(ReadableByteChannel) / FileChannel.transferTo(WritableByteChannel)
|
||||
try (InputStream inputStream = inputStreamProvider.apply(sourceFile, targetFile);
|
||||
OutputStream outputStream = outputStreamProvider.apply(sourceFile, targetFile)) {
|
||||
long count = transfer.applyAsLong(inputStream, outputStream);
|
||||
|
||||
// compare reported transferred bytes, must be 3 GB
|
||||
// less the value of the initial position
|
||||
assertEquals(BYTES_WRITTEN - initPos, count);
|
||||
}
|
||||
|
||||
// compare content of both files, failing if different
|
||||
assertEquals(-1, Files.mismatch(sourceFile, targetFile));
|
||||
|
||||
} finally {
|
||||
Files.delete(targetFile);
|
||||
}
|
||||
} finally {
|
||||
Files.delete(sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run junit/othervm/timeout=720 TransferTo_2GB_transferFrom
|
||||
* @bug 8278268
|
||||
* @summary Tests if ChannelInputStream.transferFrom correctly
|
||||
* transfers 2GB+ using FileChannel.transferFrom(ReadableByteChannel).
|
||||
* @key randomness
|
||||
*/
|
||||
public class TransferTo_2GB_transferFrom extends TransferToBase {
|
||||
|
||||
/*
|
||||
* Special test for stream-to-file transfer of more than 2 GB. This test
|
||||
* covers multiple iterations of FileChannel.transferFrom(ReadableByteChannel),
|
||||
* which ChannelInputStream.transferFrom() only applies in this particular
|
||||
* case, and cannot get tested using a single byte[] due to size limitation
|
||||
* of arrays.
|
||||
*/
|
||||
@Test
|
||||
public void testMoreThanTwoGB() throws IOException {
|
||||
testMoreThanTwoGB("From",
|
||||
(sourceFile, targetFile) -> {
|
||||
try {
|
||||
return Channels.newInputStream(
|
||||
Channels.newChannel(new BufferedInputStream(Files.newInputStream(sourceFile))));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
},
|
||||
(sourceFile, targetFile) -> {
|
||||
try {
|
||||
return Channels.newOutputStream(FileChannel.open(targetFile, WRITE));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
},
|
||||
(inputStream, outputStream) -> {
|
||||
try {
|
||||
return inputStream.transferTo(outputStream);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run junit/othervm/timeout=720 TransferTo_2GB_transferTo
|
||||
* @bug 8265891
|
||||
* @summary Tests if ChannelInputStream.transferTo correctly
|
||||
* transfers 2GB+ using FileChannel.transferTo(WritableByteChannel).
|
||||
* @key randomness
|
||||
*/
|
||||
public class TransferTo_2GB_transferTo extends TransferToBase {
|
||||
|
||||
/*
|
||||
* Special test for file-to-stream transfer of more than 2 GB. This test
|
||||
* covers multiple iterations of FileChannel.transferTo(WritableByteChannel),
|
||||
* which ChannelInputStream.transferTo() only applies in this particular
|
||||
* case, and cannot get tested using a single byte[] due to size limitation
|
||||
* of arrays.
|
||||
*/
|
||||
@Test
|
||||
public void testMoreThanTwoGB() throws IOException {
|
||||
testMoreThanTwoGB("To",
|
||||
(sourceFile, targetFile) -> {
|
||||
try {
|
||||
return Channels.newInputStream(FileChannel.open(sourceFile));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
},
|
||||
(sourceFile, targetFile) -> {
|
||||
try {
|
||||
return Channels.newOutputStream(FileChannel.open(targetFile, WRITE));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
},
|
||||
(inputStream, outputStream) -> {
|
||||
try {
|
||||
return inputStream.transferTo(outputStream);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
52
test/jdk/java/nio/channels/Channels/Write.java
Normal file
52
test/jdk/java/nio/channels/Channels/Write.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2010, 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
|
||||
* @bug 4712766
|
||||
* @summary Test Channels.newOutputStream.write
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
public class Write {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
byte[] bb = new byte[3];
|
||||
File testFile = File.createTempFile("test1", null);
|
||||
testFile.deleteOnExit();
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(testFile);
|
||||
FileChannel fc = fos.getChannel();
|
||||
OutputStream out = Channels.newOutputStream(fc);
|
||||
|
||||
out.write(bb,0,1);
|
||||
out.write(bb,2,1);
|
||||
|
||||
out.close();
|
||||
fc.close();
|
||||
fos.close();
|
||||
testFile.delete();
|
||||
}
|
||||
}
|
||||
50
test/jdk/java/nio/channels/ConfigureBlocking.java
Normal file
50
test/jdk/java/nio/channels/ConfigureBlocking.java
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 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
|
||||
* @bug 4797768
|
||||
* @summary test configureBlocking on closed channels
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
public class ConfigureBlocking {
|
||||
public static void main (String [] str) throws Exception {
|
||||
SelectableChannel [] channels = null;
|
||||
channels = new SelectableChannel [] {
|
||||
DatagramChannel.open(),
|
||||
SocketChannel.open(),
|
||||
ServerSocketChannel.open()};
|
||||
for (int i = 0; i < channels.length; i++) {
|
||||
SelectableChannel channel = channels[i];
|
||||
channel.close();
|
||||
try {
|
||||
channel.configureBlocking(true);
|
||||
throw new RuntimeException("expected exception not thrown");
|
||||
} catch (ClosedChannelException e) {
|
||||
// Correct result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* @bug 8280113
|
||||
* @summary Test async close of a DatagramSocket obtained from a DatagramChannel where
|
||||
* the DatagramChannel's internal socket address caches are already populated
|
||||
* @library /test/lib
|
||||
* @run junit AdaptorAsyncCloseAfterReceive
|
||||
*/
|
||||
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class AdaptorAsyncCloseAfterReceive {
|
||||
|
||||
// used for scheduling socket close
|
||||
private static ScheduledExecutorService scheduler;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void finish() {
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test closing a DatagramSocket, obtained from a DatagramChannel, while the main
|
||||
* thread is blocked in receive. The receive method should throw rather than
|
||||
* completing with the sender address of a previous datagram.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@CsvSource({"0,0", "100,0", "0,60000", "100,60000"})
|
||||
void testReceive(int maxLength, int timeout) throws Exception {
|
||||
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||
dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
SocketAddress localAddress = dc.getLocalAddress();
|
||||
|
||||
populateSocketAddressCaches(dc);
|
||||
|
||||
DatagramSocket s = dc.socket();
|
||||
s.setSoTimeout(timeout);
|
||||
|
||||
// schedule socket to be closed while main thread blocked in receive
|
||||
Future<?> future = scheduler.schedule(() -> s.close(), 1, TimeUnit.SECONDS);
|
||||
try {
|
||||
while (true) {
|
||||
byte[] ba = new byte[maxLength];
|
||||
DatagramPacket p = new DatagramPacket(ba, maxLength);
|
||||
s.receive(p);
|
||||
SocketAddress sender = p.getSocketAddress();
|
||||
if (sender.equals(localAddress)) {
|
||||
fail("Received datagram from " + sender);
|
||||
} else {
|
||||
System.err.format("Datagram from %s ignored%n", sender);
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
// expected
|
||||
} finally {
|
||||
future.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send and receive a few messages to ensure that the DatagramChannel internal
|
||||
* socket address cache is populated. This setup is also done in a virtual
|
||||
* thread to ensure that the underlying socket is non-blocking.
|
||||
*/
|
||||
private void populateSocketAddressCaches(DatagramChannel dc) throws Exception {
|
||||
VThreadRunner.run(() -> {
|
||||
InetSocketAddress remote = (InetSocketAddress) dc.getLocalAddress();
|
||||
if (remote.getAddress().isAnyLocalAddress()) {
|
||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||
remote = new InetSocketAddress(lb, dc.socket().getLocalPort());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
ByteBuffer bb = ByteBuffer.allocate(32);
|
||||
dc.send(bb, remote);
|
||||
bb.rewind();
|
||||
dc.receive(bb);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
189
test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java
Normal file
189
test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* 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
|
||||
* 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
|
||||
* @bug 4313882 4981129 8143610 8232673
|
||||
* @summary Unit test for datagram-socket-channel adaptors
|
||||
* @modules java.base/java.net:+open
|
||||
* @library .. /test/lib
|
||||
* @build jdk.test.lib.Utils TestServers
|
||||
* @run main AdaptorBasic
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import jdk.test.lib.Platform;
|
||||
|
||||
|
||||
public class AdaptorBasic {
|
||||
|
||||
static java.io.PrintStream out = System.out;
|
||||
static Random rand = new Random();
|
||||
|
||||
static String toString(DatagramPacket dp) {
|
||||
return ("DatagramPacket[off=" + dp.getOffset()
|
||||
+ ", len=" + dp.getLength()
|
||||
+ "]");
|
||||
}
|
||||
|
||||
static int getBufLength(DatagramPacket p) throws Exception {
|
||||
Field f = DatagramPacket.class.getDeclaredField("bufLength");
|
||||
f.setAccessible(true);
|
||||
return (int) f.get(p);
|
||||
}
|
||||
|
||||
static void test(DatagramSocket ds, InetSocketAddress dst, boolean shouldTimeout)
|
||||
throws Exception
|
||||
{
|
||||
DatagramPacket op = new DatagramPacket(new byte[100], 13, 42, dst);
|
||||
rand.nextBytes(op.getData());
|
||||
int bufLength = 100 - 19;
|
||||
DatagramPacket ip = new DatagramPacket(new byte[100], 19, bufLength);
|
||||
out.println("pre op: " + toString(op) + " ip: " + toString(ip));
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
ds.send(op);
|
||||
|
||||
for (;;) {
|
||||
try {
|
||||
ds.receive(ip);
|
||||
// weed off stray datagrams
|
||||
if (ip.getPort() != dst.getPort()) continue;
|
||||
} catch (SocketTimeoutException x) {
|
||||
if (shouldTimeout) {
|
||||
out.println("Receive timed out, as expected");
|
||||
return;
|
||||
}
|
||||
throw x;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out.println("rtt: " + (System.currentTimeMillis() - start));
|
||||
out.println("post op: " + toString(op) + " ip: " + toString(ip));
|
||||
|
||||
for (int i = 0; i < ip.getLength(); i++) {
|
||||
if (ip.getData()[ip.getOffset() + i]
|
||||
!= op.getData()[op.getOffset() + i])
|
||||
throw new Exception("Incorrect data received");
|
||||
}
|
||||
|
||||
if (!(ip.getSocketAddress().equals(dst))) {
|
||||
throw new Exception("Incorrect sender address, expected: " + dst
|
||||
+ " actual: " + ip.getSocketAddress());
|
||||
}
|
||||
|
||||
if (getBufLength(ip) != bufLength) {
|
||||
throw new Exception("DatagramPacket bufLength changed by receive!!!");
|
||||
}
|
||||
}
|
||||
|
||||
static void test(InetSocketAddress dst,
|
||||
int timeout, boolean shouldTimeout,
|
||||
boolean connect)
|
||||
throws Exception
|
||||
{
|
||||
out.println();
|
||||
out.println("dst: " + dst);
|
||||
|
||||
DatagramSocket ds;
|
||||
if (false) {
|
||||
// Original
|
||||
ds = new DatagramSocket();
|
||||
} else {
|
||||
int attempts = 0;
|
||||
DatagramChannel toclose = null;
|
||||
while (true) {
|
||||
DatagramChannel dc = DatagramChannel.open();
|
||||
ds = dc.socket();
|
||||
if (Platform.isOSX() && dst.getAddress().isLoopbackAddress()) {
|
||||
// avoid binding to the wildcard on macOS if possible, in order to limit
|
||||
// potential port conflict issues
|
||||
ds.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
} else {
|
||||
ds.bind(new InetSocketAddress(0));
|
||||
}
|
||||
// on some systems it may be possible to bind two sockets
|
||||
// to the same port if one of them is bound to the wildcard,
|
||||
// if that happens, try again...
|
||||
if (ds.getLocalPort() == dst.getPort()) {
|
||||
if (toclose != null) toclose.close();
|
||||
toclose = dc;
|
||||
if (++attempts == 10) {
|
||||
throw new AssertionError("Couldn't allocate port for client socket");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (toclose != null) toclose.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out.println("socket: " + ds + " bound to src: "
|
||||
+ ds.getLocalSocketAddress() + ", dst: " + dst);
|
||||
if (connect) {
|
||||
ds.connect(dst);
|
||||
out.println("connect: " + ds);
|
||||
}
|
||||
InetSocketAddress src = new InetSocketAddress(ds.getLocalAddress(),
|
||||
ds.getLocalPort());
|
||||
out.println("src: " + src);
|
||||
|
||||
if (timeout > 0)
|
||||
ds.setSoTimeout(timeout);
|
||||
out.println("timeout: " + ds.getSoTimeout());
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
test(ds, dst, shouldTimeout);
|
||||
}
|
||||
|
||||
// Leave the socket open so that we don't reuse the old src address
|
||||
//ds.close();
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// need an UDP echo server
|
||||
try (TestServers.UdpEchoServer echoServer
|
||||
= TestServers.UdpEchoServer.startNewServer(100, InetAddress.getLoopbackAddress())) {
|
||||
final InetSocketAddress address
|
||||
= new InetSocketAddress(echoServer.getAddress(),
|
||||
echoServer.getPort());
|
||||
test(address, 0, false, false);
|
||||
test(address, 0, false, true);
|
||||
test(address, Integer.MAX_VALUE, false, false);
|
||||
}
|
||||
try (TestServers.UdpDiscardServer discardServer
|
||||
= TestServers.UdpDiscardServer.startNewServer()) {
|
||||
final InetSocketAddress address
|
||||
= new InetSocketAddress(discardServer.getAddress(),
|
||||
discardServer.getPort());
|
||||
test(address, 10, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* @bug 8232673
|
||||
* @summary Test DatagramChannel socket adaptor with concurrent send/receive
|
||||
*/
|
||||
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class AdaptorConcurrentIO {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testConcurrentSendReceive(0);
|
||||
testConcurrentSendReceive(60_000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a task that blocks in the adaptor's receive method, then invokes
|
||||
* the adaptor's send method to send a datagram. If the adaptor were using
|
||||
* the channel's blockingLock then send without be blocked waiting for
|
||||
* the receive to complete.
|
||||
*/
|
||||
static void testConcurrentSendReceive(int timeout) throws Exception {
|
||||
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||
dc.bind(new InetSocketAddress(lb, 0));
|
||||
DatagramSocket s = dc.socket();
|
||||
s.setSoTimeout(timeout);
|
||||
|
||||
ExecutorService pool = Executors.newSingleThreadExecutor();
|
||||
try {
|
||||
Future<String> result = pool.submit(() -> {
|
||||
byte[] data = new byte[100];
|
||||
DatagramPacket p = new DatagramPacket(data, 0, data.length);
|
||||
s.receive(p);
|
||||
return new String(p.getData(), p.getOffset(), p.getLength(), "UTF-8");
|
||||
});
|
||||
|
||||
Thread.sleep(200); // give chance for thread to block
|
||||
|
||||
byte[] data = "hello".getBytes("UTF-8");
|
||||
DatagramPacket p = new DatagramPacket(data, 0, data.length);
|
||||
p.setSocketAddress(s.getLocalSocketAddress());
|
||||
s.send(p);
|
||||
|
||||
String msg = result.get();
|
||||
if (!msg.equals("hello"))
|
||||
throw new RuntimeException("Unexpected message: " + msg);
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
117
test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java
Normal file
117
test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* @bug 8232673
|
||||
* @summary Test DatagramChannel socket adaptor connect method with illegal args
|
||||
* @run testng AdaptorConnect
|
||||
*/
|
||||
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import static java.net.InetAddress.getLoopbackAddress;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@Test
|
||||
public class AdaptorConnect {
|
||||
|
||||
/**
|
||||
* Invoke the given socket's connect method with illegal arguments.
|
||||
*/
|
||||
private void testConnectWithIllegalArguments(DatagramSocket s) {
|
||||
assertThrows(IllegalArgumentException.class, () -> s.connect(null));
|
||||
assertThrows(IllegalArgumentException.class, () -> s.connect(null, 7000));
|
||||
assertThrows(IllegalArgumentException.class, () -> s.connect(getLoopbackAddress(), -1));
|
||||
assertThrows(IllegalArgumentException.class, () -> s.connect(getLoopbackAddress(), 100_000));
|
||||
|
||||
SocketAddress sillyAddress = new SocketAddress() { };
|
||||
assertThrows(IllegalArgumentException.class, () -> s.connect(sillyAddress));
|
||||
|
||||
SocketAddress unresolved = InetSocketAddress.createUnresolved("foo", 7777);
|
||||
assertThrows(SocketException.class, () -> s.connect(unresolved));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test connect method with an open socket.
|
||||
*/
|
||||
public void testOpenSocket() throws Exception {
|
||||
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||
DatagramSocket s = dc.socket();
|
||||
|
||||
testConnectWithIllegalArguments(s);
|
||||
|
||||
// should not be bound or connected
|
||||
assertTrue(s.getLocalSocketAddress() == null);
|
||||
assertTrue(s.getRemoteSocketAddress() == null);
|
||||
|
||||
// connect(SocketAddress)
|
||||
var remote1 = new InetSocketAddress(getLoopbackAddress(), 7001);
|
||||
s.connect(remote1);
|
||||
assertEquals(s.getRemoteSocketAddress(), remote1);
|
||||
testConnectWithIllegalArguments(s);
|
||||
assertEquals(s.getRemoteSocketAddress(), remote1);
|
||||
|
||||
// connect(SocketAddress)
|
||||
var remote2 = new InetSocketAddress(getLoopbackAddress(), 7002);
|
||||
s.connect(remote2);
|
||||
assertEquals(s.getRemoteSocketAddress(), remote2);
|
||||
testConnectWithIllegalArguments(s);
|
||||
assertEquals(s.getRemoteSocketAddress(), remote2);
|
||||
|
||||
// connect(InetAddress, int)
|
||||
var remote3 = new InetSocketAddress(getLoopbackAddress(), 7003);
|
||||
s.connect(remote3.getAddress(), remote3.getPort());
|
||||
assertEquals(s.getRemoteSocketAddress(), remote3);
|
||||
testConnectWithIllegalArguments(s);
|
||||
assertEquals(s.getRemoteSocketAddress(), remote3);
|
||||
|
||||
// connect(InetAddress, int)
|
||||
var remote4 = new InetSocketAddress(getLoopbackAddress(), 7004);
|
||||
s.connect(remote4.getAddress(), remote4.getPort());
|
||||
assertEquals(s.getRemoteSocketAddress(), remote4);
|
||||
testConnectWithIllegalArguments(s);
|
||||
assertEquals(s.getRemoteSocketAddress(), remote4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test connect method with a closed socket.
|
||||
*/
|
||||
public void testClosedSocket() throws Exception {
|
||||
DatagramChannel dc = DatagramChannel.open();
|
||||
DatagramSocket s = dc.socket();
|
||||
dc.close();
|
||||
|
||||
testConnectWithIllegalArguments(s);
|
||||
|
||||
// connect does not throw an exception when closed
|
||||
var remote = new InetSocketAddress(getLoopbackAddress(), 7001);
|
||||
s.connect(remote);
|
||||
s.connect(remote.getAddress(), remote.getPort());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue