0N/A/*
2362N/A * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
0N/A *
0N/A * Redistribution and use in source and binary forms, with or without
0N/A * modification, are permitted provided that the following conditions
0N/A * are met:
0N/A *
0N/A * - Redistributions of source code must retain the above copyright
0N/A * notice, this list of conditions and the following disclaimer.
0N/A *
0N/A * - Redistributions in binary form must reproduce the above copyright
0N/A * notice, this list of conditions and the following disclaimer in the
0N/A * documentation and/or other materials provided with the distribution.
0N/A *
2362N/A * - Neither the name of Oracle nor the names of its
0N/A * contributors may be used to endorse or promote products derived
0N/A * from this software without specific prior written permission.
0N/A *
0N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
0N/A * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0N/A * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0N/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0N/A * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0N/A * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0N/A * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0N/A * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0N/A * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0N/A * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0N/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
0N/Aimport java.lang.reflect.*;
0N/Aimport java.io.*;
0N/Aimport java.net.*;
0N/A
0N/A/**
0N/A * This class is provided for access to the underlying poll(2)
0N/A * or /dev/poll kernel interfaces. This may be needed for
0N/A * multiplexing IO when an application cannot afford to have
0N/A * a thread block on each outstanding IO request.
0N/A *
0N/A * It currently supports the same basic functionality as the
0N/A * C poll(2) API, although for efficiency we needed to avoid
0N/A * passing the entire pollfd array for every call. See man
0N/A * pages for poll(2) for info on C API and event types.
0N/A *
0N/A *
0N/A * @author Bruce Chapman
0N/A * @see java.io.FileDescriptor
0N/A * @see java.net.Socket
0N/A * @see attached README.txt
0N/A * @since JDK1.2
0N/A */
0N/A
0N/Apublic class Poller {
0N/A /**
0N/A * Solaris POLL event types.
0N/A */
0N/A public final static short POLLERR = 0x08;
0N/A public final static short POLLHUP = 0x10;
0N/A public final static short POLLNVAL = 0x20;
0N/A public final static short POLLIN = 1;
0N/A public final static short POLLPRI = 2;
0N/A public final static short POLLOUT = 4;
0N/A public final static short POLLRDNORM = 0x40;
0N/A public final static short POLLWRNORM = POLLOUT ;
0N/A public final static short POLLRDBAND = 0x80;
0N/A public final static short POLLWRBAND = 0x100;
0N/A public final static short POLLNORM = POLLRDNORM;
0N/A
0N/A /*
0N/A * This global synchronization object must be used for all
0N/A * creation or destruction of Poller objects.
0N/A */
0N/A private final static Object globalSync = new Object();
0N/A
0N/A /*
0N/A * The handle for a Poller Object...is used in the JNI C code
0N/A * where all the associated data is kept.
0N/A */
0N/A private int handle;
0N/A
0N/A /**
0N/A * Constructs an instance of a <code>Poller</code> object.
0N/A * Native code uses sysconf(_SC_OPEN_MAX) to determine how
0N/A * many fd/skt objects this Poller object can contain.
0N/A */
0N/A public Poller() throws Exception {
0N/A synchronized(globalSync) {
0N/A this.handle = nativeCreatePoller(-1);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Constructs an instance of a <code>Poller</code> object.
0N/A * @param maxFd the maximum number of FileDescriptors/Sockets
0N/A * this Poller object can contain.
0N/A */
0N/A public Poller(int maxFd) throws Exception {
0N/A synchronized(globalSync) {
0N/A this.handle = nativeCreatePoller(maxFd);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Needed to clean up at the JNI C level when object is GCd.
0N/A */
0N/A protected void finalize() throws Throwable {
0N/A synchronized(globalSync) {
0N/A nativeDestroyPoller(handle);
0N/A super.finalize();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Since we can't guarantee WHEN finalize is called, we may
0N/A * recycle on our own.
0N/A * @param maxFd the maximum number of FileDescriptors/Sockets
0N/A * this Poller object can contain.
0N/A */
0N/A public void reset(int maxFd) throws Exception {
0N/A synchronized(globalSync) {
0N/A nativeDestroyPoller(handle);
0N/A this.handle = nativeCreatePoller(maxFd);
0N/A }
0N/A }
0N/A /**
0N/A * Since we can't guarantee WHEN finalize is called, we may
0N/A * recycle on our own.
0N/A */
0N/A public void reset() throws Exception {
0N/A synchronized(globalSync) {
0N/A nativeDestroyPoller(handle);
0N/A this.handle = nativeCreatePoller(-1);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Add FileDescriptor to the set handled by this Poller object.
0N/A *
0N/A * @param fdObj the FileDescriptor, Socket, or ServerSocket to add.
0N/A * @param event the bitmask of events we are interested in.
0N/A * @return the OS level fd associated with this IO Object
0N/A * (which is what waitMultiple() stores in fds[])
0N/A */
0N/A public synchronized int add(Object fdObj, short event) throws Exception {
0N/A return nativeAddFd(handle,findfd(fdObj), event);
0N/A }
0N/A
0N/A /**
0N/A * Remove FileDescriptor from the set handled by this Poller object.
0N/A *
0N/A * Must be called before the fd/skt is closed.
0N/A * @param fdObj the FileDescriptor, Socket, or ServerSocket to remove.
0N/A * @return true if removal succeeded.
0N/A */
0N/A public synchronized boolean remove(Object fdObj) throws Exception {
0N/A return (nativeRemoveFd(handle,findfd(fdObj)) == 1);
0N/A }
0N/A /**
0N/A * Check if fd or socket is already in the set handled by this Poller object
0N/A *
0N/A * @param fdObj the FileDescriptor or [Server]Socket to check.
0N/A * @return true if fd/skt is in the set for this Poller object.
0N/A */
0N/A public synchronized boolean isMember(Object fdObj) throws Exception {
0N/A return (nativeIsMember(handle,findfd(fdObj)) == 1);
0N/A }
0N/A /**
0N/A * Wait on Multiple IO Objects.
0N/A *
0N/A * @param maxRet the maximum number of fds[] and revents[] to return.
0N/A * @param fds[] (return) an array of ints in which to store fds with
0N/A * available data upon a successful non-timeout return.
0N/A * fds.length must be >= maxRet
0N/A * @param revents[] (return) the actual events available on the
0N/A * same-indexed fds[] (i.e. fds[0] has events revents[0])
0N/A * revents.length must be >= maxRet
0N/A *
0N/A * Note : both above arrays are "dense," i.e. only fds[] with events
0N/A * available are returned.
0N/A *
0N/A * @param timeout the maximum number of milliseconds to wait for
0N/A * events before timing out.
0N/A * @return the number of fds with triggered events.
0N/A *
0N/A * Note : convenience methods exist for skipping the timeout parameter
0N/A * or the maxRet parameter (in the case of no maxRet, fds.length
0N/A * must equal revents.length)
0N/A *
0N/A * obj.waitMultiple(null,null,timeout) can be used for pausing the LWP
0N/A * (much more reliable and scalable than Thread.sleep() or Object.wait())
0N/A */
0N/A public synchronized int waitMultiple(int maxRet, int[] fds,short[] revents,
0N/A long timeout) throws Exception
0N/A {
0N/A if ((revents == null) || (fds == null)) {
0N/A if (maxRet > 0) {
0N/A throw new NullPointerException("fds or revents is null");
0N/A }
0N/A } else if ( (maxRet < 0) ||
0N/A (maxRet > revents.length) || (maxRet > fds.length) ) {
0N/A throw new IllegalArgumentException("maxRet out of range");
0N/A }
0N/A
0N/A int ret = nativeWait(handle, maxRet, fds, revents, timeout);
0N/A if (ret < 0) {
0N/A throw new InterruptedIOException();
0N/A }
0N/A return ret;
0N/A }
0N/A
0N/A /**
0N/A * Wait on Multiple IO Objects (no timeout).
0N/A * A convenience method for waiting indefinitely on IO events
0N/A *
0N/A * @see Poller#waitMultiple
0N/A *
0N/A */
0N/A public int waitMultiple(int maxRet, int[] fds, short[] revents)
0N/A throws Exception
0N/A {
0N/A return waitMultiple(maxRet, fds, revents,-1L); // already synchronized
0N/A }
0N/A
0N/A /**
0N/A * Wait on Multiple IO Objects (no maxRet).
0N/A * A convenience method for waiting on IO events when the fds
0N/A * and revents arrays are the same length and that specifies the
0N/A * maximum number of return events.
0N/A *
0N/A * @see Poller#waitMultiple
0N/A *
0N/A */
0N/A public synchronized int waitMultiple(int[] fds, short[] revents,
0N/A long timeout) throws Exception
0N/A {
0N/A if ((revents == null) && (fds == null)) {
0N/A return nativeWait(handle,0,null,null,timeout);
0N/A } else if ((revents == null) || (fds == null)) {
0N/A throw new NullPointerException("revents or fds is null");
0N/A } else if (fds.length == revents.length) {
0N/A return nativeWait(handle, fds.length, fds, revents, timeout);
0N/A }
0N/A throw new IllegalArgumentException("fds.length != revents.length");
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Wait on Multiple IO Objects (no maxRet/timeout).
0N/A * A convenience method for waiting on IO events when the fds
0N/A * and revents arrays are the same length and that specifies the
0N/A * maximum number of return events, and when waiting indefinitely
0N/A * for IO events to occur.
0N/A *
0N/A * @see Poller#waitMultiple
0N/A *
0N/A */
0N/A public int waitMultiple(int[] fds, short[] revents)
0N/A throws Exception
0N/A {
0N/A if ((revents == null) || (fds == null)) {
0N/A throw new NullPointerException("fds or revents is null");
0N/A } else if (fds.length == revents.length) {
0N/A return waitMultiple(revents.length,fds,revents,-1L); // already sync
0N/A }
0N/A throw new IllegalArgumentException("fds.length != revents.length");
0N/A }
0N/A
0N/A // Utility - get (int) fd from FileDescriptor or [Server]Socket objects.
0N/A
0N/A private int findfd(Object fdObj) throws Exception {
0N/A Class cl;
0N/A Field f;
0N/A Object val, implVal;
0N/A
0N/A if ((fdObj instanceof java.net.Socket) ||
0N/A (fdObj instanceof java.net.ServerSocket)) {
0N/A cl = fdObj.getClass();
0N/A f = cl.getDeclaredField("impl");
0N/A f.setAccessible(true);
0N/A val = f.get(fdObj);
0N/A cl = f.getType();
0N/A f = cl.getDeclaredField("fd");
0N/A f.setAccessible(true);
0N/A implVal = f.get(val);
0N/A cl = f.getType();
0N/A f = cl.getDeclaredField("fd");
0N/A f.setAccessible(true);
0N/A return ((Integer) f.get(implVal)).intValue();
0N/A } else if ( fdObj instanceof java.io.FileDescriptor ) {
0N/A cl = fdObj.getClass();
0N/A f = cl.getDeclaredField("fd");
0N/A f.setAccessible(true);
0N/A return ((Integer) f.get(fdObj)).intValue();
0N/A }
0N/A else {
0N/A throw new IllegalArgumentException("Illegal Object type.");
0N/A }
0N/A }
0N/A
0N/A // Actual NATIVE calls
0N/A
0N/A private static native int nativeInit();
0N/A private native int nativeCreatePoller(int maxFd) throws Exception;
0N/A private native void nativeDestroyPoller(int handle) throws Exception;
0N/A private native int nativeAddFd(int handle, int fd, short events)
0N/A throws Exception;
0N/A private native int nativeRemoveFd(int handle, int fd) throws Exception;
0N/A private native int nativeRemoveIndex(int handle, int index)
0N/A throws Exception;
0N/A private native int nativeIsMember(int handle, int fd) throws Exception;
0N/A private native int nativeWait(int handle, int maxRet, int[] fds,
0N/A short[] events, long timeout)
0N/A throws Exception;
0N/A /**
0N/A * Get number of active CPUs in this machine
0N/A * to determine proper level of concurrency.
0N/A */
0N/A public static native int getNumCPUs();
0N/A
0N/A static {
0N/A System.loadLibrary("poller");
0N/A nativeInit();
0N/A }
0N/A}