001: /*
002: * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.nio.ch;
027:
028: import sun.misc.*;
029: import java.io.IOException;
030: import java.util.LinkedList;
031:
032: /**
033: * Manipulates a native array of pollfd structs on Solaris:
034: *
035: * typedef struct pollfd {
036: * int fd;
037: * short events;
038: * short revents;
039: * } pollfd_t;
040: *
041: * @author Mike McCloskey
042: * @version 1.3, 01/05/06
043: * @since 1.4
044: */
045:
046: class DevPollArrayWrapper {
047:
048: // Event masks
049: static final short POLLIN = 0x0001;
050: static final short POLLPRI = 0x0002;
051: static final short POLLOUT = 0x0004;
052: static final short POLLRDNORM = 0x0040;
053: static final short POLLWRNORM = POLLOUT;
054: static final short POLLRDBAND = 0x0080;
055: static final short POLLWRBAND = 0x0100;
056: static final short POLLNORM = POLLRDNORM;
057: static final short POLLERR = 0x0008;
058: static final short POLLHUP = 0x0010;
059: static final short POLLNVAL = 0x0020;
060: static final short POLLREMOVE = 0x0800;
061: static final short POLLCONN = POLLOUT;
062:
063: // Miscellaneous constants
064: static final short SIZE_POLLFD = 8;
065: static final short FD_OFFSET = 0;
066: static final short EVENT_OFFSET = 4;
067: static final short REVENT_OFFSET = 6;
068:
069: // Maximum number of open file descriptors
070: static final int OPEN_MAX = fdLimit();
071:
072: // Number of pollfd structures to create.
073: // DP_POLL ioctl allows up to OPEN_MAX-1
074: static final int NUM_POLLFDS = Math.min(OPEN_MAX - 1, 8192);
075:
076: // Base address of the native pollArray
077: private long pollArrayAddress;
078:
079: // Maximum number of POLL_FD structs to update at once
080: private int MAX_UPDATE_SIZE = 10000;
081:
082: DevPollArrayWrapper() {
083: int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
084: pollArray = new AllocatedNativeObject(allocationSize, true);
085: pollArrayAddress = pollArray.address();
086: wfd = init();
087:
088: for (int i = 0; i < NUM_POLLFDS; i++) {
089: putDescriptor(i, 0);
090: putEventOps(i, 0);
091: putReventOps(i, 0);
092: }
093: }
094:
095: // Machinery for remembering fd registration changes
096: // A hashmap could be used but the number of changes pending
097: // is expected to be small
098: private static class Updator {
099: int fd;
100: int mask;
101:
102: Updator(int fd, int mask) {
103: this .fd = fd;
104: this .mask = mask;
105: }
106: }
107:
108: private LinkedList<Updator> updateList = new LinkedList<Updator>();
109:
110: // The pollfd array for results from devpoll driver
111: private AllocatedNativeObject pollArray;
112:
113: // The fd of the devpoll driver
114: int wfd;
115:
116: // The fd of the interrupt line going out
117: int outgoingInterruptFD;
118:
119: // The fd of the interrupt line coming in
120: int incomingInterruptFD;
121:
122: // The index of the interrupt FD
123: int interruptedIndex;
124:
125: // Number of updated pollfd entries
126: int updated;
127:
128: void initInterrupt(int fd0, int fd1) {
129: outgoingInterruptFD = fd1;
130: incomingInterruptFD = fd0;
131: register(wfd, fd0, POLLIN);
132: }
133:
134: void putEventOps(int i, int event) {
135: int offset = SIZE_POLLFD * i + EVENT_OFFSET;
136: pollArray.putShort(offset, (short) event);
137: }
138:
139: void putReventOps(int i, int revent) {
140: int offset = SIZE_POLLFD * i + REVENT_OFFSET;
141: pollArray.putShort(offset, (short) revent);
142: }
143:
144: void putDescriptor(int i, int fd) {
145: int offset = SIZE_POLLFD * i + FD_OFFSET;
146: pollArray.putInt(offset, fd);
147: }
148:
149: int getEventOps(int i) {
150: int offset = SIZE_POLLFD * i + EVENT_OFFSET;
151: return pollArray.getShort(offset);
152: }
153:
154: int getReventOps(int i) {
155: int offset = SIZE_POLLFD * i + REVENT_OFFSET;
156: return pollArray.getShort(offset);
157: }
158:
159: int getDescriptor(int i) {
160: int offset = SIZE_POLLFD * i + FD_OFFSET;
161: return pollArray.getInt(offset);
162: }
163:
164: void setInterest(int fd, int mask) {
165: synchronized (updateList) {
166: updateList.add(new Updator(fd, mask));
167: }
168: }
169:
170: void release(int fd) {
171: synchronized (updateList) {
172: updateList.add(new Updator(fd, POLLREMOVE));
173: }
174: }
175:
176: void closeDevPollFD() throws IOException {
177: FileDispatcher.closeIntFD(wfd);
178: pollArray.free();
179: }
180:
181: int poll(long timeout) {
182: updateRegistrations();
183: updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
184: for (int i = 0; i < updated; i++) {
185: if (getDescriptor(i) == incomingInterruptFD) {
186: interruptedIndex = i;
187: interrupted = true;
188: break;
189: }
190: }
191: return updated;
192: }
193:
194: void updateRegistrations() {
195: // take snapshot of the updateList size to see if there are
196: // any registrations to update
197: int updateSize;
198: synchronized (updateList) {
199: updateSize = updateList.size();
200: }
201: if (updateSize > 0) {
202: // Construct a pollfd array with updated masks; we may overallocate
203: // by some amount because if the events are already POLLREMOVE
204: // then the second pollfd of that pair will not be needed. The
205: // number of entries is limited to a reasonable number to avoid
206: // allocating a lot of memory.
207: int maxUpdates = Math.min(updateSize * 2, MAX_UPDATE_SIZE);
208: int allocationSize = maxUpdates * SIZE_POLLFD;
209: AllocatedNativeObject updatePollArray = new AllocatedNativeObject(
210: allocationSize, true);
211:
212: try {
213: synchronized (updateList) {
214: while (updateList.size() > 0) {
215: // We have to insert a dummy node in between each
216: // real update to use POLLREMOVE on the fd first because
217: // otherwise the changes are simply OR'd together
218: int index = 0;
219: Updator u = null;
220: while ((u = updateList.poll()) != null) {
221: // First add pollfd struct to clear out this fd
222: putPollFD(updatePollArray, index, u.fd,
223: (short) POLLREMOVE);
224: index++;
225: // Now add pollfd to update this fd, if necessary
226: if (u.mask != POLLREMOVE) {
227: putPollFD(updatePollArray, index, u.fd,
228: (short) u.mask);
229: index++;
230: }
231:
232: // Check against the max allocation size; these are
233: // all we will process. Valid index ranges from 0 to
234: // (maxUpdates - 1) and we can use up to 2 per loop
235: if (index > maxUpdates - 2)
236: break;
237: }
238: // Register the changes with /dev/poll
239: registerMultiple(wfd,
240: updatePollArray.address(), index);
241: }
242: }
243: } finally {
244: // Free the native array
245: updatePollArray.free();
246: // BUG: If an exception was thrown then the selector now believes
247: // that the last set of changes was updated but it probably
248: // was not. This should not be a likely occurrence.
249: }
250: }
251: }
252:
253: private void putPollFD(AllocatedNativeObject array, int index,
254: int fd, short event) {
255: int structIndex = SIZE_POLLFD * index;
256: array.putInt(structIndex + FD_OFFSET, fd);
257: array.putShort(structIndex + EVENT_OFFSET, event);
258: array.putShort(structIndex + REVENT_OFFSET, (short) 0);
259: }
260:
261: boolean interrupted = false;
262:
263: public void interrupt() {
264: interrupt(outgoingInterruptFD);
265: }
266:
267: public int interruptedIndex() {
268: return interruptedIndex;
269: }
270:
271: boolean interrupted() {
272: return interrupted;
273: }
274:
275: void clearInterrupted() {
276: interrupted = false;
277: }
278:
279: private native int init();
280:
281: private native void register(int wfd, int fd, int mask);
282:
283: private native void registerMultiple(int wfd, long address, int len);
284:
285: private native int poll0(long pollAddress, int numfds,
286: long timeout, int wfd);
287:
288: private static native void interrupt(int fd);
289:
290: private static native int fdLimit();
291:
292: }
|