001: /*
002: * Copyright 2005-2007 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 java.io.IOException;
029: import java.util.LinkedList;
030: import java.util.HashSet;
031:
032: /**
033: * Manipulates a native array of epoll_event structs on Linux:
034: *
035: * typedef union epoll_data {
036: * void *ptr;
037: * int fd;
038: * __uint32_t u32;
039: * __uint64_t u64;
040: * } epoll_data_t;
041: *
042: * struct epoll_event {
043: * __uint32_t events;
044: * epoll_data_t data;
045: * };
046: *
047: * The system call to wait for I/O events is epoll_wait(2). It populates an
048: * array of epoll_event structures that are passed to the call. The data
049: * member of the epoll_event structure contains the same data as was set
050: * when the file descriptor was registered to epoll via epoll_ctl(2). In
051: * this implementation we set data.fd to be the file descriptor that we
052: * register. That way, we have the file descriptor available when we
053: * process the events.
054: *
055: * All file descriptors registered with epoll have the POLLHUP and POLLERR
056: * events enabled even when registered with an event set of 0. To ensure
057: * that epoll_wait doesn't poll an idle file descriptor when the underlying
058: * connection is closed or reset then its registration is deleted from
059: * epoll (it will be re-added again if the event set is changed)
060: */
061:
062: class EPollArrayWrapper {
063: // EPOLL_EVENTS
064: static final int EPOLLIN = 0x001;
065:
066: // opcodes
067: static final int EPOLL_CTL_ADD = 1;
068: static final int EPOLL_CTL_DEL = 2;
069: static final int EPOLL_CTL_MOD = 3;
070:
071: // Miscellaneous constants
072: static final short SIZE_EPOLLEVENT = 12;
073: static final short EVENT_OFFSET = 0;
074: static final short DATA_OFFSET = 4;
075: static final short FD_OFFSET = 4;
076: static final int NUM_EPOLLEVENTS = Math.min(fdLimit(), 8192);
077:
078: // Base address of the native pollArray
079: private final long pollArrayAddress;
080:
081: // Set of "idle" file descriptors
082: private final HashSet<Integer> idleSet;
083:
084: EPollArrayWrapper() {
085: // creates the epoll file descriptor
086: epfd = epollCreate();
087:
088: // the epoll_event array passed to epoll_wait
089: int allocationSize = NUM_EPOLLEVENTS * SIZE_EPOLLEVENT;
090: pollArray = new AllocatedNativeObject(allocationSize, true);
091: pollArrayAddress = pollArray.address();
092:
093: for (int i = 0; i < NUM_EPOLLEVENTS; i++) {
094: putEventOps(i, 0);
095: putData(i, 0L);
096: }
097:
098: // create idle set
099: idleSet = new HashSet<Integer>();
100: }
101:
102: // Used to update file description registrations
103: private static class Updator {
104: int opcode;
105: int fd;
106: int events;
107:
108: Updator(int opcode, int fd, int events) {
109: this .opcode = opcode;
110: this .fd = fd;
111: this .events = events;
112: }
113: }
114:
115: private LinkedList<Updator> updateList = new LinkedList<Updator>();
116:
117: // The epoll_event array for results from epoll_wait
118: private AllocatedNativeObject pollArray;
119:
120: // The fd of the epoll driver
121: final int epfd;
122:
123: // The fd of the interrupt line going out
124: int outgoingInterruptFD;
125:
126: // The fd of the interrupt line coming in
127: int incomingInterruptFD;
128:
129: // The index of the interrupt FD
130: int interruptedIndex;
131:
132: // Number of updated pollfd entries
133: int updated;
134:
135: void initInterrupt(int fd0, int fd1) {
136: outgoingInterruptFD = fd1;
137: incomingInterruptFD = fd0;
138: epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
139: }
140:
141: void putEventOps(int i, int event) {
142: int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
143: pollArray.putInt(offset, event);
144: }
145:
146: void putData(int i, long value) {
147: int offset = SIZE_EPOLLEVENT * i + DATA_OFFSET;
148: pollArray.putLong(offset, value);
149: }
150:
151: void putDescriptor(int i, int fd) {
152: int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
153: pollArray.putInt(offset, fd);
154: }
155:
156: int getEventOps(int i) {
157: int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
158: return pollArray.getInt(offset);
159: }
160:
161: int getDescriptor(int i) {
162: int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
163: return pollArray.getInt(offset);
164: }
165:
166: /**
167: * Update the events for a given file descriptor.
168: */
169: void setInterest(int fd, int mask) {
170: synchronized (updateList) {
171:
172: // if the interest events are 0 then add to idle set, and delete
173: // from epoll if registered (or pending)
174: if (mask == 0) {
175: if (idleSet.add(fd)) {
176: updateList.add(new Updator(EPOLL_CTL_DEL, fd, 0));
177: }
178: return;
179: }
180:
181: // if file descriptor is idle then add to epoll
182: if (!idleSet.isEmpty() && idleSet.remove(fd)) {
183: updateList.add(new Updator(EPOLL_CTL_ADD, fd, mask));
184: return;
185: }
186:
187: // if the previous pending operation is to add this file descriptor
188: // to epoll then update its event set
189: if (updateList.size() > 0) {
190: Updator last = updateList.getLast();
191: if (last.fd == fd && last.opcode == EPOLL_CTL_ADD) {
192: last.events = mask;
193: return;
194: }
195: }
196:
197: // update existing registration
198: updateList.add(new Updator(EPOLL_CTL_MOD, fd, mask));
199: }
200: }
201:
202: /**
203: * Add a new file descriptor to epoll
204: */
205: void add(int fd) {
206: synchronized (updateList) {
207: updateList.add(new Updator(EPOLL_CTL_ADD, fd, 0));
208: }
209: }
210:
211: /**
212: * Remove a file descriptor from epoll
213: */
214: void release(int fd) {
215: synchronized (updateList) {
216: // if file descriptor is idle then remove from idle set, otherwise
217: // delete from epoll
218: if (!idleSet.remove(fd)) {
219: updateList.add(new Updator(EPOLL_CTL_DEL, fd, 0));
220: }
221: }
222: }
223:
224: /**
225: * Close epoll file descriptor and free poll array
226: */
227: void closeEPollFD() throws IOException {
228: FileDispatcher.closeIntFD(epfd);
229: pollArray.free();
230: }
231:
232: int poll(long timeout) throws IOException {
233: updateRegistrations();
234: updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout,
235: epfd);
236: for (int i = 0; i < updated; i++) {
237: if (getDescriptor(i) == incomingInterruptFD) {
238: interruptedIndex = i;
239: interrupted = true;
240: break;
241: }
242: }
243: return updated;
244: }
245:
246: /**
247: * Update the pending registrations.
248: */
249: void updateRegistrations() {
250: synchronized (updateList) {
251: Updator u = null;
252: while ((u = updateList.poll()) != null) {
253: epollCtl(epfd, u.opcode, u.fd, u.events);
254: }
255: }
256: }
257:
258: // interrupt support
259: boolean interrupted = false;
260:
261: public void interrupt() {
262: interrupt(outgoingInterruptFD);
263: }
264:
265: public int interruptedIndex() {
266: return interruptedIndex;
267: }
268:
269: boolean interrupted() {
270: return interrupted;
271: }
272:
273: void clearInterrupted() {
274: interrupted = false;
275: }
276:
277: static {
278: init();
279: }
280:
281: private native int epollCreate();
282:
283: private native void epollCtl(int epfd, int opcode, int fd,
284: int events);
285:
286: private native int epollWait(long pollAddress, int numfds,
287: long timeout, int epfd) throws IOException;
288:
289: private static native int fdLimit();
290:
291: private static native void interrupt(int fd);
292:
293: private static native void init();
294: }
|