893N/A/*
2362N/A * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
893N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
893N/A *
893N/A * This code is free software; you can redistribute it and/or modify it
893N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
893N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
893N/A *
893N/A * This code is distributed in the hope that it will be useful, but WITHOUT
893N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
893N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
893N/A * version 2 for more details (a copy is included in the LICENSE file that
893N/A * accompanied this code).
893N/A *
893N/A * You should have received a copy of the GNU General Public License version
893N/A * 2 along with this work; if not, write to the Free Software Foundation,
893N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
893N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
893N/A */
893N/A
893N/Apackage sun.nio.ch;
893N/A
893N/Aimport java.nio.channels.spi.AsynchronousChannelProvider;
893N/Aimport java.nio.channels.*;
893N/Aimport java.io.IOException;
893N/Aimport java.io.Closeable;
893N/Aimport java.io.FileDescriptor;
893N/Aimport java.util.Map;
893N/Aimport java.util.HashMap;
893N/Aimport java.util.concurrent.locks.ReadWriteLock;
893N/Aimport java.util.concurrent.locks.ReentrantReadWriteLock;
893N/A
893N/A/**
893N/A * Base implementation of AsynchronousChannelGroupImpl for Unix systems.
893N/A */
893N/A
893N/Aabstract class Port extends AsynchronousChannelGroupImpl {
893N/A static final short POLLIN = 0x0001;
893N/A static final short POLLOUT = 0x0004;
893N/A static final short POLLERR = 0x0008;
893N/A static final short POLLHUP = 0x0010;
893N/A
893N/A /**
893N/A * Implemented by clients registered with this port.
893N/A */
893N/A interface PollableChannel extends Closeable {
1580N/A void onEvent(int events, boolean mayInvokeDirect);
893N/A }
893N/A
893N/A // maps fd to "pollable" channel
893N/A protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock();
893N/A protected final Map<Integer,PollableChannel> fdToChannel =
893N/A new HashMap<Integer,PollableChannel>();
893N/A
893N/A
893N/A Port(AsynchronousChannelProvider provider, ThreadPool pool) {
893N/A super(provider, pool);
893N/A }
893N/A
893N/A /**
893N/A * Register channel identified by its file descriptor
893N/A */
893N/A final void register(int fd, PollableChannel ch) {
893N/A fdToChannelLock.writeLock().lock();
893N/A try {
893N/A if (isShutdown())
893N/A throw new ShutdownChannelGroupException();
893N/A fdToChannel.put(Integer.valueOf(fd), ch);
893N/A } finally {
893N/A fdToChannelLock.writeLock().unlock();
893N/A }
893N/A }
893N/A
893N/A /**
893N/A * Unregister channel identified by its file descriptor
893N/A */
893N/A final void unregister(int fd) {
893N/A boolean checkForShutdown = false;
893N/A
893N/A fdToChannelLock.writeLock().lock();
893N/A try {
893N/A fdToChannel.remove(Integer.valueOf(fd));
893N/A
893N/A // last key to be removed so check if group is shutdown
893N/A if (fdToChannel.isEmpty())
893N/A checkForShutdown = true;
893N/A
893N/A } finally {
893N/A fdToChannelLock.writeLock().unlock();
893N/A }
893N/A
893N/A // continue shutdown
893N/A if (checkForShutdown && isShutdown()) {
893N/A try {
893N/A shutdownNow();
893N/A } catch (IOException ignore) { }
893N/A }
893N/A }
893N/A /**
893N/A * Register file descriptor with polling mechanism for given events.
893N/A * The implementation should translate the events as required.
893N/A */
893N/A abstract void startPoll(int fd, int events);
893N/A
893N/A @Override
893N/A final boolean isEmpty() {
893N/A fdToChannelLock.writeLock().lock();
893N/A try {
893N/A return fdToChannel.isEmpty();
893N/A } finally {
893N/A fdToChannelLock.writeLock().unlock();
893N/A }
893N/A }
893N/A
893N/A @Override
893N/A final Object attachForeignChannel(final Channel channel, FileDescriptor fd) {
893N/A int fdVal = IOUtil.fdVal(fd);
893N/A register(fdVal, new PollableChannel() {
1580N/A public void onEvent(int events, boolean mayInvokeDirect) { }
893N/A public void close() throws IOException {
893N/A channel.close();
893N/A }
893N/A });
893N/A return Integer.valueOf(fdVal);
893N/A }
893N/A
893N/A @Override
893N/A final void detachForeignChannel(Object key) {
893N/A unregister((Integer)key);
893N/A }
893N/A
893N/A @Override
893N/A final void closeAllChannels() {
893N/A /**
893N/A * Close channels in batches of up to 128 channels. This allows close
893N/A * to remove the channel from the map without interference.
893N/A */
893N/A final int MAX_BATCH_SIZE = 128;
893N/A PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE];
893N/A int count;
893N/A do {
893N/A // grab a batch of up to 128 channels
893N/A fdToChannelLock.writeLock().lock();
893N/A count = 0;
893N/A try {
893N/A for (Integer fd: fdToChannel.keySet()) {
893N/A channels[count++] = fdToChannel.get(fd);
893N/A if (count >= MAX_BATCH_SIZE)
893N/A break;
893N/A }
893N/A } finally {
893N/A fdToChannelLock.writeLock().unlock();
893N/A }
893N/A
893N/A // close them
893N/A for (int i=0; i<count; i++) {
893N/A try {
893N/A channels[i].close();
893N/A } catch (IOException ignore) { }
893N/A }
893N/A } while (count > 0);
893N/A }
893N/A}