2
|
1 |
/*
|
715
|
2 |
* Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
|
2
|
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 |
|
|
26 |
package sun.nio.ch;
|
|
27 |
|
|
28 |
import sun.misc.*;
|
|
29 |
import java.io.IOException;
|
|
30 |
import 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 |
|
|
46 |
class 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
|
51
|
220 |
putPollFD(updatePollArray, index, u.fd, POLLREMOVE);
|
2
|
221 |
index++;
|
|
222 |
// Now add pollfd to update this fd, if necessary
|
|
223 |
if (u.mask != POLLREMOVE) {
|
|
224 |
putPollFD(updatePollArray, index, u.fd,
|
|
225 |
(short)u.mask);
|
|
226 |
index++;
|
|
227 |
}
|
|
228 |
|
|
229 |
// Check against the max allocation size; these are
|
|
230 |
// all we will process. Valid index ranges from 0 to
|
|
231 |
// (maxUpdates - 1) and we can use up to 2 per loop
|
|
232 |
if (index > maxUpdates - 2)
|
|
233 |
break;
|
|
234 |
}
|
|
235 |
// Register the changes with /dev/poll
|
|
236 |
registerMultiple(wfd, updatePollArray.address(), index);
|
|
237 |
}
|
|
238 |
}
|
|
239 |
} finally {
|
|
240 |
// Free the native array
|
|
241 |
updatePollArray.free();
|
|
242 |
// BUG: If an exception was thrown then the selector now believes
|
|
243 |
// that the last set of changes was updated but it probably
|
|
244 |
// was not. This should not be a likely occurrence.
|
|
245 |
}
|
|
246 |
}
|
|
247 |
}
|
|
248 |
|
|
249 |
private void putPollFD(AllocatedNativeObject array, int index, int fd,
|
|
250 |
short event)
|
|
251 |
{
|
|
252 |
int structIndex = SIZE_POLLFD * index;
|
|
253 |
array.putInt(structIndex + FD_OFFSET, fd);
|
|
254 |
array.putShort(structIndex + EVENT_OFFSET, event);
|
|
255 |
array.putShort(structIndex + REVENT_OFFSET, (short)0);
|
|
256 |
}
|
|
257 |
|
|
258 |
boolean interrupted = false;
|
|
259 |
|
|
260 |
public void interrupt() {
|
|
261 |
interrupt(outgoingInterruptFD);
|
|
262 |
}
|
|
263 |
|
|
264 |
public int interruptedIndex() {
|
|
265 |
return interruptedIndex;
|
|
266 |
}
|
|
267 |
|
|
268 |
boolean interrupted() {
|
|
269 |
return interrupted;
|
|
270 |
}
|
|
271 |
|
|
272 |
void clearInterrupted() {
|
|
273 |
interrupted = false;
|
|
274 |
}
|
|
275 |
|
|
276 |
private native int init();
|
|
277 |
private native void register(int wfd, int fd, int mask);
|
|
278 |
private native void registerMultiple(int wfd, long address, int len);
|
|
279 |
private native int poll0(long pollAddress, int numfds, long timeout,
|
|
280 |
int wfd);
|
|
281 |
private static native void interrupt(int fd);
|
|
282 |
private static native int fdLimit();
|
|
283 |
|
|
284 |
}
|