64 static final short SIZE_POLLFD = 8; |
62 static final short SIZE_POLLFD = 8; |
65 static final short FD_OFFSET = 0; |
63 static final short FD_OFFSET = 0; |
66 static final short EVENT_OFFSET = 4; |
64 static final short EVENT_OFFSET = 4; |
67 static final short REVENT_OFFSET = 6; |
65 static final short REVENT_OFFSET = 6; |
68 |
66 |
|
67 // Special value to indicate that an update should be ignored |
|
68 static final byte CANCELLED = (byte)-1; |
|
69 |
69 // Maximum number of open file descriptors |
70 // Maximum number of open file descriptors |
70 static final int OPEN_MAX = fdLimit(); |
71 static final int OPEN_MAX = fdLimit(); |
71 |
72 |
72 // Number of pollfd structures to create. |
73 // Number of pollfd structures to create. |
73 // DP_POLL ioctl allows up to OPEN_MAX-1 |
74 // DP_POLL ioctl allows up to OPEN_MAX-1 |
74 static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192); |
75 static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192); |
75 |
76 |
76 // Base address of the native pollArray |
77 // Base address of the native pollArray |
77 private long pollArrayAddress; |
78 private final long pollArrayAddress; |
78 |
79 |
79 // Array of pollfd structs used for driver updates |
80 // Array of pollfd structs used for driver updates |
80 private AllocatedNativeObject updatePollArray; |
81 private final AllocatedNativeObject updatePollArray; |
81 |
82 |
82 // Maximum number of POLL_FD structs to update at once |
83 // Maximum number of POLL_FD structs to update at once |
83 private int MAX_UPDATE_SIZE = Math.min(OPEN_MAX, 10000); |
84 private final int MAX_UPDATE_SIZE = Math.min(OPEN_MAX, 512); |
|
85 |
|
86 // Initial size of arrays for fd registration changes |
|
87 private final int INITIAL_PENDING_UPDATE_SIZE = 64; |
84 |
88 |
85 DevPollArrayWrapper() { |
89 DevPollArrayWrapper() { |
86 int allocationSize = NUM_POLLFDS * SIZE_POLLFD; |
90 int allocationSize = NUM_POLLFDS * SIZE_POLLFD; |
87 pollArray = new AllocatedNativeObject(allocationSize, true); |
91 pollArray = new AllocatedNativeObject(allocationSize, true); |
88 pollArrayAddress = pollArray.address(); |
92 pollArrayAddress = pollArray.address(); |
89 allocationSize = MAX_UPDATE_SIZE * SIZE_POLLFD; |
93 allocationSize = MAX_UPDATE_SIZE * SIZE_POLLFD; |
90 updatePollArray = new AllocatedNativeObject(allocationSize, true); |
94 updatePollArray = new AllocatedNativeObject(allocationSize, true); |
91 wfd = init(); |
95 wfd = init(); |
92 } |
96 } |
93 |
97 |
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 |
98 // The pollfd array for results from devpoll driver |
108 private AllocatedNativeObject pollArray; |
99 private AllocatedNativeObject pollArray; |
109 |
100 |
110 // The fd of the devpoll driver |
101 // The fd of the devpoll driver |
111 int wfd; |
102 int wfd; |
119 // The index of the interrupt FD |
110 // The index of the interrupt FD |
120 int interruptedIndex; |
111 int interruptedIndex; |
121 |
112 |
122 // Number of updated pollfd entries |
113 // Number of updated pollfd entries |
123 int updated; |
114 int updated; |
|
115 |
|
116 // object to synchronize fd registration changes |
|
117 private final Object updateLock = new Object(); |
|
118 |
|
119 // number of file descriptors with registration changes pending |
|
120 private int updateCount; |
|
121 |
|
122 // file descriptors with registration changes pending |
|
123 private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE]; |
|
124 |
|
125 // events for file descriptors with registration changes pending, indexed |
|
126 // by file descriptor and stored as bytes for efficiency reasons. |
|
127 private byte[] updateEvents = new byte[OPEN_MAX]; |
|
128 |
124 |
129 |
125 void initInterrupt(int fd0, int fd1) { |
130 void initInterrupt(int fd0, int fd1) { |
126 outgoingInterruptFD = fd1; |
131 outgoingInterruptFD = fd1; |
127 incomingInterruptFD = fd0; |
132 incomingInterruptFD = fd0; |
128 register(wfd, fd0, POLLIN); |
133 register(wfd, fd0, POLLIN); |
147 int offset = SIZE_POLLFD * i + FD_OFFSET; |
152 int offset = SIZE_POLLFD * i + FD_OFFSET; |
148 return pollArray.getInt(offset); |
153 return pollArray.getInt(offset); |
149 } |
154 } |
150 |
155 |
151 void setInterest(int fd, int mask) { |
156 void setInterest(int fd, int mask) { |
152 synchronized (updateList) { |
157 synchronized (updateLock) { |
153 updateList.add(new Updator(fd, mask)); |
158 // record the file descriptor and events, expanding the |
|
159 // respective arrays first if necessary. |
|
160 int oldCapacity = updateDescriptors.length; |
|
161 if (updateCount >= oldCapacity) { |
|
162 int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE; |
|
163 int[] newDescriptors = new int[newCapacity]; |
|
164 System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity); |
|
165 updateDescriptors = newDescriptors; |
|
166 } |
|
167 updateDescriptors[updateCount++] = fd; |
|
168 |
|
169 // events are stored as bytes for efficiency reasons |
|
170 byte b = (byte)mask; |
|
171 assert (b == mask) && (b != CANCELLED); |
|
172 updateEvents[fd] = b; |
154 } |
173 } |
155 } |
174 } |
156 |
175 |
157 void release(int fd) { |
176 void release(int fd) { |
158 synchronized (updateList) { |
177 synchronized (updateLock) { |
159 updateList.add(new Updator(fd, POLLREMOVE)); |
178 // cancel any pending update for this file descriptor |
|
179 updateEvents[fd] = CANCELLED; |
|
180 |
|
181 // remove from /dev/poll |
|
182 register(wfd, fd, POLLREMOVE); |
160 } |
183 } |
161 } |
184 } |
162 |
185 |
163 void closeDevPollFD() throws IOException { |
186 void closeDevPollFD() throws IOException { |
164 FileDispatcherImpl.closeIntFD(wfd); |
187 FileDispatcherImpl.closeIntFD(wfd); |
179 return updated; |
202 return updated; |
180 } |
203 } |
181 |
204 |
182 void updateRegistrations() throws IOException { |
205 void updateRegistrations() throws IOException { |
183 // Populate pollfd array with updated masks |
206 // Populate pollfd array with updated masks |
184 synchronized (updateList) { |
207 synchronized (updateLock) { |
185 while (updateList.size() > 0) { |
208 |
186 // We have to insert a dummy node in between each |
209 int j = 0; |
187 // real update to use POLLREMOVE on the fd first because |
210 int index = 0; |
188 // otherwise the changes are simply OR'd together |
211 while (j < updateCount) { |
189 int index = 0; |
212 int fd = updateDescriptors[j]; |
190 Updator u = null; |
213 short events = updateEvents[fd]; |
191 while ((u = updateList.poll()) != null) { |
214 |
192 // First add pollfd struct to clear out this fd |
215 // skip update if key has been cancelled |
193 putPollFD(updatePollArray, index, u.fd, POLLREMOVE); |
216 if (events != CANCELLED) { |
|
217 // remove from /dev/poll when the interest ops changes to 0 |
|
218 if (events == 0) |
|
219 events = POLLREMOVE; |
|
220 |
|
221 // populate pollfd array with updated event |
|
222 putPollFD(updatePollArray, index, fd, events); |
194 index++; |
223 index++; |
195 // Now add pollfd to update this fd, if necessary |
224 if (index >= MAX_UPDATE_SIZE) { |
196 if (u.mask != POLLREMOVE) { |
225 registerMultiple(wfd, updatePollArray.address(), index); |
197 putPollFD(updatePollArray, index, u.fd, (short)u.mask); |
226 index = 0; |
198 index++; |
|
199 } |
227 } |
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 } |
228 } |
207 // Register the changes with /dev/poll |
229 j++; |
|
230 |
|
231 } |
|
232 |
|
233 // write any remaining updates |
|
234 if (index > 0) |
208 registerMultiple(wfd, updatePollArray.address(), index); |
235 registerMultiple(wfd, updatePollArray.address(), index); |
209 } |
236 |
|
237 updateCount = 0; |
210 } |
238 } |
211 } |
239 } |
212 |
240 |
213 private void putPollFD(AllocatedNativeObject array, int index, int fd, |
241 private void putPollFD(AllocatedNativeObject array, int index, int fd, |
214 short event) |
242 short event) |