001: /*
002: * Copyright (c) 2000 by Matt Welsh and The Regents of the University of
003: * California. All rights reserved.
004: *
005: * Permission to use, copy, modify, and distribute this software and its
006: * documentation for any purpose, without fee, and without written agreement is
007: * hereby granted, provided that the above copyright notice and the following
008: * two paragraphs appear in all copies of this software.
009: *
010: * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
011: * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
012: * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
013: * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
014: *
015: * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
016: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
017: * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
018: * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
019: * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
020: *
021: * Author: Matt Welsh <mdw@cs.berkeley.edu>
022: *
023: */
024:
025: package seda.nbio;
026:
027: import java.util.Vector;
028:
029: /**
030: * SelectSetDevPollImpl is an implementation of SelectSet which
031: * uses the UNIX /dev/poll mechanism.
032: *
033: * @see SelectSet
034: */
035: class SelectSetDevPollImpl extends SelectSetImpl {
036:
037: /**
038: * The maximum number of events to return on each call to doSelect().
039: */
040: private static final int MAX_EVENTS_PER_SELECT = 32768;
041:
042: // The initial size of the internal SelectItem vector.
043: private static final int TO_ALLOCATE = 256;
044:
045: private long native_state; // Internal pointer to native state
046: private Vector vec; // Vector of registered SelectItems
047: private boolean needUpdate; // Does itemarr need to be updated
048: private SelectItem itemarr[]; // Array of registered SelectItems
049: private SelectItem retevents[]; // List of returned events
050: private int retevents_length; // Number of valid entries in retevents
051: private int cachedActiveCount = -1; // Cached count of active selitems
052:
053: // Return true if supported
054: private static native boolean supported();
055:
056: // Initialize native code
057: private native void init(int max_retevents);
058:
059: // Register a SelectItem with native code
060: private native void register(SelectItem sel);
061:
062: // Deregister a SelectItem with native code
063: private native void deregister(SelectItem sel);
064:
065: // Actually do select; return number of events
066: // Places returned events in retevents array
067: private native int doSelect(int timeout, int num_fds_to_poll);
068:
069: // Copy vec into itemarr
070: private void updateitemarr() {
071: if (vec.size() == 0) {
072: itemarr = null;
073: } else {
074: itemarr = new SelectItem[vec.size()];
075: vec.copyInto(itemarr);
076: }
077: }
078:
079: // Returns true if fd already in vec
080: private boolean checkFD(NBIOFileDescriptor fd) {
081: for (int i = 0; i < vec.size(); i++) {
082: SelectItem sel = (SelectItem) vec.elementAt(i);
083: if (fd.equals(sel.getFD()))
084: return true;
085: }
086: return false;
087: }
088:
089: /**
090: * Returns true if /dev/poll is supported on this platform.
091: */
092: static boolean isSupported() {
093: return supported();
094: }
095:
096: /**
097: * Create a SelectSetDevPollImpl with no SelectItems.
098: */
099: SelectSetDevPollImpl() {
100: vec = new Vector(TO_ALLOCATE, TO_ALLOCATE);
101: retevents = new SelectItem[MAX_EVENTS_PER_SELECT];
102: retevents_length = 0;
103: init(MAX_EVENTS_PER_SELECT);
104: }
105:
106: /**
107: * Add a SelectItem to this SelectSetDevPollImpl.
108: */
109: synchronized void add(SelectItem sel) {
110: NBIOFileDescriptor fd = sel.getFD();
111: if (checkFD(fd))
112: throw new IllegalArgumentException(
113: "Cannot register SelectItem with same NBIOFileDescriptor twice");
114: vec.addElement(sel);
115: register(sel);
116: needUpdate = true;
117: cachedActiveCount = -1;
118: }
119:
120: /**
121: * Add all of the SelectItems in the given array to the SelectSetDevPollImpl.
122: */
123: synchronized void add(SelectItem selarr[]) {
124: for (int i = 0; i < selarr.length; i++) {
125: SelectItem sel = selarr[i];
126: NBIOFileDescriptor fd = sel.getFD();
127: if (checkFD(fd))
128: throw new IllegalArgumentException(
129: "Cannot register SelectItem with same NBIOFileDescriptor twice");
130: vec.addElement(sel);
131: register(sel);
132: }
133: needUpdate = true;
134: cachedActiveCount = -1;
135: }
136:
137: /**
138: * Remove a SelectItem from the SelectSetDevPollImpl.
139: */
140: synchronized void remove(SelectItem sel) {
141: vec.removeElement(sel);
142: deregister(sel);
143: needUpdate = true;
144: cachedActiveCount = -1;
145: }
146:
147: /**
148: * Remove all of the SelectItems in the given array from the
149: * SelectSetDevPollImpl.
150: */
151: synchronized void remove(SelectItem selarr[]) {
152: for (int i = 0; i < selarr.length; i++) {
153: vec.removeElement(selarr[i]);
154: deregister(selarr[i]);
155: }
156: needUpdate = true;
157: cachedActiveCount = -1;
158: }
159:
160: /**
161: * Remove the SelectItem at the given index from the SelectSetDevPollImpl.
162: */
163: synchronized void remove(int index) {
164: SelectItem sel = (SelectItem) vec.elementAt(index);
165: vec.removeElementAt(index);
166: deregister(sel);
167: needUpdate = true;
168: cachedActiveCount = -1;
169: }
170:
171: /**
172: * Push updated event masks for all SelectItems in this SelectSet to
173: * the /dev/poll device.
174: */
175: synchronized void update() {
176: for (int i = 0; i < vec.size(); i++) {
177: SelectItem sel = (SelectItem) vec.elementAt(i);
178: register(sel);
179: }
180: cachedActiveCount = -1;
181: }
182:
183: /**
184: * Push updated event masks for all SelectItems in this SelectSet to
185: * native code.
186: */
187: synchronized void update(SelectItem sel) {
188: register(sel);
189: cachedActiveCount = -1;
190: }
191:
192: /**
193: * Return the number of SelectItems in this SelectSetDevPollImpl.
194: */
195: synchronized int size() {
196: return vec.size();
197: }
198:
199: /**
200: * Return the number of active SelectItems in this SelectSetDevPollImpl.
201: */
202: synchronized int numActive() {
203: if (cachedActiveCount != -1)
204: return cachedActiveCount;
205: if (needUpdate) {
206: updateitemarr();
207: needUpdate = false;
208: }
209: int count = 0;
210: if (itemarr != null) {
211: for (int i = 0; i < itemarr.length; i++) {
212: if (itemarr[i].events != 0)
213: count++;
214: }
215: }
216: cachedActiveCount = count;
217: return count;
218: }
219:
220: /**
221: * Return the SelectItem at the given index.
222: */
223: synchronized SelectItem elementAt(int index) {
224: return (SelectItem) vec.elementAt(index);
225: }
226:
227: /**
228: * Wait for events to occur on the SelectItems in this SelectSetDevPollImpl.
229: * Upon return, the 'revents' field of each SelectItem will be
230: * set to the mask of events that occurred. Note that this method
231: * <b>does not</b> set revents to 0 when called; after processing an
232: * event, it is the application's responsibility to clear the revents
233: * field. This is intentional: if the application wishes to delay
234: * the processing of an event, it can leave the revents field as-is so
235: * that subsequent calls to select will continue to indicate that the
236: * event is pending.
237: *
238: * <p>
239: * <b>IMPORTANT NOTE:</b> If timeout is non-zero, this call will
240: * <b>block</b> the thread which invokes it. If you are using
241: * Green Threads, this will block the entire JVM. Unless you have
242: * a single-threaded application, you should only use
243: * SelectSet.select() with native threads.
244: *
245: * @param timeout The maximum number of milliseconds to block waiting
246: * for an event to occur. A timeout of 0 means than select should not block;
247: * a timeout of -1 means that select should block indefinitely.
248: *
249: * @return The number of events received, or 0 if no events occurred.
250: */
251: int select(int timeout) {
252: synchronized (this ) {
253: if (needUpdate) {
254: updateitemarr();
255: needUpdate = false;
256: }
257: }
258: retevents_length = doSelect(timeout, itemarr.length);
259: return retevents_length;
260: }
261:
262: /**
263: * Returns an array of SelectItems for which events matching the given
264: * event mask have occurred (that is, that the revents field matches
265: * the given mask).
266: *
267: * This is a convenience method and is not meant to be optimized; since
268: * it scans the SelectItem array and creates a new reference array, it
269: * imposes higher overhead than the application scanning the SelectItem
270: * array directly, using the size() and elementAt() methods.
271: */
272: synchronized SelectItem[] getEvents(short mask) {
273: if (retevents_length == 0)
274: return null;
275:
276: int count = 0;
277: for (int i = 0; i < retevents_length; i++) {
278: if ((retevents[i].events & mask) != 0)
279: count++;
280: }
281: SelectItem retarr[] = new SelectItem[count];
282: count = 0;
283: for (int i = 0; i < retevents_length; i++) {
284: if ((retevents[i].events & mask) != 0)
285: retarr[count++] = retevents[i];
286: }
287: return retevents;
288: }
289:
290: /**
291: * Returns an array of SelectItems for which some events have occurred
292: * (that is, that the revents field is nonzero).
293: *
294: * This is a convenience method and is not meant to be optimized; since
295: * it scans the SelectItem array and creates a new reference array, it
296: * imposes higher overhead than the application scanning the SelectItem
297: * array directly, using the size() and elementAt() methods.
298: */
299: synchronized SelectItem[] getEvents() {
300: if (retevents_length == 0)
301: return null;
302: SelectItem retarr[] = new SelectItem[retevents_length];
303: System.arraycopy(retevents, 0, retarr, 0, retevents_length);
304: return retarr;
305: }
306:
307: public String toString() {
308: String s = "SelectSetDevPollImpl:\n";
309: for (int i = 0; i < size(); i++) {
310: s = s + "\t" + elementAt(i).toString() + "\n";
311: }
312: return s;
313: }
314:
315: }
|