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 static final short POLLIN = 0x0001; 44 static final short POLLOUT = 0x0004; 45 static final short POLLERR = 0x0008; 46 static final short POLLHUP = 0x0010; 47 48 /** 49 * Implemented by clients registered with this port. 50 */ 51 interface PollableChannel extends Closeable { 52 void onEvent(int events, boolean mayInvokeDirect); 53 } 54 55 // maps fd to "pollable" channel 56 protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock(); 57 protected final Map<Integer,PollableChannel> fdToChannel = 58 new HashMap<Integer,PollableChannel>(); 59 60 61 Port(AsynchronousChannelProvider provider, ThreadPool pool) { 62 super(provider, pool); 63 } 64 65 /** 66 * Register channel identified by its file descriptor 67 */ 68 final void register(int fd, PollableChannel ch) { 69 fdToChannelLock.writeLock().lock(); 70 try { 71 if (isShutdown()) 72 throw new ShutdownChannelGroupException(); 73 fdToChannel.put(Integer.valueOf(fd), ch); 74 } finally { 75 fdToChannelLock.writeLock().unlock(); 76 } 77 } 78 79 /** 80 * Callback method for implementations that need special handling when fd is 81 * removed (currently only needed in the AIX-Port - see AixPollPort.java). 82 */ 83 protected void preUnregister(int fd) { 84 // Do nothing by default. 85 } 86 87 /** 88 * Unregister channel identified by its file descriptor 89 */ 90 final void unregister(int fd) { 91 boolean checkForShutdown = false; 92 93 preUnregister(fd); 94 95 fdToChannelLock.writeLock().lock(); 96 try { 97 fdToChannel.remove(Integer.valueOf(fd)); 98 99 // last key to be removed so check if group is shutdown 100 if (fdToChannel.isEmpty()) 101 checkForShutdown = true; 102 103 } finally { 104 fdToChannelLock.writeLock().unlock(); 105 } 106 107 // continue shutdown 108 if (checkForShutdown && isShutdown()) { 109 try { 110 shutdownNow(); 111 } catch (IOException ignore) { } 112 } 113 } 114 /** 115 * Register file descriptor with polling mechanism for given events. 116 * The implementation should translate the events as required. 117 */ 118 abstract void startPoll(int fd, int events); 119 120 @Override 121 final boolean isEmpty() { 122 fdToChannelLock.writeLock().lock(); 123 try { 124 return fdToChannel.isEmpty(); 125 } finally { 126 fdToChannelLock.writeLock().unlock(); 127 } 128 } 129 130 @Override 131 final Object attachForeignChannel(final Channel channel, FileDescriptor fd) { 132 int fdVal = IOUtil.fdVal(fd); 133 register(fdVal, new PollableChannel() { 134 public void onEvent(int events, boolean mayInvokeDirect) { } 135 public void close() throws IOException { 136 channel.close(); 137 } 138 }); 139 return Integer.valueOf(fdVal); 140 } 141 142 @Override 143 final void detachForeignChannel(Object key) { 144 unregister((Integer)key); 145 } 146 147 @Override 148 final void closeAllChannels() { 149 /** 150 * Close channels in batches of up to 128 channels. This allows close 151 * to remove the channel from the map without interference. 152 */ 153 final int MAX_BATCH_SIZE = 128; 154 PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE]; 155 int count; 156 do { 157 // grab a batch of up to 128 channels 158 fdToChannelLock.writeLock().lock(); 159 count = 0; 160 try { 161 for (Integer fd: fdToChannel.keySet()) { 162 channels[count++] = fdToChannel.get(fd); 163 if (count >= MAX_BATCH_SIZE) 164 break; 165 } 166 } finally { 167 fdToChannelLock.writeLock().unlock(); 168 } 169 170 // close them 171 for (int i=0; i<count; i++) { 172 try { 173 channels[i].close(); 174 } catch (IOException ignore) { } 175 } 176 } while (count > 0); 177 } 178 }