1e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera/*
2e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
3e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera *
5e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * This code is free software; you can redistribute it and/or modify it
6e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * under the terms of the GNU General Public License version 2 only, as
7e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * published by the Free Software Foundation.  Oracle designates this
8e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * particular file as subject to the "Classpath" exception as provided
9e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * by Oracle in the LICENSE file that accompanied this code.
10e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera *
11e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * This code is distributed in the hope that it will be useful, but WITHOUT
12e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * version 2 for more details (a copy is included in the LICENSE file that
15e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * accompanied this code).
16e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera *
17e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * You should have received a copy of the GNU General Public License version
18e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * 2 along with this work; if not, write to the Free Software Foundation,
19e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera *
21e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * or visit www.oracle.com if you need additional information or have any
23e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * questions.
24e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera */
25e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
26e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmerapackage sun.nio.ch;
27e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
28e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.nio.channels.spi.AsynchronousChannelProvider;
29e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.nio.channels.*;
30e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.io.IOException;
31e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.io.Closeable;
32e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.io.FileDescriptor;
33e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.util.Map;
34e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.util.HashMap;
35e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.util.concurrent.locks.ReadWriteLock;
36e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraimport java.util.concurrent.locks.ReentrantReadWriteLock;
37e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
38e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera/**
39e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera * Base implementation of AsynchronousChannelGroupImpl for Unix systems.
40e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera */
41e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
42e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmeraabstract class Port extends AsynchronousChannelGroupImpl {
43e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
44e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    /**
45e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     * Implemented by clients registered with this port.
46e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     */
47e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    interface PollableChannel extends Closeable {
48e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        void onEvent(int events, boolean mayInvokeDirect);
49e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
50e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
51e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    // maps fd to "pollable" channel
52e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock();
53e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    protected final Map<Integer,PollableChannel> fdToChannel =
54e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        new HashMap<Integer,PollableChannel>();
55e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
56e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
57e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    Port(AsynchronousChannelProvider provider, ThreadPool pool) {
58e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        super(provider, pool);
59e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
60e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
61e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    /**
62e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     * Register channel identified by its file descriptor
63e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     */
64e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    final void register(int fd, PollableChannel ch) {
65e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        fdToChannelLock.writeLock().lock();
66e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        try {
67e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            if (isShutdown())
68e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                throw new ShutdownChannelGroupException();
69e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            fdToChannel.put(Integer.valueOf(fd), ch);
70e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        } finally {
71e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            fdToChannelLock.writeLock().unlock();
72e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        }
73e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
74e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
75e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    /**
76519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera     * Callback method for implementations that need special handling when fd is
77519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera     * removed (currently only needed in the AIX-Port - see AixPollPort.java).
78519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera     */
79519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera    protected void preUnregister(int fd) {
80519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera        // Do nothing by default.
81519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera    }
82519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera
83519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera    /**
84e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     * Unregister channel identified by its file descriptor
85e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     */
86e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    final void unregister(int fd) {
87e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        boolean checkForShutdown = false;
88e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
89519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera        preUnregister(fd);
90519adb2f61bb2bfa6cc993b1ca15cf7022b96697Shubham Ajmera
91e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        fdToChannelLock.writeLock().lock();
92e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        try {
93e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            fdToChannel.remove(Integer.valueOf(fd));
94e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
95e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            // last key to be removed so check if group is shutdown
96e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            if (fdToChannel.isEmpty())
97e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                checkForShutdown = true;
98e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
99e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        } finally {
100e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            fdToChannelLock.writeLock().unlock();
101e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        }
102e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
103e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        // continue shutdown
104e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        if (checkForShutdown && isShutdown()) {
105e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            try {
106e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                shutdownNow();
107e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            } catch (IOException ignore) { }
108e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        }
109e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
110e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    /**
111e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     * Register file descriptor with polling mechanism for given events.
112e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     * The implementation should translate the events as required.
113e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera     */
114e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    abstract void startPoll(int fd, int events);
115e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
116e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    @Override
117e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    final boolean isEmpty() {
118e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        fdToChannelLock.writeLock().lock();
119e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        try {
120e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            return fdToChannel.isEmpty();
121e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        } finally {
122e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            fdToChannelLock.writeLock().unlock();
123e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        }
124e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
125e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
126e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    @Override
127e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    final Object attachForeignChannel(final Channel channel, FileDescriptor fd) {
128e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        int fdVal = IOUtil.fdVal(fd);
129e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        register(fdVal, new PollableChannel() {
130e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            public void onEvent(int events, boolean mayInvokeDirect) { }
131e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            public void close() throws IOException {
132e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                channel.close();
133e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            }
134e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        });
135e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        return Integer.valueOf(fdVal);
136e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
137e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
138e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    @Override
139e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    final void detachForeignChannel(Object key) {
140e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        unregister((Integer)key);
141e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
142e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
143e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    @Override
144e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    final void closeAllChannels() {
145e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        /**
146e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera         * Close channels in batches of up to 128 channels. This allows close
147e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera         * to remove the channel from the map without interference.
148e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera         */
149e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        final int MAX_BATCH_SIZE = 128;
150e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE];
151e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        int count;
152e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        do {
153e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            // grab a batch of up to 128 channels
154e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            fdToChannelLock.writeLock().lock();
155e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            count = 0;
156e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            try {
157e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                for (Integer fd: fdToChannel.keySet()) {
158e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                    channels[count++] = fdToChannel.get(fd);
159e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                    if (count >= MAX_BATCH_SIZE)
160e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                        break;
161e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                }
162e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            } finally {
163e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                fdToChannelLock.writeLock().unlock();
164e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            }
165e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera
166e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            // close them
167e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            for (int i=0; i<count; i++) {
168e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                try {
169e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                    channels[i].close();
170e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera                } catch (IOException ignore) { }
171e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera            }
172e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera        } while (count > 0);
173e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera    }
174e318a0eaa02b186f9f135016e95a6282fe9a83cbShubham Ajmera}
175