blob: af5efcf7b017c847f92479272fc7473b98dbba16 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999 Sun Microsystems, Inc. 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 Sun Microsystems 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
32import java.lang.reflect.*;
33import java.io.*;
34import java.net.*;
35
36/**
37 * This class is provided for access to the underlying poll(2)
38 * or /dev/poll kernel interfaces. This may be needed for
39 * multiplexing IO when an application cannot afford to have
40 * a thread block on each outstanding IO request.
41 *
42 * It currently supports the same basic functionality as the
43 * C poll(2) API, although for efficiency we needed to avoid
44 * passing the entire pollfd array for every call. See man
45 * pages for poll(2) for info on C API and event types.
46 *
47 *
48 * @author Bruce Chapman
49 * @see java.io.FileDescriptor
50 * @see java.net.Socket
51 * @see attached README.txt
52 * @since JDK1.2
53 */
54
55public class Poller {
56 /**
57 * Solaris POLL event types.
58 */
59 public final static short POLLERR = 0x08;
60 public final static short POLLHUP = 0x10;
61 public final static short POLLNVAL = 0x20;
62 public final static short POLLIN = 1;
63 public final static short POLLPRI = 2;
64 public final static short POLLOUT = 4;
65 public final static short POLLRDNORM = 0x40;
66 public final static short POLLWRNORM = POLLOUT ;
67 public final static short POLLRDBAND = 0x80;
68 public final static short POLLWRBAND = 0x100;
69 public final static short POLLNORM = POLLRDNORM;
70
71 /*
72 * This global synchronization object must be used for all
73 * creation or destruction of Poller objects.
74 */
75 private final static Object globalSync = new Object();
76
77 /*
78 * The handle for a Poller Object...is used in the JNI C code
79 * where all the associated data is kept.
80 */
81 private int handle;
82
83 /**
84 * Constructs an instance of a <code>Poller</code> object.
85 * Native code uses sysconf(_SC_OPEN_MAX) to determine how
86 * many fd/skt objects this Poller object can contain.
87 */
88 public Poller() throws Exception {
89 synchronized(globalSync) {
90 this.handle = nativeCreatePoller(-1);
91 }
92 }
93
94 /**
95 * Constructs an instance of a <code>Poller</code> object.
96 * @param maxFd the maximum number of FileDescriptors/Sockets
97 * this Poller object can contain.
98 */
99 public Poller(int maxFd) throws Exception {
100 synchronized(globalSync) {
101 this.handle = nativeCreatePoller(maxFd);
102 }
103 }
104
105 /**
106 * Needed to clean up at the JNI C level when object is GCd.
107 */
108 protected void finalize() throws Throwable {
109 synchronized(globalSync) {
110 nativeDestroyPoller(handle);
111 super.finalize();
112 }
113 }
114
115 /**
116 * Since we can't guarantee WHEN finalize is called, we may
117 * recycle on our own.
118 * @param maxFd the maximum number of FileDescriptors/Sockets
119 * this Poller object can contain.
120 */
121 public void reset(int maxFd) throws Exception {
122 synchronized(globalSync) {
123 nativeDestroyPoller(handle);
124 this.handle = nativeCreatePoller(maxFd);
125 }
126 }
127 /**
128 * Since we can't guarantee WHEN finalize is called, we may
129 * recycle on our own.
130 */
131 public void reset() throws Exception {
132 synchronized(globalSync) {
133 nativeDestroyPoller(handle);
134 this.handle = nativeCreatePoller(-1);
135 }
136 }
137
138 /**
139 * Add FileDescriptor to the set handled by this Poller object.
140 *
141 * @param fdObj the FileDescriptor, Socket, or ServerSocket to add.
142 * @param event the bitmask of events we are interested in.
143 * @return the OS level fd associated with this IO Object
144 * (which is what waitMultiple() stores in fds[])
145 */
146 public synchronized int add(Object fdObj, short event) throws Exception {
147 return nativeAddFd(handle,findfd(fdObj), event);
148 }
149
150 /**
151 * Remove FileDescriptor from the set handled by this Poller object.
152 *
153 * Must be called before the fd/skt is closed.
154 * @param fdObj the FileDescriptor, Socket, or ServerSocket to remove.
155 * @return true if removal succeeded.
156 */
157 public synchronized boolean remove(Object fdObj) throws Exception {
158 return (nativeRemoveFd(handle,findfd(fdObj)) == 1);
159 }
160 /**
161 * Check if fd or socket is already in the set handled by this Poller object
162 *
163 * @param fdObj the FileDescriptor or [Server]Socket to check.
164 * @return true if fd/skt is in the set for this Poller object.
165 */
166 public synchronized boolean isMember(Object fdObj) throws Exception {
167 return (nativeIsMember(handle,findfd(fdObj)) == 1);
168 }
169 /**
170 * Wait on Multiple IO Objects.
171 *
172 * @param maxRet the maximum number of fds[] and revents[] to return.
173 * @param fds[] (return) an array of ints in which to store fds with
174 * available data upon a successful non-timeout return.
175 * fds.length must be >= maxRet
176 * @param revents[] (return) the actual events available on the
177 * same-indexed fds[] (i.e. fds[0] has events revents[0])
178 * revents.length must be >= maxRet
179 *
180 * Note : both above arrays are "dense," i.e. only fds[] with events
181 * available are returned.
182 *
183 * @param timeout the maximum number of milliseconds to wait for
184 * events before timing out.
185 * @return the number of fds with triggered events.
186 *
187 * Note : convenience methods exist for skipping the timeout parameter
188 * or the maxRet parameter (in the case of no maxRet, fds.length
189 * must equal revents.length)
190 *
191 * obj.waitMultiple(null,null,timeout) can be used for pausing the LWP
192 * (much more reliable and scalable than Thread.sleep() or Object.wait())
193 */
194 public synchronized int waitMultiple(int maxRet, int[] fds,short[] revents,
195 long timeout) throws Exception
196 {
197 if ((revents == null) || (fds == null)) {
198 if (maxRet > 0) {
199 throw new NullPointerException("fds or revents is null");
200 }
201 } else if ( (maxRet < 0) ||
202 (maxRet > revents.length) || (maxRet > fds.length) ) {
203 throw new IllegalArgumentException("maxRet out of range");
204 }
205
206 int ret = nativeWait(handle, maxRet, fds, revents, timeout);
207 if (ret < 0) {
208 throw new InterruptedIOException();
209 }
210 return ret;
211 }
212
213 /**
214 * Wait on Multiple IO Objects (no timeout).
215 * A convenience method for waiting indefinitely on IO events
216 *
217 * @see Poller#waitMultiple
218 *
219 */
220 public int waitMultiple(int maxRet, int[] fds, short[] revents)
221 throws Exception
222 {
223 return waitMultiple(maxRet, fds, revents,-1L); // already synchronized
224 }
225
226 /**
227 * Wait on Multiple IO Objects (no maxRet).
228 * A convenience method for waiting on IO events when the fds
229 * and revents arrays are the same length and that specifies the
230 * maximum number of return events.
231 *
232 * @see Poller#waitMultiple
233 *
234 */
235 public synchronized int waitMultiple(int[] fds, short[] revents,
236 long timeout) throws Exception
237 {
238 if ((revents == null) && (fds == null)) {
239 return nativeWait(handle,0,null,null,timeout);
240 } else if ((revents == null) || (fds == null)) {
241 throw new NullPointerException("revents or fds is null");
242 } else if (fds.length == revents.length) {
243 return nativeWait(handle, fds.length, fds, revents, timeout);
244 }
245 throw new IllegalArgumentException("fds.length != revents.length");
246 }
247
248
249 /**
250 * Wait on Multiple IO Objects (no maxRet/timeout).
251 * A convenience method for waiting on IO events when the fds
252 * and revents arrays are the same length and that specifies the
253 * maximum number of return events, and when waiting indefinitely
254 * for IO events to occur.
255 *
256 * @see Poller#waitMultiple
257 *
258 */
259 public int waitMultiple(int[] fds, short[] revents)
260 throws Exception
261 {
262 if ((revents == null) || (fds == null)) {
263 throw new NullPointerException("fds or revents is null");
264 } else if (fds.length == revents.length) {
265 return waitMultiple(revents.length,fds,revents,-1L); // already sync
266 }
267 throw new IllegalArgumentException("fds.length != revents.length");
268 }
269
270 // Utility - get (int) fd from FileDescriptor or [Server]Socket objects.
271
272 private int findfd(Object fdObj) throws Exception {
273 Class cl;
274 Field f;
275 Object val, implVal;
276
277 if ((fdObj instanceof java.net.Socket) ||
278 (fdObj instanceof java.net.ServerSocket)) {
279 cl = fdObj.getClass();
280 f = cl.getDeclaredField("impl");
281 f.setAccessible(true);
282 val = f.get(fdObj);
283 cl = f.getType();
284 f = cl.getDeclaredField("fd");
285 f.setAccessible(true);
286 implVal = f.get(val);
287 cl = f.getType();
288 f = cl.getDeclaredField("fd");
289 f.setAccessible(true);
290 return ((Integer) f.get(implVal)).intValue();
291 } else if ( fdObj instanceof java.io.FileDescriptor ) {
292 cl = fdObj.getClass();
293 f = cl.getDeclaredField("fd");
294 f.setAccessible(true);
295 return ((Integer) f.get(fdObj)).intValue();
296 }
297 else {
298 throw new IllegalArgumentException("Illegal Object type.");
299 }
300 }
301
302 // Actual NATIVE calls
303
304 private static native int nativeInit();
305 private native int nativeCreatePoller(int maxFd) throws Exception;
306 private native void nativeDestroyPoller(int handle) throws Exception;
307 private native int nativeAddFd(int handle, int fd, short events)
308 throws Exception;
309 private native int nativeRemoveFd(int handle, int fd) throws Exception;
310 private native int nativeRemoveIndex(int handle, int index)
311 throws Exception;
312 private native int nativeIsMember(int handle, int fd) throws Exception;
313 private native int nativeWait(int handle, int maxRet, int[] fds,
314 short[] events, long timeout)
315 throws Exception;
316 /**
317 * Get number of active CPUs in this machine
318 * to determine proper level of concurrency.
319 */
320 public static native int getNumCPUs();
321
322 static {
323 System.loadLibrary("poller");
324 nativeInit();
325 }
326}