1 /* 2 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 import java.lang.reflect.*; 42 import java.io.*; 43 import java.net.*; 44 45 /** 46 * This class is provided for access to the underlying poll(2) 47 * or /dev/poll kernel interfaces. This may be needed for 48 * multiplexing IO when an application cannot afford to have 49 * a thread block on each outstanding IO request. 50 * 51 * It currently supports the same basic functionality as the 52 * C poll(2) API, although for efficiency we needed to avoid 53 * passing the entire pollfd array for every call. See man 54 * pages for poll(2) for info on C API and event types. 55 * 56 * 57 * @author Bruce Chapman 58 * @see java.io.FileDescriptor 59 * @see java.net.Socket 60 * @see attached README.txt 61 * @since JDK1.2 62 */ 63 64 public class Poller { 65 /** 66 * Solaris POLL event types. 67 */ 68 public final static short POLLERR = 0x08; 69 public final static short POLLHUP = 0x10; 70 public final static short POLLNVAL = 0x20; 71 public final static short POLLIN = 1; 72 public final static short POLLPRI = 2; 73 public final static short POLLOUT = 4; 74 public final static short POLLRDNORM = 0x40; 75 public final static short POLLWRNORM = POLLOUT ; 76 public final static short POLLRDBAND = 0x80; 77 public final static short POLLWRBAND = 0x100; 78 public final static short POLLNORM = POLLRDNORM; 79 80 /* 81 * This global synchronization object must be used for all 82 * creation or destruction of Poller objects. 83 */ 84 private final static Object globalSync = new Object(); 85 86 /* 87 * The handle for a Poller Object...is used in the JNI C code 88 * where all the associated data is kept. 89 */ 90 private int handle; 91 92 /** 93 * Constructs an instance of a <code>Poller</code> object. 94 * Native code uses sysconf(_SC_OPEN_MAX) to determine how 95 * many fd/skt objects this Poller object can contain. 96 */ 97 public Poller() throws Exception { 98 synchronized(globalSync) { 99 this.handle = nativeCreatePoller(-1); 100 } 101 } 102 103 /** 104 * Constructs an instance of a <code>Poller</code> object. 105 * @param maxFd the maximum number of FileDescriptors/Sockets 106 * this Poller object can contain. 107 */ 108 public Poller(int maxFd) throws Exception { 109 synchronized(globalSync) { 110 this.handle = nativeCreatePoller(maxFd); 111 } 112 } 113 114 /** 115 * Needed to clean up at the JNI C level when object is GCd. 116 */ 117 protected void finalize() throws Throwable { 118 synchronized(globalSync) { 119 nativeDestroyPoller(handle); 120 super.finalize(); 121 } 122 } 123 124 /** 125 * Since we can't guarantee WHEN finalize is called, we may 126 * recycle on our own. 127 * @param maxFd the maximum number of FileDescriptors/Sockets 128 * this Poller object can contain. 129 */ 130 public void reset(int maxFd) throws Exception { 131 synchronized(globalSync) { 132 nativeDestroyPoller(handle); 133 this.handle = nativeCreatePoller(maxFd); 134 } 135 } 136 /** 137 * Since we can't guarantee WHEN finalize is called, we may 138 * recycle on our own. 139 */ 140 public void reset() throws Exception { 141 synchronized(globalSync) { 142 nativeDestroyPoller(handle); 143 this.handle = nativeCreatePoller(-1); 144 } 145 } 146 147 /** 148 * Add FileDescriptor to the set handled by this Poller object. 149 * 150 * @param fdObj the FileDescriptor, Socket, or ServerSocket to add. 151 * @param event the bitmask of events we are interested in. 152 * @return the OS level fd associated with this IO Object 153 * (which is what waitMultiple() stores in fds[]) 154 */ 155 public synchronized int add(Object fdObj, short event) throws Exception { 156 return nativeAddFd(handle,findfd(fdObj), event); 157 } 158 159 /** 160 * Remove FileDescriptor from the set handled by this Poller object. 161 * 162 * Must be called before the fd/skt is closed. 163 * @param fdObj the FileDescriptor, Socket, or ServerSocket to remove. 164 * @return true if removal succeeded. 165 */ 166 public synchronized boolean remove(Object fdObj) throws Exception { 167 return (nativeRemoveFd(handle,findfd(fdObj)) == 1); 168 } 169 /** 170 * Check if fd or socket is already in the set handled by this Poller object 171 * 172 * @param fdObj the FileDescriptor or [Server]Socket to check. 173 * @return true if fd/skt is in the set for this Poller object. 174 */ 175 public synchronized boolean isMember(Object fdObj) throws Exception { 176 return (nativeIsMember(handle,findfd(fdObj)) == 1); 177 } 178 /** 179 * Wait on Multiple IO Objects. 180 * 181 * @param maxRet the maximum number of fds[] and revents[] to return. 182 * @param fds[] (return) an array of ints in which to store fds with 183 * available data upon a successful non-timeout return. 184 * fds.length must be >= maxRet 185 * @param revents[] (return) the actual events available on the 186 * same-indexed fds[] (i.e. fds[0] has events revents[0]) 187 * revents.length must be >= maxRet 188 * 189 * Note : both above arrays are "dense," i.e. only fds[] with events 190 * available are returned. 191 * 192 * @param timeout the maximum number of milliseconds to wait for 193 * events before timing out. 194 * @return the number of fds with triggered events. 195 * 196 * Note : convenience methods exist for skipping the timeout parameter 197 * or the maxRet parameter (in the case of no maxRet, fds.length 198 * must equal revents.length) 199 * 200 * obj.waitMultiple(null,null,timeout) can be used for pausing the LWP 201 * (much more reliable and scalable than Thread.sleep() or Object.wait()) 202 */ 203 public synchronized int waitMultiple(int maxRet, int[] fds,short[] revents, 204 long timeout) throws Exception 205 { 206 if ((revents == null) || (fds == null)) { 207 if (maxRet > 0) { 208 throw new NullPointerException("fds or revents is null"); 209 } 210 } else if ( (maxRet < 0) || 211 (maxRet > revents.length) || (maxRet > fds.length) ) { 212 throw new IllegalArgumentException("maxRet out of range"); 213 } 214 215 int ret = nativeWait(handle, maxRet, fds, revents, timeout); 216 if (ret < 0) { 217 throw new InterruptedIOException(); 218 } 219 return ret; 220 } 221 222 /** 223 * Wait on Multiple IO Objects (no timeout). 224 * A convenience method for waiting indefinitely on IO events 225 * 226 * @see Poller#waitMultiple 227 * 228 */ 229 public int waitMultiple(int maxRet, int[] fds, short[] revents) 230 throws Exception 231 { 232 return waitMultiple(maxRet, fds, revents,-1L); // already synchronized 233 } 234 235 /** 236 * Wait on Multiple IO Objects (no maxRet). 237 * A convenience method for waiting on IO events when the fds 238 * and revents arrays are the same length and that specifies the 239 * maximum number of return events. 240 * 241 * @see Poller#waitMultiple 242 * 243 */ 244 public synchronized int waitMultiple(int[] fds, short[] revents, 245 long timeout) throws Exception 246 { 247 if ((revents == null) && (fds == null)) { 248 return nativeWait(handle,0,null,null,timeout); 249 } else if ((revents == null) || (fds == null)) { 250 throw new NullPointerException("revents or fds is null"); 251 } else if (fds.length == revents.length) { 252 return nativeWait(handle, fds.length, fds, revents, timeout); 253 } 254 throw new IllegalArgumentException("fds.length != revents.length"); 255 } 256 257 258 /** 259 * Wait on Multiple IO Objects (no maxRet/timeout). 260 * A convenience method for waiting on IO events when the fds 261 * and revents arrays are the same length and that specifies the 262 * maximum number of return events, and when waiting indefinitely 263 * for IO events to occur. 264 * 265 * @see Poller#waitMultiple 266 * 267 */ 268 public int waitMultiple(int[] fds, short[] revents) 269 throws Exception 270 { 271 if ((revents == null) || (fds == null)) { 272 throw new NullPointerException("fds or revents is null"); 273 } else if (fds.length == revents.length) { 274 return waitMultiple(revents.length,fds,revents,-1L); // already sync 275 } 276 throw new IllegalArgumentException("fds.length != revents.length"); 277 } 278 279 // Utility - get (int) fd from FileDescriptor or [Server]Socket objects. 280 281 private int findfd(Object fdObj) throws Exception { 282 Class cl; 283 Field f; 284 Object val, implVal; 285 286 if ((fdObj instanceof java.net.Socket) || 287 (fdObj instanceof java.net.ServerSocket)) { 288 cl = fdObj.getClass(); 289 f = cl.getDeclaredField("impl"); 290 f.setAccessible(true); 291 val = f.get(fdObj); 292 cl = f.getType(); 293 f = cl.getDeclaredField("fd"); 294 f.setAccessible(true); 295 implVal = f.get(val); 296 cl = f.getType(); 297 f = cl.getDeclaredField("fd"); 298 f.setAccessible(true); 299 return ((Integer) f.get(implVal)).intValue(); 300 } else if ( fdObj instanceof java.io.FileDescriptor ) { 301 cl = fdObj.getClass(); 302 f = cl.getDeclaredField("fd"); 303 f.setAccessible(true); 304 return ((Integer) f.get(fdObj)).intValue(); 305 } 306 else { 307 throw new IllegalArgumentException("Illegal Object type."); 308 } 309 } 310 311 // Actual NATIVE calls 312 313 private static native int nativeInit(); 314 private native int nativeCreatePoller(int maxFd) throws Exception; 315 private native void nativeDestroyPoller(int handle) throws Exception; 316 private native int nativeAddFd(int handle, int fd, short events) 317 throws Exception; 318 private native int nativeRemoveFd(int handle, int fd) throws Exception; 319 private native int nativeRemoveIndex(int handle, int index) 320 throws Exception; 321 private native int nativeIsMember(int handle, int fd) throws Exception; 322 private native int nativeWait(int handle, int maxRet, int[] fds, 323 short[] events, long timeout) 324 throws Exception; 325 /** 326 * Get number of active CPUs in this machine 327 * to determine proper level of concurrency. 328 */ 329 public static native int getNumCPUs(); 330 331 static { 332 System.loadLibrary("poller"); 333 nativeInit(); 334 } 335 }