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