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: * A SelectSet represents a set of SelectItems which you wish to
031: * poll or wait for events to occur on. The interface is very much
032: * like the poll(2) system call in SVR4.
033: *
034: * To poll for events across many sockets or file descriptors, create
035: * a SelectSet and initialize it with one or more SelectItems. The
036: * 'events' field of each SelectItem should be set to the mask of event
037: * types you wish to receive. The event types are specified by the constants
038: * in the Selectable class.
039: * <p>
040: * Calling the <tt>select</tt> method (with an optional timeout) checks
041: * each of the file descriptors in the SelectSet for events, and sets the
042: * 'revents' field of each SelectItem accordingly. The <tt>getEvents</tt>
043: * method is provided for convenience; it returns an array of SelectItems
044: * for which some event occurred.
045: *
046: * <p>
047: * Multiple implementations of SelectSet may be available on a given
048: * system. The particular implementation used is determined on the
049: * features of the underlying OS, but the default choice can be overridden
050: * by setting the <tt>nbio.SelectSetImpl</tt> runtime property. See
051: * the subclasses of SelectSetImpl for details.
052: *
053: * @author Matt Welsh (mdw@cs.berkeley.edu)
054: * @see Selectable
055: * @see SelectSetImpl, SelectSetPollImpl, SelectSetDevPollImpl
056: */
057: public class SelectSet {
058:
059: private static final boolean DEBUG = false;
060:
061: private SelectSetImpl impl;
062: private static final int POLL_IMPL = 0;
063: private static final int DEVPOLL_IMPL = 1;
064: private static int IMPL_TO_USE;
065:
066: static {
067: NonblockingSocket.loadNativeLibrary();
068:
069: String implProp = System.getProperty("nbio.SelectSetImpl");
070: if (implProp != null) {
071: if (implProp.equals("devpoll")
072: && SelectSetDevPollImpl.isSupported()) {
073: System.err.println("SelectSet: Using /dev/poll");
074: IMPL_TO_USE = DEVPOLL_IMPL;
075: } else if (implProp.equals("poll")
076: && SelectSetPollImpl.isSupported()) {
077: System.err.println("SelectSet: Using poll(2)");
078: IMPL_TO_USE = POLL_IMPL;
079: } else {
080: throw new UnsatisfiedLinkError(
081: "No SelectSetImpl supported on this platform!");
082: }
083: } else {
084: if (SelectSetDevPollImpl.isSupported()) {
085: System.err.println("SelectSet: Using /dev/poll");
086: IMPL_TO_USE = DEVPOLL_IMPL;
087: } else if (SelectSetPollImpl.isSupported()) {
088: System.err.println("SelectSet: Using poll(2)");
089: IMPL_TO_USE = POLL_IMPL;
090: } else {
091: throw new UnsatisfiedLinkError(
092: "No SelectSetImpl supported on this platform!");
093: }
094: }
095: }
096:
097: /**
098: * Create a SelectSet with no SelectItems.
099: */
100: public SelectSet() {
101: switch (IMPL_TO_USE) {
102: case POLL_IMPL:
103: impl = new SelectSetPollImpl();
104: break;
105: case DEVPOLL_IMPL:
106: impl = new SelectSetDevPollImpl();
107: break;
108: default:
109: throw new LinkageError(
110: "Error: SelectSet has bad value for IMPL_TO_USE; this is a bug - please contact <mdw@cs.berkeley.edu>");
111: }
112: }
113:
114: /**
115: * Add a SelectItem to this SelectSet.
116: */
117: public void add(SelectItem sel) {
118: impl.add(sel);
119: }
120:
121: /**
122: * Add all of the SelectItems in the given array to the SelectSet.
123: */
124: public void add(SelectItem selarr[]) {
125: impl.add(selarr);
126: }
127:
128: /**
129: * Remove a SelectItem from the SelectSet.
130: */
131: public void remove(SelectItem sel) {
132: impl.remove(sel);
133: }
134:
135: /**
136: * Remove all of the SelectItems in the given array from the SelectSet.
137: */
138: public void remove(SelectItem selarr[]) {
139: impl.remove(selarr);
140: }
141:
142: /**
143: * Remove the SelectItem at the given index from the SelectSet.
144: */
145: public void remove(int index) {
146: impl.remove(index);
147: }
148:
149: /**
150: * Update any changed 'events' fields in SelectItems registered with
151: * this SelectSet. This method should be called if a SelectItem
152: * 'events' field is modified after adding it to this SelectSet.
153: */
154: public void update() {
155: impl.update();
156: }
157:
158: /**
159: * Update any changed 'events' fields in the given SelectItem.
160: * This method should be called if a SelectItem 'events' field is
161: * modified after adding it to this SelectSet.
162: */
163: public void update(SelectItem sel) {
164: impl.update(sel);
165: }
166:
167: /**
168: * Return the number of SelectItems in this SelectSet.
169: */
170: public int size() {
171: return impl.size();
172: }
173:
174: /**
175: * Return the number of active SelectItems in this SelectSet.
176: * An active SelectItem is defined as one with a non-zero
177: * events request mask.
178: */
179: public int numActive() {
180: return impl.numActive();
181: }
182:
183: /**
184: * Return the SelectItem at the given index.
185: */
186: public SelectItem elementAt(int index) {
187: return impl.elementAt(index);
188: }
189:
190: /**
191: * Wait for events to occur on the SelectItems in this SelectSet.
192: * Upon return, the 'revents' field of each SelectItem will be
193: * set to the mask of events that occurred. Note that this method
194: * <b>does not</b> set revents to 0 when called; after processing an
195: * event, it is the application's responsibility to clear the revents
196: * field. This is intentional: if the application wishes to delay
197: * the processing of an event, it can leave the revents field as-is so
198: * that subsequent calls to select will continue to indicate that the
199: * event is pending.
200: *
201: * <p>
202: * <b>IMPORTANT NOTE:</b> If timeout is non-zero, this call will
203: * <b>block</b> the thread which invokes it. If you are using
204: * Green Threads, this will block the entire JVM. Unless you have
205: * a single-threaded application, you should only use
206: * SelectSet.select() with native threads.
207: *
208: * @param timeout The maximum number of milliseconds to block waiting
209: * for an event to occur. A timeout of 0 means than select should not block;
210: * a timeout of -1 means that select should block indefinitely.
211: *
212: * @return The number of events received, or 0 if no events occurred.
213: */
214: public int select(int timeout) {
215: return impl.select(timeout);
216: }
217:
218: /**
219: * Returns an array of SelectItems for which events matching the given
220: * event mask have occurred (that is, that the revents field matches
221: * the given mask).
222: *
223: * This is a convenience method and is not meant to be optimized; since
224: * it scans the SelectItem array and creates a new reference array, it
225: * imposes higher overhead than the application scanning the SelectItem
226: * array directly, using the size() and elementAt() methods.
227: */
228: public SelectItem[] getEvents(short mask) {
229: return impl.getEvents(mask);
230: }
231:
232: /**
233: * Returns an array of SelectItems for which some events have occurred
234: * (that is, that the revents field is nonzero).
235: *
236: * This is a convenience method and is not meant to be optimized; since
237: * it scans the SelectItem array and creates a new reference array, it
238: * imposes higher overhead than the application scanning the SelectItem
239: * array directly, using the size() and elementAt() methods.
240: */
241: public SelectItem[] getEvents() {
242: return impl.getEvents();
243: }
244:
245: public String toString() {
246: String s = "SelectSet (impl " + impl.toString() + "):\n";
247: for (int i = 0; i < size(); i++) {
248: s = s + "\t" + elementAt(i).toString() + "\n";
249: }
250: return s;
251: }
252:
253: }
|