]> sourceware.org Git - glibc.git/blob - hurd/hurdselect.c
bcc2594bf05fc58a20400846080fb46294451015
[glibc.git] / hurd / hurdselect.c
1 /* Guts of both `select' and `poll' for Hurd.
2 Copyright (C) 1991,92,93,94,95,96,97,98, 99 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 #include <sys/types.h>
21 #include <sys/poll.h>
22 #include <hurd.h>
23 #include <hurd/fd.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <stdint.h>
28
29 /* All user select types. */
30 #define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
31
32 /* Used to record that a particular select rpc returned. Must be distinct
33 from SELECT_ALL (which better not have the high bit set). */
34 #define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
35
36 /* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in
37 each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull. If TIMEOUT is not
38 NULL, time out after waiting the interval specified therein. Returns
39 the number of ready descriptors, or -1 for errors. */
40 int
41 _hurd_select (int nfds,
42 struct pollfd *pollfds,
43 fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
44 const struct timespec *timeout, const sigset_t *sigmask)
45 {
46 int i;
47 mach_port_t portset;
48 int got;
49 error_t err;
50 fd_set rfds, wfds, xfds;
51 int firstfd, lastfd;
52 mach_msg_timeout_t to = (timeout != NULL ?
53 (timeout->tv_sec * 1000 +
54 timeout->tv_nsec / 1000000) :
55 0);
56 struct
57 {
58 struct hurd_userlink ulink;
59 struct hurd_fd *cell;
60 mach_port_t io_port;
61 int type;
62 mach_port_t reply_port;
63 } d[nfds];
64 sigset_t oset;
65
66 if (sigmask && __sigprocmask (SIG_SETMASK, sigmask, &oset))
67 return -1;
68
69 if (pollfds)
70 {
71 /* Collect interesting descriptors from the user's `pollfd' array.
72 We do a first pass that reads the user's array before taking
73 any locks. The second pass then only touches our own stack,
74 and gets the port references. */
75
76 for (i = 0; i < nfds; ++i)
77 if (pollfds[i].fd >= 0)
78 {
79 int type = 0;
80 if (pollfds[i].events & POLLIN)
81 type |= SELECT_READ;
82 if (pollfds[i].events & POLLOUT)
83 type |= SELECT_WRITE;
84 if (pollfds[i].events & POLLPRI)
85 type |= SELECT_URG;
86
87 d[i].io_port = pollfds[i].fd;
88 d[i].type = type;
89 }
90 else
91 d[i].type = 0;
92
93 HURD_CRITICAL_BEGIN;
94 __mutex_lock (&_hurd_dtable_lock);
95
96 for (i = 0; i < nfds; ++i)
97 if (d[i].type != 0)
98 {
99 const int fd = (int) d[i].io_port;
100
101 if (fd < _hurd_dtablesize)
102 {
103 d[i].cell = _hurd_dtable[fd];
104 d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
105 if (d[i].io_port != MACH_PORT_NULL)
106 continue;
107 }
108
109 /* If one descriptor is bogus, we fail completely. */
110 while (i-- > 0)
111 if (d[i].type != 0)
112 _hurd_port_free (&d[i].cell->port,
113 &d[i].ulink, d[i].io_port);
114 break;
115 }
116
117 __mutex_unlock (&_hurd_dtable_lock);
118 HURD_CRITICAL_END;
119
120 if (i < nfds)
121 {
122 if (sigmask)
123 __sigprocmask (SIG_SETMASK, &oset, NULL);
124 errno = EBADF;
125 return -1;
126 }
127
128 lastfd = i - 1;
129 firstfd = i == 0 ? lastfd : 0;
130 }
131 else
132 {
133 /* Collect interested descriptors from the user's fd_set arguments.
134 Use local copies so we can't crash from user bogosity. */
135
136 if (readfds == NULL)
137 FD_ZERO (&rfds);
138 else
139 rfds = *readfds;
140 if (writefds == NULL)
141 FD_ZERO (&wfds);
142 else
143 wfds = *writefds;
144 if (exceptfds == NULL)
145 FD_ZERO (&xfds);
146 else
147 xfds = *exceptfds;
148
149 HURD_CRITICAL_BEGIN;
150 __mutex_lock (&_hurd_dtable_lock);
151
152 if (nfds > _hurd_dtablesize)
153 nfds = _hurd_dtablesize;
154
155 /* Collect the ports for interesting FDs. */
156 firstfd = lastfd = -1;
157 for (i = 0; i < nfds; ++i)
158 {
159 int type = 0;
160 if (readfds != NULL && FD_ISSET (i, &rfds))
161 type |= SELECT_READ;
162 if (writefds != NULL && FD_ISSET (i, &wfds))
163 type |= SELECT_WRITE;
164 if (exceptfds != NULL && FD_ISSET (i, &xfds))
165 type |= SELECT_URG;
166 d[i].type = type;
167 if (type)
168 {
169 d[i].cell = _hurd_dtable[i];
170 d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
171 if (d[i].io_port == MACH_PORT_NULL)
172 {
173 /* If one descriptor is bogus, we fail completely. */
174 while (i-- > 0)
175 if (d[i].type != 0)
176 _hurd_port_free (&d[i].cell->port, &d[i].ulink,
177 d[i].io_port);
178 break;
179 }
180 lastfd = i;
181 if (firstfd == -1)
182 firstfd = i;
183 }
184 }
185
186 __mutex_unlock (&_hurd_dtable_lock);
187 HURD_CRITICAL_END;
188
189 if (i < nfds)
190 {
191 if (sigmask)
192 __sigprocmask (SIG_SETMASK, &oset, NULL);
193 errno = EBADF;
194 return -1;
195 }
196 }
197
198
199 err = 0;
200 got = 0;
201
202 /* Send them all io_select request messages. */
203
204 if (firstfd == -1)
205 /* But not if there were no ports to deal with at all.
206 We are just a pure timeout. */
207 portset = __mach_reply_port ();
208 else
209 {
210 portset = MACH_PORT_NULL;
211
212 for (i = firstfd; i <= lastfd; ++i)
213 if (d[i].type)
214 {
215 int type = d[i].type;
216 d[i].reply_port = __mach_reply_port ();
217 err = __io_select (d[i].io_port, d[i].reply_port,
218 /* Poll only if there's a single descriptor. */
219 (firstfd == lastfd) ? to : 0,
220 &type);
221 switch (err)
222 {
223 case MACH_RCV_TIMED_OUT:
224 /* No immediate response. This is normal. */
225 err = 0;
226 if (firstfd == lastfd)
227 /* When there's a single descriptor, we don't need a
228 portset, so just pretend we have one, but really
229 use the single reply port. */
230 portset = d[i].reply_port;
231 else if (got == 0)
232 /* We've got multiple reply ports, so we need a port set to
233 multiplex them. */
234 {
235 /* We will wait again for a reply later. */
236 if (portset == MACH_PORT_NULL)
237 /* Create the portset to receive all the replies on. */
238 err = __mach_port_allocate (__mach_task_self (),
239 MACH_PORT_RIGHT_PORT_SET,
240 &portset);
241 if (! err)
242 /* Put this reply port in the port set. */
243 __mach_port_move_member (__mach_task_self (),
244 d[i].reply_port, portset);
245 }
246 break;
247
248 default:
249 /* No other error should happen. Callers of select
250 don't expect to see errors, so we simulate
251 readiness of the erring object and the next call
252 hopefully will get the error again. */
253 type = SELECT_ALL;
254 /* FALLTHROUGH */
255
256 case 0:
257 /* We got an answer. */
258 if ((type & SELECT_ALL) == 0)
259 /* Bogus answer; treat like an error, as a fake positive. */
260 type = SELECT_ALL;
261
262 /* This port is already ready already. */
263 d[i].type &= type;
264 d[i].type |= SELECT_RETURNED;
265 ++got;
266 break;
267 }
268 _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
269 }
270 }
271
272 /* Now wait for reply messages. */
273 if (!err && got == 0)
274 {
275 /* Now wait for io_select_reply messages on PORT,
276 timing out as appropriate. */
277
278 union
279 {
280 mach_msg_header_t head;
281 struct
282 {
283 mach_msg_header_t head;
284 mach_msg_type_t err_type;
285 error_t err;
286 } error;
287 struct
288 {
289 mach_msg_header_t head;
290 mach_msg_type_t err_type;
291 error_t err;
292 mach_msg_type_t result_type;
293 int result;
294 } success;
295 } msg;
296 mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
297 error_t msgerr;
298 while ((msgerr = __mach_msg (&msg.head,
299 MACH_RCV_MSG | options,
300 0, sizeof msg, portset, to,
301 MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
302 {
303 /* We got a message. Decode it. */
304 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
305 const mach_msg_type_t inttype =
306 { MACH_MSG_TYPE_INTEGER_T, sizeof (MACH_MSG_TYPE_INTEGER_T) * 8,
307 1, 1, 0, 0 };
308 if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
309 msg.head.msgh_size >= sizeof msg.error &&
310 !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
311 *(int *) &msg.error.err_type == *(int *) &inttype)
312 {
313 /* This is a properly formatted message so far.
314 See if it is a success or a failure. */
315 if (msg.error.err == EINTR &&
316 msg.head.msgh_size == sizeof msg.error)
317 {
318 /* EINTR response; poll for further responses
319 and then return quickly. */
320 err = EINTR;
321 goto poll;
322 }
323 if (msg.error.err ||
324 msg.head.msgh_size != sizeof msg.success ||
325 *(int *) &msg.success.result_type != *(int *) &inttype ||
326 (msg.success.result & SELECT_ALL) == 0)
327 {
328 /* Error or bogus reply. Simulate readiness. */
329 __mach_msg_destroy (&msg.head);
330 msg.success.result = SELECT_ALL;
331 }
332
333 /* Look up the respondent's reply port and record its
334 readiness. */
335 {
336 int had = got;
337 if (firstfd != -1)
338 for (i = firstfd; i <= lastfd; ++i)
339 if (d[i].type
340 && d[i].reply_port == msg.head.msgh_local_port)
341 {
342 d[i].type &= msg.success.result;
343 d[i].type |= SELECT_RETURNED;
344 ++got;
345 }
346 assert (got > had);
347 }
348 }
349
350 if (msg.head.msgh_remote_port != MACH_PORT_NULL)
351 __mach_port_deallocate (__mach_task_self (),
352 msg.head.msgh_remote_port);
353
354 if (got)
355 poll:
356 {
357 /* Poll for another message. */
358 to = 0;
359 options |= MACH_RCV_TIMEOUT;
360 }
361 }
362
363 if (err == MACH_RCV_TIMED_OUT)
364 /* This is the normal value for ERR. We might have timed out and
365 read no messages. Otherwise, after receiving the first message,
366 we poll for more messages. We receive with a timeout of 0 to
367 effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
368 message waiting. */
369 err = 0;
370
371 if (got)
372 /* At least one descriptor is known to be ready now, so we will
373 return success. */
374 err = 0;
375 }
376
377 if (firstfd != -1)
378 for (i = firstfd; i <= lastfd; ++i)
379 if (d[i].type)
380 __mach_port_destroy (__mach_task_self (), d[i].reply_port);
381 if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
382 /* Destroy PORTSET, but only if it's not actually the reply port for a
383 single descriptor (in which case it's destroyed in the previous loop;
384 not doing it here is just a bit more efficient). */
385 __mach_port_destroy (__mach_task_self (), portset);
386
387 if (err)
388 {
389 if (sigmask)
390 __sigprocmask (SIG_SETMASK, &oset, NULL);
391 return __hurd_fail (err);
392 }
393
394 if (pollfds)
395 /* Fill in the `revents' members of the user's array. */
396 for (i = 0; i < nfds; ++i)
397 {
398 const int type = d[i].type;
399 int_fast16_t revents = 0;
400
401 if (type & SELECT_READ)
402 revents |= POLLIN;
403 if (type & SELECT_WRITE)
404 revents |= POLLOUT;
405 if (type & SELECT_URG)
406 revents |= POLLPRI;
407
408 pollfds[i].revents = revents;
409 }
410 else
411 {
412 /* Below we recalculate GOT to include an increment for each operation
413 allowed on each fd. */
414 got = 0;
415
416 /* Set the user bitarrays. We only ever have to clear bits, as all
417 desired ones are initially set. */
418 if (firstfd != -1)
419 for (i = firstfd; i <= lastfd; ++i)
420 {
421 int type = d[i].type;
422
423 if ((type & SELECT_RETURNED) == 0)
424 type = 0;
425
426 if (type & SELECT_READ)
427 got++;
428 else if (readfds)
429 FD_CLR (i, readfds);
430 if (type & SELECT_WRITE)
431 got++;
432 else if (writefds)
433 FD_CLR (i, writefds);
434 if (type & SELECT_URG)
435 got++;
436 else if (exceptfds)
437 FD_CLR (i, exceptfds);
438 }
439 }
440
441 if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
442 return -1;
443
444 return got;
445 }
This page took 0.055777 seconds and 4 git commands to generate.