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:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View 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);
}
}
}
}

File diff suppressed because it is too large Load diff

View 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();
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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));
}
}
}

View 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));
}
}

View 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();
}
}

View 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);
}
}
}

View 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());
}
}

View 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);
}
}

View 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) + "'");
}
}

View 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) + "'");
}
}

View 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) + "'");
}
}

View 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) + "'");
}
}

View 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) + "'");
}
}

View 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) + "'");
}
}

View 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) + "'");
}
}

View 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();
}
}

View 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) + "'");
}
}

View 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);
}
}
}

View 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());
}
}
}

View 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;
}
}

View 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);
}
}
}

View 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]
}
}

View 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();
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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.");
}
}
}

View 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));
}
}

View 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);
}
}
}

View 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

View 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

View 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

View 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");
}
}

View 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);
}
}

View 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();
}
}

View 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");
}
}
}

View 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);
}
}
}
}

View 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");
}
}

View 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}");
}
}
}

View 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");
}
}
}

View 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) { }
}
}

View 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);
}
}

View 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);
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}

View 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) {
}
}
}

View file

@ -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");
}
}

View file

@ -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;
}
}

View 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();
}
}
}
}

View file

@ -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);
}
}

View file

@ -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");
}
}

View 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) { }
}
}
}

View file

@ -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;
}
}
}

View file

@ -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");
}
}

View 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();
}
}
}

View file

@ -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();
}
}
}
}

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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");
}
}

View 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);
}
}

View file

@ -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());
}
}

View file

@ -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();
}
}

View 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();
}
}

View file

@ -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) { }
}
}

View 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();
}
}
}

View 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);
}
}

View 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; }
}
}

View file

@ -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");
}
}
}

View 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);
}
}
}

View 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;
}
}

View 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);
}
}
}
});
}
}

View 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");
}
}

View 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
}
}

View 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);
}
);
}
}

View 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");
}
}

View 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();
}
}
}

View 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);
}
}

View 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));
};
}
}

View 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());
};
}
}

View 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);
}
}
}

View file

@ -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);
}
}
);
}
}

View file

@ -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);
}
}
);
}
}

View 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();
}
}

View 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
}
}
}
}

View file

@ -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);
}
});
}
}

View 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);
}
}
}

View file

@ -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();
}
}
}
}

View 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