1 /*
2 * Copyright (c) 2001, 2009, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * 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 // Array of pollfd structs used for driver updates
80 private AllocatedNativeObject updatePollArray;
81
82 // Maximum number of POLL_FD structs to update at once
83 private int MAX_UPDATE_SIZE = Math.min(OPEN_MAX, 10000);
84
85 DevPollArrayWrapper() {
86 int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
87 pollArray = new AllocatedNativeObject(allocationSize, true);
88 pollArrayAddress = pollArray.address();
89 allocationSize = MAX_UPDATE_SIZE * SIZE_POLLFD;
90 updatePollArray = new AllocatedNativeObject(allocationSize, true);
91 wfd = init();
92 }
93
94 // Machinery for remembering fd registration changes
95 // A hashmap could be used but the number of changes pending
96 // is expected to be small
97 private static class Updator {
98 int fd;
99 int mask;
100 Updator(int fd, int mask) {
101 this.fd = fd;
102 this.mask = mask;
103 }
104 }
105 private LinkedList<Updator> updateList = new LinkedList<Updator>();
106
107 // The pollfd array for results from devpoll driver
108 private AllocatedNativeObject pollArray;
109
110 // The fd of the devpoll driver
111 int wfd;
112
113 // The fd of the interrupt line going out
114 int outgoingInterruptFD;
115
116 // The fd of the interrupt line coming in
117 int incomingInterruptFD;
118
119 // The index of the interrupt FD
120 int interruptedIndex;
121
122 // Number of updated pollfd entries
123 int updated;
124
125 void initInterrupt(int fd0, int fd1) {
126 outgoingInterruptFD = fd1;
127 incomingInterruptFD = fd0;
128 register(wfd, fd0, POLLIN);
129 }
130
131 void putReventOps(int i, int revent) {
132 int offset = SIZE_POLLFD * i + REVENT_OFFSET;
133 pollArray.putShort(offset, (short)revent);
134 }
135
136 int getEventOps(int i) {
137 int offset = SIZE_POLLFD * i + EVENT_OFFSET;
138 return pollArray.getShort(offset);
139 }
140
141 int getReventOps(int i) {
142 int offset = SIZE_POLLFD * i + REVENT_OFFSET;
143 return pollArray.getShort(offset);
144 }
145
146 int getDescriptor(int i) {
147 int offset = SIZE_POLLFD * i + FD_OFFSET;
148 return pollArray.getInt(offset);
149 }
150
151 void setInterest(int fd, int mask) {
152 synchronized (updateList) {
153 updateList.add(new Updator(fd, mask));
154 }
155 }
156
157 void release(int fd) {
158 synchronized (updateList) {
159 updateList.add(new Updator(fd, POLLREMOVE));
160 }
161 }
162
163 void closeDevPollFD() throws IOException {
164 FileDispatcherImpl.closeIntFD(wfd);
165 pollArray.free();
166 updatePollArray.free();
167 }
168
169 int poll(long timeout) throws IOException {
170 updateRegistrations();
171 updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
172 for (int i=0; i<updated; i++) {
173 if (getDescriptor(i) == incomingInterruptFD) {
174 interruptedIndex = i;
175 interrupted = true;
176 break;
177 }
178 }
179 return updated;
180 }
181
182 void updateRegistrations() throws IOException {
183 // Populate pollfd array with updated masks
184 synchronized (updateList) {
185 while (updateList.size() > 0) {
186 // We have to insert a dummy node in between each
187 // real update to use POLLREMOVE on the fd first because
188 // otherwise the changes are simply OR'd together
189 int index = 0;
190 Updator u = null;
191 while ((u = updateList.poll()) != null) {
192 // First add pollfd struct to clear out this fd
193 putPollFD(updatePollArray, index, u.fd, POLLREMOVE);
194 index++;
195 // Now add pollfd to update this fd, if necessary
196 if (u.mask != POLLREMOVE) {
197 putPollFD(updatePollArray, index, u.fd, (short)u.mask);
198 index++;
199 }
200
201 // Check against the max update size; these are
202 // all we will process. Valid index ranges from 0 to
203 // (MAX_UPDATE_SIZE - 1) and we can use up to 2 per loop
204 if (index > MAX_UPDATE_SIZE - 2)
205 break;
206 }
207 // Register the changes with /dev/poll
208 registerMultiple(wfd, updatePollArray.address(), index);
209 }
210 }
211 }
212
213 private void putPollFD(AllocatedNativeObject array, int index, int fd,
214 short event)
215 {
216 int structIndex = SIZE_POLLFD * index;
217 array.putInt(structIndex + FD_OFFSET, fd);
218 array.putShort(structIndex + EVENT_OFFSET, event);
219 array.putShort(structIndex + REVENT_OFFSET, (short)0);
220 }
221
222 boolean interrupted = false;
223
224 public void interrupt() {
225 interrupt(outgoingInterruptFD);
226 }
227
228 public int interruptedIndex() {
229 return interruptedIndex;
230 }
231
232 boolean interrupted() {
233 return interrupted;
234 }
235
236 void clearInterrupted() {
237 interrupted = false;
238 }
239
240 private native int init();
241 private native void register(int wfd, int fd, int mask);
242 private native void registerMultiple(int wfd, long address, int len)
243 throws IOException;
244 private native int poll0(long pollAddress, int numfds, long timeout,
245 int wfd);
246 private static native void interrupt(int fd);
247 private static native int fdLimit();
248
249 }