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 }