|
1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License, Version 1.0 only |
|
6 * (the "License"). You may not use this file except in compliance |
|
7 * with the License. |
|
8 * |
|
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
10 * or http://www.opensolaris.org/os/licensing. |
|
11 * See the License for the specific language governing permissions |
|
12 * and limitations under the License. |
|
13 * |
|
14 * When distributing Covered Code, include this CDDL HEADER in each |
|
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
16 * If applicable, add the following below this CDDL HEADER, with the |
|
17 * fields enclosed by brackets "[]" replaced with your own identifying |
|
18 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
19 * |
|
20 * CDDL HEADER END |
|
21 */ |
|
22 /* |
|
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. |
|
24 * Use is subject to license terms. |
|
25 */ |
|
26 |
|
27 #pragma ident "%Z%%M% %I% %E% SMI" |
|
28 |
|
29 /* Copyright (c) 1988 AT&T */ |
|
30 /* All Rights Reserved */ |
|
31 |
|
32 |
|
33 /* |
|
34 * Emulation of select() system call using _pollsys() system call. |
|
35 * |
|
36 * Assumptions: |
|
37 * polling for input only is most common. |
|
38 * polling for exceptional conditions is very rare. |
|
39 * |
|
40 * Note that is it not feasible to emulate all error conditions, |
|
41 * in particular conditions that would return EFAULT are far too |
|
42 * difficult to check for in a library routine. |
|
43 * |
|
44 * This is the alternate large fd_set select. |
|
45 * |
|
46 */ |
|
47 |
|
48 /* |
|
49 * Must precede any include files |
|
50 */ |
|
51 #ifdef FD_SETSIZE |
|
52 #undef FD_SETSIZE |
|
53 #endif |
|
54 #define FD_SETSIZE 65536 |
|
55 |
|
56 /* |
|
57 * We do not #redefine the name since the only users of this |
|
58 * are external to the libraries and commands. |
|
59 * |
|
60 * #pragma weak pselect_large_fdset = _pselect_large_fdset |
|
61 * #pragma weak select_large_fdset = _select_large_fdset |
|
62 */ |
|
63 |
|
64 #include "synonyms.h" |
|
65 #include <values.h> |
|
66 #include <stdlib.h> |
|
67 #include <string.h> |
|
68 #include <errno.h> |
|
69 #include <sys/time.h> |
|
70 #include <sys/types.h> |
|
71 #include <sys/poll.h> |
|
72 #include <string.h> |
|
73 #include <stdlib.h> |
|
74 #include "libc.h" |
|
75 |
|
76 #define DEFAULT_POLL_SIZE 64 |
|
77 |
|
78 static struct pollfd *realloc_fds(int *, struct pollfd **, struct pollfd *); |
|
79 |
|
80 int |
|
81 pselect_large_fdset(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, |
|
82 const timespec_t *tsp, const sigset_t *sigmask) |
|
83 { |
|
84 long *in, *out, *ex; |
|
85 ulong_t m; /* bit mask */ |
|
86 int j; /* loop counter */ |
|
87 ulong_t b; /* bits to test */ |
|
88 int n, rv; |
|
89 int lastj = -1; |
|
90 int nused; |
|
91 |
|
92 /* |
|
93 * Rather than have a mammoth pollfd (65K) list on the stack |
|
94 * we start with a small one and then malloc larger chunks |
|
95 * on the heap if necessary. |
|
96 */ |
|
97 |
|
98 struct pollfd pfd[DEFAULT_POLL_SIZE]; |
|
99 struct pollfd *p; |
|
100 struct pollfd *pfd_list; |
|
101 int nfds_on_list; |
|
102 |
|
103 fd_set zero; |
|
104 |
|
105 /* |
|
106 * Check for invalid conditions at outset. |
|
107 * Required for spec1170. |
|
108 * SUSV3: We must behave as a cancellation point even if we fail early. |
|
109 */ |
|
110 if (nfds >= 0 && nfds <= FD_SETSIZE) { |
|
111 if (tsp != NULL) { |
|
112 if (tsp->tv_nsec < 0 || tsp->tv_nsec >= NANOSEC || |
|
113 tsp->tv_sec < 0) { |
|
114 _private_testcancel(); |
|
115 errno = EINVAL; |
|
116 return (-1); |
|
117 } |
|
118 } |
|
119 } else { |
|
120 _private_testcancel(); |
|
121 errno = EINVAL; |
|
122 return (-1); |
|
123 } |
|
124 |
|
125 /* |
|
126 * If any input args are null, point them at the null array. |
|
127 */ |
|
128 (void) memset(&zero, 0, sizeof (fd_set)); |
|
129 if (in0 == NULL) |
|
130 in0 = &zero; |
|
131 if (out0 == NULL) |
|
132 out0 = &zero; |
|
133 if (ex0 == NULL) |
|
134 ex0 = &zero; |
|
135 |
|
136 nfds_on_list = DEFAULT_POLL_SIZE; |
|
137 pfd_list = pfd; |
|
138 p = pfd_list; |
|
139 (void) memset(pfd, 0, sizeof (pfd)); |
|
140 /* |
|
141 * For each fd, if any bits are set convert them into |
|
142 * the appropriate pollfd struct. |
|
143 */ |
|
144 in = (long *)in0->fds_bits; |
|
145 out = (long *)out0->fds_bits; |
|
146 ex = (long *)ex0->fds_bits; |
|
147 nused = 0; |
|
148 /* |
|
149 * nused reflects the number of pollfd structs currently used |
|
150 * less one. If realloc_fds returns 0 it is because malloc |
|
151 * failed. We expect malloc() to have done the proper |
|
152 * thing with errno. |
|
153 */ |
|
154 for (n = 0; n < nfds; n += NFDBITS) { |
|
155 b = (ulong_t)(*in | *out | *ex); |
|
156 for (j = 0, m = 1; b != 0; j++, b >>= 1, m <<= 1) { |
|
157 if (b & 1) { |
|
158 p->fd = n + j; |
|
159 if (p->fd < nfds) { |
|
160 p->events = 0; |
|
161 if (*in & m) |
|
162 p->events |= POLLRDNORM; |
|
163 if (*out & m) |
|
164 p->events |= POLLWRNORM; |
|
165 if (*ex & m) |
|
166 p->events |= POLLRDBAND; |
|
167 if (nused < (nfds_on_list - 1)) { |
|
168 p++; |
|
169 } else { |
|
170 p = realloc_fds( |
|
171 &nfds_on_list, |
|
172 &pfd_list, pfd); |
|
173 if (p == 0) { |
|
174 if (pfd_list != pfd) |
|
175 (void) free(pfd_list); |
|
176 _private_testcancel(); |
|
177 return (-1); |
|
178 } |
|
179 } |
|
180 nused++; |
|
181 } else |
|
182 goto done; |
|
183 } |
|
184 } |
|
185 in++; |
|
186 out++; |
|
187 ex++; |
|
188 } |
|
189 done: |
|
190 /* |
|
191 * Now do the poll. |
|
192 */ |
|
193 do { |
|
194 rv = _pollsys(pfd_list, (nfds_t)nused, tsp, sigmask); |
|
195 } while (rv < 0 && errno == EAGAIN); |
|
196 |
|
197 if (rv < 0) { /* no need to set bit masks */ |
|
198 if (pfd_list != pfd) |
|
199 (void) free(pfd_list); |
|
200 return (rv); |
|
201 } else if (rv == 0) { |
|
202 /* |
|
203 * Clear out bit masks, just in case. |
|
204 * On the assumption that usually only |
|
205 * one bit mask is set, use three loops. |
|
206 */ |
|
207 if (in0 != &zero) { |
|
208 in = (long *)in0->fds_bits; |
|
209 for (n = 0; n < nfds; n += NFDBITS) |
|
210 *in++ = 0; |
|
211 } |
|
212 if (out0 != &zero) { |
|
213 out = (long *)out0->fds_bits; |
|
214 for (n = 0; n < nfds; n += NFDBITS) |
|
215 *out++ = 0; |
|
216 } |
|
217 if (ex0 != &zero) { |
|
218 ex = (long *)ex0->fds_bits; |
|
219 for (n = 0; n < nfds; n += NFDBITS) |
|
220 *ex++ = 0; |
|
221 } |
|
222 if (pfd_list != pfd) |
|
223 (void) free(pfd_list); |
|
224 return (0); |
|
225 } |
|
226 |
|
227 /* |
|
228 * Check for EINVAL error case first to avoid changing any bits |
|
229 * if we're going to return an error. |
|
230 */ |
|
231 for (p = pfd_list, j = nused; j-- > 0; p++) { |
|
232 /* |
|
233 * select will return EBADF immediately if any fd's |
|
234 * are bad. poll will complete the poll on the |
|
235 * rest of the fd's and include the error indication |
|
236 * in the returned bits. This is a rare case so we |
|
237 * accept this difference and return the error after |
|
238 * doing more work than select would've done. |
|
239 */ |
|
240 if (p->revents & POLLNVAL) { |
|
241 errno = EBADF; |
|
242 if (pfd_list != pfd) |
|
243 (void) free(pfd_list); |
|
244 return (-1); |
|
245 } |
|
246 /* |
|
247 * We would like to make POLLHUP available to select, |
|
248 * checking to see if we have pending data to be read. |
|
249 * BUT until we figure out how not to break Xsun's |
|
250 * dependencies on select's existing features... |
|
251 * This is what we _thought_ would work ... sigh! |
|
252 */ |
|
253 /* |
|
254 * if ((p->revents & POLLHUP) && |
|
255 * !(p->revents & (POLLRDNORM|POLLRDBAND))) { |
|
256 * errno = EINTR; |
|
257 * return (-1); |
|
258 * } |
|
259 */ |
|
260 } |
|
261 |
|
262 /* |
|
263 * Convert results of poll back into bits |
|
264 * in the argument arrays. |
|
265 * |
|
266 * We assume POLLRDNORM, POLLWRNORM, and POLLRDBAND will only be set |
|
267 * on return from poll if they were set on input, thus we don't |
|
268 * worry about accidentally setting the corresponding bits in the |
|
269 * zero array if the input bit masks were null. |
|
270 * |
|
271 * Must return number of bits set, not number of ready descriptors |
|
272 * (as the man page says, and as poll() does). |
|
273 */ |
|
274 rv = 0; |
|
275 for (p = pfd_list; nused-- > 0; p++) { |
|
276 j = (int)(p->fd / NFDBITS); |
|
277 /* have we moved into another word of the bit mask yet? */ |
|
278 if (j != lastj) { |
|
279 /* clear all output bits to start with */ |
|
280 in = (long *)&in0->fds_bits[j]; |
|
281 out = (long *)&out0->fds_bits[j]; |
|
282 ex = (long *)&ex0->fds_bits[j]; |
|
283 /* |
|
284 * In case we made "zero" read-only (e.g., with |
|
285 * cc -R), avoid actually storing into it. |
|
286 */ |
|
287 if (in0 != &zero) |
|
288 *in = 0; |
|
289 if (out0 != &zero) |
|
290 *out = 0; |
|
291 if (ex0 != &zero) |
|
292 *ex = 0; |
|
293 lastj = j; |
|
294 } |
|
295 if (p->revents) { |
|
296 m = 1L << (p->fd % NFDBITS); |
|
297 if (p->revents & POLLRDNORM) { |
|
298 *in |= m; |
|
299 rv++; |
|
300 } |
|
301 if (p->revents & POLLWRNORM) { |
|
302 *out |= m; |
|
303 rv++; |
|
304 } |
|
305 if (p->revents & POLLRDBAND) { |
|
306 *ex |= m; |
|
307 rv++; |
|
308 } |
|
309 /* |
|
310 * Only set this bit on return if we asked about |
|
311 * input conditions. |
|
312 */ |
|
313 if ((p->revents & (POLLHUP|POLLERR)) && |
|
314 (p->events & POLLRDNORM)) { |
|
315 if ((*in & m) == 0) |
|
316 rv++; /* wasn't already set */ |
|
317 *in |= m; |
|
318 } |
|
319 /* |
|
320 * Only set this bit on return if we asked about |
|
321 * output conditions. |
|
322 */ |
|
323 if ((p->revents & (POLLHUP|POLLERR)) && |
|
324 (p->events & POLLWRNORM)) { |
|
325 if ((*out & m) == 0) |
|
326 rv++; /* wasn't already set */ |
|
327 *out |= m; |
|
328 } |
|
329 /* |
|
330 * Only set this bit on return if we asked about |
|
331 * output conditions. |
|
332 */ |
|
333 if ((p->revents & (POLLHUP|POLLERR)) && |
|
334 (p->events & POLLRDBAND)) { |
|
335 if ((*ex & m) == 0) |
|
336 rv++; /* wasn't already set */ |
|
337 *ex |= m; |
|
338 } |
|
339 } |
|
340 } |
|
341 if (pfd_list != pfd) |
|
342 (void) free(pfd_list); |
|
343 return (rv); |
|
344 } |
|
345 |
|
346 int |
|
347 select_large_fdset(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, |
|
348 struct timeval *tv) |
|
349 { |
|
350 timespec_t ts; |
|
351 timespec_t *tsp; |
|
352 |
|
353 if (tv == NULL) |
|
354 tsp = NULL; |
|
355 else { |
|
356 if (tv->tv_usec < 0 || tv->tv_usec >= MICROSEC) { |
|
357 errno = EINVAL; |
|
358 return (-1); |
|
359 } |
|
360 ts.tv_sec = tv->tv_sec; |
|
361 ts.tv_nsec = tv->tv_usec * 1000; |
|
362 tsp = &ts; |
|
363 } |
|
364 |
|
365 return (pselect_large_fdset(nfds, in0, out0, ex0, tsp, NULL)); |
|
366 } |
|
367 |
|
368 /* |
|
369 * Reallocate buffers of pollfds for our list. We malloc a new buffer |
|
370 * and, in the case where the old buffer does not match what is passed |
|
371 * in orig, free the buffer after copying the contents. |
|
372 */ |
|
373 struct pollfd * |
|
374 realloc_fds(int *num, struct pollfd **list_head, struct pollfd *orig) |
|
375 { |
|
376 struct pollfd *b; |
|
377 int nta; |
|
378 int n2; |
|
379 |
|
380 n2 = *num * 2; |
|
381 nta = n2 * sizeof (struct pollfd); |
|
382 b = malloc(nta); |
|
383 if (b) { |
|
384 (void) memset(b, 0, (size_t)nta); |
|
385 (void) memcpy(b, *list_head, nta / 2); |
|
386 if (*list_head != orig) |
|
387 (void) free (*list_head); |
|
388 *list_head = b; |
|
389 b += *num; |
|
390 *num = n2; |
|
391 } |
|
392 return (b); |
|
393 } |