/*
* 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.nio;
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Objects;
import sun.nio.ch.IOUtil;
import sun.nio.ch.Net;
import sun.nio.ch.SelChImpl;
import sun.nio.ch.SelectionKeyImpl;
import sun.nio.ch.SelectorProviderImpl;
Defines static methods to create channels
. Unless otherwise specified, passing a null
argument to any of the methods defined here will cause a NullPointerException
to be thrown.
Since: 11
/**
* Defines static methods to create {@link java.nio.channels.Channel channels}.
*
* <p> Unless otherwise specified, passing a {@code null} argument to any of the
* methods defined here will cause a {@code NullPointerException} to be thrown.
*
* @since 11
*/
public final class Channels {
private Channels() { }
An object used to coordinate the closing of a selectable channel created by readWriteSelectableChannel
. Since: 11
/**
* An object used to coordinate the closing of a selectable channel created
* by {@link Channels#readWriteSelectableChannel readWriteSelectableChannel}.
*
* @since 11
*/
public interface SelectableChannelCloser {
Closes a selectable channel.
This method is invoked by the channel's close method in order to
perform the actual work of closing the channel. This method is only
invoked if the channel has not yet been closed, and it is never
invoked more than once by the channel's close implementation.
An implementation of this method must arrange for any other thread that is blocked in an I/O operation upon the channel to return immediately, either by throwing an exception or by returning normally. If the channel is registered
with one or more Selector
s then the file descriptor should not be released until the implReleaseChannel
method is invoked.
Params: - sc –
The selectable channel
Throws: - IOException –
If an I/O error occurs while closing the file descriptor
See Also:
/**
* Closes a selectable channel.
*
* <p> This method is invoked by the channel's close method in order to
* perform the actual work of closing the channel. This method is only
* invoked if the channel has not yet been closed, and it is never
* invoked more than once by the channel's close implementation.
*
* <p> An implementation of this method must arrange for any other
* thread that is blocked in an I/O operation upon the channel to return
* immediately, either by throwing an exception or by returning normally.
* If the channel is {@link SelectableChannel#isRegistered registered}
* with one or more {@link java.nio.channels.Selector Selector}s then
* the file descriptor should not be released until the {@link
* #implReleaseChannel implReleaseChannel} method is invoked. </p>
*
* @param sc
* The selectable channel
*
* @throws IOException
* If an I/O error occurs while closing the file descriptor
*
* @see java.nio.channels.spi.AbstractInterruptibleChannel#implCloseChannel
*/
void implCloseChannel(SelectableChannel sc) throws IOException;
Release the file descriptor and any resources for a selectable channel that closed while registered with one or more Selector
s. This method is for cases where a channel is closed when registered
with one or more Selector
s. A channel may remain registered for some time after it is closed. This method is invoked when the channel is eventually deregistered from the last Selector
that it was registered with. It is invoked at most once.
Params: - sc –
The closed selectable channel
Throws: - IOException –
If an I/O error occurs
See Also: API Note: This method is invoked while synchronized on the selector
and its selected-key set. Great care must be taken to avoid deadlocks
with other threads that also synchronize on these objects.
/**
* Release the file descriptor and any resources for a selectable
* channel that closed while registered with one or more {@link
* java.nio.channels.Selector Selector}s.
*
* <p> This method is for cases where a channel is closed when
* {@link java.nio.channels.SelectableChannel#isRegistered registered}
* with one or more {@code Selector}s. A channel may remain registered
* for some time after it is closed. This method is invoked when the
* channel is eventually deregistered from the last {@code Selector}
* that it was registered with. It is invoked at most once.
*
* @apiNote This method is invoked while synchronized on the selector
* and its selected-key set. Great care must be taken to avoid deadlocks
* with other threads that also synchronize on these objects.
*
* @param sc
* The closed selectable channel
*
* @throws IOException
* If an I/O error occurs
*
* @see java.nio.channels.spi.AbstractSelector#deregister
*/
void implReleaseChannel(SelectableChannel sc) throws IOException;
}
Creates a selectable channel to a file descriptor that supports an operation-set
of OP_READ
and OP_WRITE
. The selectable channel will be created by the default SelectorProvider
. The given file descriptor is a socket or resource that can be multiplexed by a Selector
for read and write readiness. Great care is required to coordinate direct use of the file descriptor with the use of the selectable channel. In particular, changing the blocking mode or closing the file descriptor without careful coordination will result in unspecified and unsafe side effects. The given SelectableChannelCloser
is invoked to close the file descriptor and to coordinate the closing when the channel is registered with a Selector
.
If there is a security manager set then its checkRead
and checkWrite
methods are invoked to check that the caller has permission to both read from and write to the file descriptor.
Params: - fd –
The file descriptor
- closer –
The object to close the channel
Throws: - IllegalArgumentException – If the file descriptor is not
valid
- SecurityException –
If denied by the security manager
Implementation Note: This method throws UnsupportedOperationException
if the default SelectorProvider
is not the JDK built-in implementation. Returns: The selectable channel
/**
* Creates a selectable channel to a file descriptor that supports an
* {@link SelectableChannel#validOps() operation-set} of
* {@link SelectionKey#OP_READ OP_READ} and
* {@link SelectionKey#OP_WRITE OP_WRITE}. The selectable channel will be
* created by the default {@link SelectorProvider}.
*
* <p> The given file descriptor is a socket or resource that can be
* multiplexed by a {@link java.nio.channels.Selector} for read and write
* readiness. Great care is required to coordinate direct use of the file
* descriptor with the use of the selectable channel. In particular,
* changing the blocking mode or closing the file descriptor without careful
* coordination will result in unspecified and unsafe side effects. The
* given {@link SelectableChannelCloser SelectableChannelCloser} is invoked to
* close the file descriptor and to coordinate the closing when the channel
* is registered with a {@code Selector}. </p>
*
* <p> If there is a security manager set then its
* {@link SecurityManager#checkRead(FileDescriptor) checkRead} and
* {@link SecurityManager#checkWrite(FileDescriptor) checkWrite} methods
* are invoked to check that the caller has permission to both read from and
* write to the file descriptor. </p>
*
* @implNote This method throws {@code UnsupportedOperationException} if
* the default {@code SelectorProvider} is not the JDK built-in implementation.
*
* @param fd
* The file descriptor
* @param closer
* The object to close the channel
*
* @return The selectable channel
*
* @throws IllegalArgumentException
* If the file descriptor is not {@link FileDescriptor#valid() valid}
* @throws SecurityException
* If denied by the security manager
*/
public static SelectableChannel readWriteSelectableChannel(FileDescriptor fd,
SelectableChannelCloser closer) {
Objects.requireNonNull(closer);
if (!fd.valid())
throw new IllegalArgumentException("file descriptor is not valid");
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkRead(fd);
sm.checkWrite(fd);
}
SelectorProvider provider = SelectorProvider.provider();
if (!(provider instanceof SelectorProviderImpl))
throw new UnsupportedOperationException("custom SelectorProvider");
return new ReadWriteChannelImpl((SelectorProviderImpl)provider, fd, closer);
}
private static final class ReadWriteChannelImpl
extends AbstractSelectableChannel implements SelChImpl
{
private final FileDescriptor fd;
private final int fdVal;
private final SelectableChannelCloser closer;
ReadWriteChannelImpl(SelectorProviderImpl provider,
FileDescriptor fd,
SelectableChannelCloser closer) {
super(provider);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
this.closer = closer;
}
@Override
public FileDescriptor getFD() {
return fd;
}
@Override
public int getFDVal() {
return fdVal;
}
@Override
public int validOps() {
return (SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
private boolean translateReadyOps(int ops,
int initialOps,
SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
if (((ops & Net.POLLIN) != 0) &&
((intOps & SelectionKey.OP_READ) != 0))
newOps |= SelectionKey.OP_READ;
if (((ops & Net.POLLOUT) != 0) &&
((intOps & SelectionKey.OP_WRITE) != 0))
newOps |= SelectionKey.OP_WRITE;
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@Override
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
@Override
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
@Override
public int translateInterestOps(int ops) {
int newOps = 0;
if ((ops & SelectionKey.OP_READ) != 0)
newOps |= Net.POLLIN;
if ((ops & SelectionKey.OP_WRITE) != 0)
newOps |= Net.POLLOUT;
return newOps;
}
@Override
protected void implConfigureBlocking(boolean block) throws IOException {
IOUtil.configureBlocking(fd, block);
}
@Override
protected void implCloseSelectableChannel() throws IOException {
closer.implCloseChannel(this);
}
@Override
public void kill() throws IOException {
closer.implReleaseChannel(this);
}
}
}