Skip to content

Commit

Permalink
8325028: (ch) Pipe channels should lazily set socket to non-blocking …
Browse files Browse the repository at this point in the history
…mode on first use by virtual thread

Reviewed-by: bpb
  • Loading branch information
Alan Bateman committed Feb 8, 2024
1 parent 1fb9e3d commit d109903
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 14 deletions.
47 changes: 40 additions & 7 deletions src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
Expand Down Expand Up @@ -66,6 +66,13 @@ class SinkChannelImpl
// ID of native thread doing write, for signalling
private long thread;

// True if the channel's socket has been forced into non-blocking mode
// by a virtual thread. It cannot be reset. When the channel is in
// blocking mode and the channel's socket is in non-blocking mode then
// operations that don't complete immediately will poll the socket and
// preserve the semantics of blocking operations.
private volatile boolean forcedNonBlocking;

// -- End of fields protected by stateLock


Expand All @@ -79,11 +86,34 @@ public int getFDVal() {

SinkChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException {
super(sp);
IOUtil.configureBlocking(fd, false);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
}

/**
* Checks that the channel is open.
*
* @throws ClosedChannelException if channel is closed (or closing)
*/
private void ensureOpen() throws ClosedChannelException {
if (!isOpen())
throw new ClosedChannelException();
}

/**
* Ensures that the socket is configured non-blocking when on a virtual thread.
*/
private void configureSocketNonBlockingIfVirtualThread() throws IOException {
assert writeLock.isHeldByCurrentThread();
if (!forcedNonBlocking && Thread.currentThread().isVirtual()) {
synchronized (stateLock) {
ensureOpen();
IOUtil.configureBlocking(fd, false);
forcedNonBlocking = true;
}
}
}

/**
* Closes the write end of the pipe if there are no write operation in
* progress and the channel is not registered with a Selector.
Expand Down Expand Up @@ -183,9 +213,11 @@ protected void implConfigureBlocking(boolean block) throws IOException {
writeLock.lock();
try {
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
IOUtil.configureBlocking(fd, block);
ensureOpen();
// do nothing if virtual thread has forced the socket to be non-blocking
if (!forcedNonBlocking) {
IOUtil.configureBlocking(fd, block);
}
}
} finally {
writeLock.unlock();
Expand Down Expand Up @@ -241,8 +273,7 @@ private void beginWrite(boolean blocking) throws ClosedChannelException {
begin();
}
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
ensureOpen();
if (blocking)
thread = NativeThread.current();
}
Expand Down Expand Up @@ -279,6 +310,7 @@ public int write(ByteBuffer src) throws IOException {
int n = 0;
try {
beginWrite(blocking);
configureSocketNonBlockingIfVirtualThread();
n = IOUtil.write(fd, src, -1, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
Expand Down Expand Up @@ -306,6 +338,7 @@ public long write(ByteBuffer[] srcs, int offset, int length) throws IOException
long n = 0;
try {
beginWrite(blocking);
configureSocketNonBlockingIfVirtualThread();
n = IOUtil.write(fd, srcs, offset, length, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
Expand Down
47 changes: 40 additions & 7 deletions src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
Expand Down Expand Up @@ -66,6 +66,13 @@ class SourceChannelImpl
// ID of native thread doing read, for signalling
private long thread;

// True if the channel's socket has been forced into non-blocking mode
// by a virtual thread. It cannot be reset. When the channel is in
// blocking mode and the channel's socket is in non-blocking mode then
// operations that don't complete immediately will poll the socket and
// preserve the semantics of blocking operations.
private volatile boolean forcedNonBlocking;

// -- End of fields protected by stateLock


Expand All @@ -79,11 +86,34 @@ public int getFDVal() {

SourceChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException {
super(sp);
IOUtil.configureBlocking(fd, false);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
}

/**
* Checks that the channel is open.
*
* @throws ClosedChannelException if channel is closed (or closing)
*/
private void ensureOpen() throws ClosedChannelException {
if (!isOpen())
throw new ClosedChannelException();
}

/**
* Ensures that the socket is configured non-blocking when on a virtual thread.
*/
private void configureSocketNonBlockingIfVirtualThread() throws IOException {
assert readLock.isHeldByCurrentThread();
if (!forcedNonBlocking && Thread.currentThread().isVirtual()) {
synchronized (stateLock) {
ensureOpen();
IOUtil.configureBlocking(fd, false);
forcedNonBlocking = true;
}
}
}

/**
* Closes the read end of the pipe if there are no read operation in
* progress and the channel is not registered with a Selector.
Expand Down Expand Up @@ -183,9 +213,11 @@ protected void implConfigureBlocking(boolean block) throws IOException {
readLock.lock();
try {
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
IOUtil.configureBlocking(fd, block);
ensureOpen();
// do nothing if virtual thread has forced the socket to be non-blocking
if (!forcedNonBlocking) {
IOUtil.configureBlocking(fd, block);
}
}
} finally {
readLock.unlock();
Expand Down Expand Up @@ -241,8 +273,7 @@ private void beginRead(boolean blocking) throws ClosedChannelException {
begin();
}
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
ensureOpen();
if (blocking)
thread = NativeThread.current();
}
Expand Down Expand Up @@ -279,6 +310,7 @@ public int read(ByteBuffer dst) throws IOException {
int n = 0;
try {
beginRead(blocking);
configureSocketNonBlockingIfVirtualThread();
n = IOUtil.read(fd, dst, -1, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
Expand Down Expand Up @@ -306,6 +338,7 @@ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
long n = 0;
try {
beginRead(blocking);
configureSocketNonBlockingIfVirtualThread();
n = IOUtil.read(fd, dsts, offset, length, nd);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
Expand Down

7 comments on commit d109903

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@openjdk
Copy link

@openjdk openjdk bot commented on d109903 Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vpa1977 The target branch JDK-8325028 does not exist

@vpa1977
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/backport jdk21u-dev

@openjdk
Copy link

@openjdk openjdk bot commented on d109903 Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vpa1977 the backport was successfully created on the branch backport-vpa1977-d1099033 in my personal fork of openjdk/jdk21u-dev. To create a pull request with this backport targeting openjdk/jdk21u-dev:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit d1099033 from the openjdk/jdk repository.

The commit being backported was authored by Alan Bateman on 8 Feb 2024 and was reviewed by Brian Burkhalter.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk21u-dev:

$ git fetch https://github.com/openjdk-bots/jdk21u-dev.git backport-vpa1977-d1099033:backport-vpa1977-d1099033
$ git checkout backport-vpa1977-d1099033
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/jdk21u-dev.git backport-vpa1977-d1099033

⚠️ @vpa1977 You are not yet a collaborator in my fork openjdk-bots/jdk21u-dev. An invite will be sent out and you need to accept it before you can proceed.

@openjdk
Copy link

@openjdk openjdk bot commented on d109903 Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vpa1977 The target repository jdk22u-dev is not a valid target for backports.
List of valid target repositories: openjdk/jdk, openjdk/jdk11u, openjdk/jdk11u-dev, openjdk/jdk17u, openjdk/jdk17u-dev, openjdk/jdk21u, openjdk/jdk21u-dev, openjdk/jdk22, openjdk/jdk22u, openjdk/jdk7u, openjdk/jdk8u, openjdk/jdk8u-dev, openjdk/jfx, openjdk/jfx17u, openjdk/jfx21u, openjdk/jfx22u, openjdk/lilliput-jdk17u, openjdk/lilliput-jdk21u, openjdk/shenandoah-jdk21u, openjdk/shenandoah-jdk8u.
Supplying the organization/group prefix is optional.

@vpa1977
Copy link
Contributor

@vpa1977 vpa1977 commented on d109903 Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/backport jdk22u

@openjdk
Copy link

@openjdk openjdk bot commented on d109903 Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vpa1977 the backport was successfully created on the branch backport-vpa1977-d1099033 in my personal fork of openjdk/jdk22u. To create a pull request with this backport targeting openjdk/jdk22u:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit d1099033 from the openjdk/jdk repository.

The commit being backported was authored by Alan Bateman on 8 Feb 2024 and was reviewed by Brian Burkhalter.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk22u:

$ git fetch https://github.com/openjdk-bots/jdk22u.git backport-vpa1977-d1099033:backport-vpa1977-d1099033
$ git checkout backport-vpa1977-d1099033
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/jdk22u.git backport-vpa1977-d1099033

⚠️ @vpa1977 You are not yet a collaborator in my fork openjdk-bots/jdk22u. An invite will be sent out and you need to accept it before you can proceed.

Please sign in to comment.