blob: 2514a2fffc013ef07a0be89a34e97ceaaeec8793 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.nio.ch;
27
28import sun.misc.*;
29import java.io.IOException;
30import java.util.LinkedList;
31
32
33/**
34 * Manipulates a native array of pollfd structs on Solaris:
35 *
36 * typedef struct pollfd {
37 * int fd;
38 * short events;
39 * short revents;
40 * } pollfd_t;
41 *
42 * @author Mike McCloskey
43 * @since 1.4
44 */
45
46class DevPollArrayWrapper {
47
48 // Event masks
49 static final short POLLIN = 0x0001;
50 static final short POLLPRI = 0x0002;
51 static final short POLLOUT = 0x0004;
52 static final short POLLRDNORM = 0x0040;
53 static final short POLLWRNORM = POLLOUT;
54 static final short POLLRDBAND = 0x0080;
55 static final short POLLWRBAND = 0x0100;
56 static final short POLLNORM = POLLRDNORM;
57 static final short POLLERR = 0x0008;
58 static final short POLLHUP = 0x0010;
59 static final short POLLNVAL = 0x0020;
60 static final short POLLREMOVE = 0x0800;
61 static final short POLLCONN = POLLOUT;
62
63 // Miscellaneous constants
64 static final short SIZE_POLLFD = 8;
65 static final short FD_OFFSET = 0;
66 static final short EVENT_OFFSET = 4;
67 static final short REVENT_OFFSET = 6;
68
69 // Maximum number of open file descriptors
70 static final int OPEN_MAX = fdLimit();
71
72 // Number of pollfd structures to create.
73 // DP_POLL ioctl allows up to OPEN_MAX-1
74 static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);
75
76 // Base address of the native pollArray
77 private long pollArrayAddress;
78
79 // Maximum number of POLL_FD structs to update at once
80 private int MAX_UPDATE_SIZE = 10000;
81
82 DevPollArrayWrapper() {
83 int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
84 pollArray = new AllocatedNativeObject(allocationSize, true);
85 pollArrayAddress = pollArray.address();
86 wfd = init();
87
88 for (int i=0; i<NUM_POLLFDS; i++) {
89 putDescriptor(i, 0);
90 putEventOps(i, 0);
91 putReventOps(i, 0);
92 }
93 }
94
95 // Machinery for remembering fd registration changes
96 // A hashmap could be used but the number of changes pending
97 // is expected to be small
98 private static class Updator {
99 int fd;
100 int mask;
101 Updator(int fd, int mask) {
102 this.fd = fd;
103 this.mask = mask;
104 }
105 }
106 private LinkedList<Updator> updateList = new LinkedList<Updator>();
107
108 // The pollfd array for results from devpoll driver
109 private AllocatedNativeObject pollArray;
110
111 // The fd of the devpoll driver
112 int wfd;
113
114 // The fd of the interrupt line going out
115 int outgoingInterruptFD;
116
117 // The fd of the interrupt line coming in
118 int incomingInterruptFD;
119
120 // The index of the interrupt FD
121 int interruptedIndex;
122
123 // Number of updated pollfd entries
124 int updated;
125
126 void initInterrupt(int fd0, int fd1) {
127 outgoingInterruptFD = fd1;
128 incomingInterruptFD = fd0;
129 register(wfd, fd0, POLLIN);
130 }
131
132 void putEventOps(int i, int event) {
133 int offset = SIZE_POLLFD * i + EVENT_OFFSET;
134 pollArray.putShort(offset, (short)event);
135 }
136
137 void putReventOps(int i, int revent) {
138 int offset = SIZE_POLLFD * i + REVENT_OFFSET;
139 pollArray.putShort(offset, (short)revent);
140 }
141
142 void putDescriptor(int i, int fd) {
143 int offset = SIZE_POLLFD * i + FD_OFFSET;
144 pollArray.putInt(offset, fd);
145 }
146
147 int getEventOps(int i) {
148 int offset = SIZE_POLLFD * i + EVENT_OFFSET;
149 return pollArray.getShort(offset);
150 }
151
152 int getReventOps(int i) {
153 int offset = SIZE_POLLFD * i + REVENT_OFFSET;
154 return pollArray.getShort(offset);
155 }
156
157 int getDescriptor(int i) {
158 int offset = SIZE_POLLFD * i + FD_OFFSET;
159 return pollArray.getInt(offset);
160 }
161
162 void setInterest(int fd, int mask) {
163 synchronized (updateList) {
164 updateList.add(new Updator(fd, mask));
165 }
166 }
167
168 void release(int fd) {
169 synchronized (updateList) {
170 updateList.add(new Updator(fd, POLLREMOVE));
171 }
172 }
173
174 void closeDevPollFD() throws IOException {
175 FileDispatcher.closeIntFD(wfd);
176 pollArray.free();
177 }
178
179 int poll(long timeout) {
180 updateRegistrations();
181 updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
182 for (int i=0; i<updated; i++) {
183 if (getDescriptor(i) == incomingInterruptFD) {
184 interruptedIndex = i;
185 interrupted = true;
186 break;
187 }
188 }
189 return updated;
190 }
191
192 void updateRegistrations() {
193 // take snapshot of the updateList size to see if there are
194 // any registrations to update
195 int updateSize;
196 synchronized (updateList) {
197 updateSize = updateList.size();
198 }
199 if (updateSize > 0) {
200 // Construct a pollfd array with updated masks; we may overallocate
201 // by some amount because if the events are already POLLREMOVE
202 // then the second pollfd of that pair will not be needed. The
203 // number of entries is limited to a reasonable number to avoid
204 // allocating a lot of memory.
205 int maxUpdates = Math.min(updateSize * 2, MAX_UPDATE_SIZE);
206 int allocationSize = maxUpdates * SIZE_POLLFD;
207 AllocatedNativeObject updatePollArray =
208 new AllocatedNativeObject(allocationSize, true);
209
210 try {
211 synchronized (updateList) {
212 while (updateList.size() > 0) {
213 // We have to insert a dummy node in between each
214 // real update to use POLLREMOVE on the fd first because
215 // otherwise the changes are simply OR'd together
216 int index = 0;
217 Updator u = null;
218 while ((u = updateList.poll()) != null) {
219 // First add pollfd struct to clear out this fd
220 putPollFD(updatePollArray, index, u.fd,
221 (short)POLLREMOVE);
222 index++;
223 // Now add pollfd to update this fd, if necessary
224 if (u.mask != POLLREMOVE) {
225 putPollFD(updatePollArray, index, u.fd,
226 (short)u.mask);
227 index++;
228 }
229
230 // Check against the max allocation size; these are
231 // all we will process. Valid index ranges from 0 to
232 // (maxUpdates - 1) and we can use up to 2 per loop
233 if (index > maxUpdates - 2)
234 break;
235 }
236 // Register the changes with /dev/poll
237 registerMultiple(wfd, updatePollArray.address(), index);
238 }
239 }
240 } finally {
241 // Free the native array
242 updatePollArray.free();
243 // BUG: If an exception was thrown then the selector now believes
244 // that the last set of changes was updated but it probably
245 // was not. This should not be a likely occurrence.
246 }
247 }
248 }
249
250 private void putPollFD(AllocatedNativeObject array, int index, int fd,
251 short event)
252 {
253 int structIndex = SIZE_POLLFD * index;
254 array.putInt(structIndex + FD_OFFSET, fd);
255 array.putShort(structIndex + EVENT_OFFSET, event);
256 array.putShort(structIndex + REVENT_OFFSET, (short)0);
257 }
258
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 private native int init();
278 private native void register(int wfd, int fd, int mask);
279 private native void registerMultiple(int wfd, long address, int len);
280 private native int poll0(long pollAddress, int numfds, long timeout,
281 int wfd);
282 private static native void interrupt(int fd);
283 private static native int fdLimit();
284
285}