|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * This file implements _PR_MD_PR_POLL for OS/2. |
|
8 */ |
|
9 |
|
10 #include <sys/time.h> /* For timeval. */ |
|
11 |
|
12 #include "primpl.h" |
|
13 |
|
14 #ifndef BSD_SELECT |
|
15 /* Utility functions called when using OS/2 select */ |
|
16 |
|
17 PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count ) |
|
18 { |
|
19 int i; |
|
20 PRBool isSet = PR_FALSE; |
|
21 |
|
22 for( i = start; i < start+count; i++ ) |
|
23 { |
|
24 if( socks[i] == osfd ) |
|
25 isSet = PR_TRUE; |
|
26 } |
|
27 |
|
28 return isSet; |
|
29 } |
|
30 #endif |
|
31 |
|
32 PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) |
|
33 { |
|
34 #ifdef BSD_SELECT |
|
35 fd_set rd, wt, ex; |
|
36 #else |
|
37 int rd, wt, ex; |
|
38 int* socks; |
|
39 unsigned long msecs; |
|
40 int i, j; |
|
41 #endif |
|
42 PRFileDesc *bottom; |
|
43 PRPollDesc *pd, *epd; |
|
44 PRInt32 maxfd = -1, ready, err; |
|
45 PRIntervalTime remaining, elapsed, start; |
|
46 |
|
47 #ifdef BSD_SELECT |
|
48 struct timeval tv, *tvp = NULL; |
|
49 |
|
50 FD_ZERO(&rd); |
|
51 FD_ZERO(&wt); |
|
52 FD_ZERO(&ex); |
|
53 #else |
|
54 rd = 0; |
|
55 wt = 0; |
|
56 ex = 0; |
|
57 socks = (int) PR_MALLOC( npds * 3 * sizeof(int) ); |
|
58 |
|
59 if (!socks) |
|
60 { |
|
61 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
|
62 return -1; |
|
63 } |
|
64 #endif |
|
65 |
|
66 ready = 0; |
|
67 for (pd = pds, epd = pd + npds; pd < epd; pd++) |
|
68 { |
|
69 PRInt16 in_flags_read = 0, in_flags_write = 0; |
|
70 PRInt16 out_flags_read = 0, out_flags_write = 0; |
|
71 |
|
72 if ((NULL != pd->fd) && (0 != pd->in_flags)) |
|
73 { |
|
74 if (pd->in_flags & PR_POLL_READ) |
|
75 { |
|
76 in_flags_read = (pd->fd->methods->poll)( |
|
77 pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); |
|
78 } |
|
79 if (pd->in_flags & PR_POLL_WRITE) |
|
80 { |
|
81 in_flags_write = (pd->fd->methods->poll)( |
|
82 pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); |
|
83 } |
|
84 if ((0 != (in_flags_read & out_flags_read)) || |
|
85 (0 != (in_flags_write & out_flags_write))) |
|
86 { |
|
87 /* this one's ready right now */ |
|
88 if (0 == ready) |
|
89 { |
|
90 /* |
|
91 * We will have to return without calling the |
|
92 * system poll/select function. So zero the |
|
93 * out_flags fields of all the poll descriptors |
|
94 * before this one. |
|
95 */ |
|
96 PRPollDesc *prev; |
|
97 for (prev = pds; prev < pd; prev++) |
|
98 { |
|
99 prev->out_flags = 0; |
|
100 } |
|
101 } |
|
102 ready += 1; |
|
103 pd->out_flags = out_flags_read | out_flags_write; |
|
104 } |
|
105 else |
|
106 { |
|
107 pd->out_flags = 0; /* pre-condition */ |
|
108 |
|
109 /* make sure this is an NSPR supported stack */ |
|
110 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
|
111 PR_ASSERT(NULL != bottom); /* what to do about that? */ |
|
112 if ((NULL != bottom) && |
|
113 (_PR_FILEDESC_OPEN == bottom->secret->state)) |
|
114 { |
|
115 if (0 == ready) |
|
116 { |
|
117 PRInt32 osfd = bottom->secret->md.osfd; |
|
118 if (osfd > maxfd) |
|
119 maxfd = osfd; |
|
120 if (in_flags_read & PR_POLL_READ) |
|
121 { |
|
122 pd->out_flags |= _PR_POLL_READ_SYS_READ; |
|
123 #ifdef BSD_SELECT |
|
124 FD_SET(osfd, &rd); |
|
125 #else |
|
126 socks[rd] = osfd; |
|
127 rd++; |
|
128 #endif |
|
129 } |
|
130 if (in_flags_read & PR_POLL_WRITE) |
|
131 { |
|
132 pd->out_flags |= _PR_POLL_READ_SYS_WRITE; |
|
133 #ifdef BSD_SELECT |
|
134 FD_SET(osfd, &wt); |
|
135 #else |
|
136 socks[npds+wt] = osfd; |
|
137 wt++; |
|
138 #endif |
|
139 } |
|
140 if (in_flags_write & PR_POLL_READ) |
|
141 { |
|
142 pd->out_flags |= _PR_POLL_WRITE_SYS_READ; |
|
143 #ifdef BSD_SELECT |
|
144 FD_SET(osfd, &rd); |
|
145 #else |
|
146 socks[rd] = osfd; |
|
147 rd++; |
|
148 #endif |
|
149 } |
|
150 if (in_flags_write & PR_POLL_WRITE) |
|
151 { |
|
152 pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; |
|
153 #ifdef BSD_SELECT |
|
154 FD_SET(osfd, &wt); |
|
155 #else |
|
156 socks[npds+wt] = osfd; |
|
157 wt++; |
|
158 #endif |
|
159 } |
|
160 if (pd->in_flags & PR_POLL_EXCEPT) |
|
161 { |
|
162 #ifdef BSD_SELECT |
|
163 FD_SET(osfd, &ex); |
|
164 #else |
|
165 socks[npds*2+ex] = osfd; |
|
166 ex++; |
|
167 #endif |
|
168 } |
|
169 } |
|
170 } |
|
171 else |
|
172 { |
|
173 if (0 == ready) |
|
174 { |
|
175 PRPollDesc *prev; |
|
176 for (prev = pds; prev < pd; prev++) |
|
177 { |
|
178 prev->out_flags = 0; |
|
179 } |
|
180 } |
|
181 ready += 1; /* this will cause an abrupt return */ |
|
182 pd->out_flags = PR_POLL_NVAL; /* bogii */ |
|
183 } |
|
184 } |
|
185 } |
|
186 else |
|
187 { |
|
188 pd->out_flags = 0; |
|
189 } |
|
190 } |
|
191 |
|
192 if (0 != ready) |
|
193 { |
|
194 #ifndef BSD_SELECT |
|
195 PR_Free(socks); |
|
196 #endif |
|
197 return ready; /* no need to block */ |
|
198 } |
|
199 |
|
200 remaining = timeout; |
|
201 start = PR_IntervalNow(); |
|
202 |
|
203 retry: |
|
204 #ifdef BSD_SELECT |
|
205 if (timeout != PR_INTERVAL_NO_TIMEOUT) |
|
206 { |
|
207 PRInt32 ticksPerSecond = PR_TicksPerSecond(); |
|
208 tv.tv_sec = remaining / ticksPerSecond; |
|
209 tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); |
|
210 tvp = &tv; |
|
211 } |
|
212 |
|
213 ready = bsdselect(maxfd + 1, &rd, &wt, &ex, tvp); |
|
214 #else |
|
215 switch (timeout) |
|
216 { |
|
217 case PR_INTERVAL_NO_WAIT: |
|
218 msecs = 0; |
|
219 break; |
|
220 case PR_INTERVAL_NO_TIMEOUT: |
|
221 msecs = -1; |
|
222 break; |
|
223 default: |
|
224 msecs = PR_IntervalToMilliseconds(remaining); |
|
225 } |
|
226 |
|
227 /* compact array */ |
|
228 for( i = rd, j = npds; j < npds+wt; i++,j++ ) |
|
229 socks[i] = socks[j]; |
|
230 for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ ) |
|
231 socks[i] = socks[j]; |
|
232 |
|
233 ready = os2_select(socks, rd, wt, ex, msecs); |
|
234 #endif |
|
235 |
|
236 if (ready == -1 && errno == EINTR) |
|
237 { |
|
238 if (timeout == PR_INTERVAL_NO_TIMEOUT) |
|
239 goto retry; |
|
240 else |
|
241 { |
|
242 elapsed = (PRIntervalTime) (PR_IntervalNow() - start); |
|
243 if (elapsed > timeout) |
|
244 ready = 0; /* timed out */ |
|
245 else |
|
246 { |
|
247 remaining = timeout - elapsed; |
|
248 goto retry; |
|
249 } |
|
250 } |
|
251 } |
|
252 |
|
253 /* |
|
254 ** Now to unravel the select sets back into the client's poll |
|
255 ** descriptor list. Is this possibly an area for pissing away |
|
256 ** a few cycles or what? |
|
257 */ |
|
258 if (ready > 0) |
|
259 { |
|
260 ready = 0; |
|
261 for (pd = pds, epd = pd + npds; pd < epd; pd++) |
|
262 { |
|
263 PRInt16 out_flags = 0; |
|
264 if ((NULL != pd->fd) && (0 != pd->in_flags)) |
|
265 { |
|
266 PRInt32 osfd; |
|
267 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
|
268 PR_ASSERT(NULL != bottom); |
|
269 |
|
270 osfd = bottom->secret->md.osfd; |
|
271 |
|
272 #ifdef BSD_SELECT |
|
273 if (FD_ISSET(osfd, &rd)) |
|
274 #else |
|
275 if( IsSocketSet(osfd, socks, 0, rd) ) |
|
276 #endif |
|
277 { |
|
278 if (pd->out_flags & _PR_POLL_READ_SYS_READ) |
|
279 out_flags |= PR_POLL_READ; |
|
280 if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) |
|
281 out_flags |= PR_POLL_WRITE; |
|
282 } |
|
283 |
|
284 #ifdef BSD_SELECT |
|
285 if (FD_ISSET(osfd, &wt)) |
|
286 #else |
|
287 if( IsSocketSet(osfd, socks, rd, wt) ) |
|
288 #endif |
|
289 { |
|
290 if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) |
|
291 out_flags |= PR_POLL_READ; |
|
292 if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) |
|
293 out_flags |= PR_POLL_WRITE; |
|
294 } |
|
295 |
|
296 #ifdef BSD_SELECT |
|
297 if (FD_ISSET(osfd, &ex)) |
|
298 #else |
|
299 if( IsSocketSet(osfd, socks, rd+wt, ex) ) |
|
300 #endif |
|
301 { |
|
302 out_flags |= PR_POLL_EXCEPT; |
|
303 } |
|
304 } |
|
305 pd->out_flags = out_flags; |
|
306 if (out_flags) ready++; |
|
307 } |
|
308 PR_ASSERT(ready > 0); |
|
309 } |
|
310 else if (ready < 0) |
|
311 { |
|
312 err = _MD_ERRNO(); |
|
313 if (err == EBADF) |
|
314 { |
|
315 /* Find the bad fds */ |
|
316 int optval; |
|
317 int optlen = sizeof(optval); |
|
318 ready = 0; |
|
319 for (pd = pds, epd = pd + npds; pd < epd; pd++) |
|
320 { |
|
321 pd->out_flags = 0; |
|
322 if ((NULL != pd->fd) && (0 != pd->in_flags)) |
|
323 { |
|
324 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
|
325 if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, |
|
326 SO_TYPE, (char *) &optval, &optlen) == -1) |
|
327 { |
|
328 PR_ASSERT(sock_errno() == ENOTSOCK); |
|
329 if (sock_errno() == ENOTSOCK) |
|
330 { |
|
331 pd->out_flags = PR_POLL_NVAL; |
|
332 ready++; |
|
333 } |
|
334 } |
|
335 } |
|
336 } |
|
337 PR_ASSERT(ready > 0); |
|
338 } |
|
339 else |
|
340 _PR_MD_MAP_SELECT_ERROR(err); |
|
341 } |
|
342 |
|
343 #ifndef BSD_SELECT |
|
344 PR_Free(socks); |
|
345 #endif |
|
346 return ready; |
|
347 } |
|
348 |