]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/mach/hurd/select.c
Update.
[thirdparty/glibc.git] / sysdeps / mach / hurd / select.c
CommitLineData
ebbad4cc 1/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
6d52618b 2 This file is part of the GNU C Library.
28f540f4 3
6d52618b
UD
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
28f540f4 8
6d52618b
UD
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
28f540f4 13
6d52618b
UD
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
28f540f4 18
28f540f4
RM
19#include <sys/types.h>
20#include <hurd.h>
21#include <hurd/fd.h>
22#include <stdlib.h>
23#include <string.h>
8f0c527e 24#include <assert.h>
28f540f4 25
0c7b844d
MB
26/* All user select types. */
27#define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
28
29/* Used to record that a particular select rpc returned. Must be distinct
30 from SELECT_ALL (which better not have the high bit set). */
31#define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
28f540f4
RM
32
33/* Check the first NFDS descriptors each in READFDS (if not NULL) for read
34 readiness, in WRITEFDS (if not NULL) for write readiness, and in EXCEPTFDS
35 (if not NULL) for exceptional conditions. If TIMEOUT is not NULL, time out
36 after waiting the interval specified therein. Returns the number of ready
37 descriptors, or -1 for errors. */
38int
ebbad4cc
UD
39__select (nfds, readfds, writefds, exceptfds, timeout)
40 int nfds;
41 fd_set *readfds;
42 fd_set *writefds;
43 fd_set *exceptfds;
44 struct timeval *timeout;
28f540f4
RM
45{
46 int i;
8f0c527e 47 mach_port_t portset;
28f540f4 48 int got;
28f540f4
RM
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_usec / 1000) :
55 0);
8f0c527e
RM
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];
28f540f4
RM
64
65 /* Use local copies so we can't crash from user bogosity. */
66 if (readfds == NULL)
67 FD_ZERO (&rfds);
68 else
69 rfds = *readfds;
70 if (writefds == NULL)
71 FD_ZERO (&wfds);
72 else
73 wfds = *writefds;
74 if (exceptfds == NULL)
75 FD_ZERO (&xfds);
76 else
77 xfds = *exceptfds;
78
79 HURD_CRITICAL_BEGIN;
80 __mutex_lock (&_hurd_dtable_lock);
81
82 if (nfds > _hurd_dtablesize)
83 nfds = _hurd_dtablesize;
84
85 /* Collect the ports for interesting FDs. */
28f540f4
RM
86 firstfd = lastfd = -1;
87 for (i = 0; i < nfds; ++i)
88 {
89 int type = 0;
90 if (readfds != NULL && FD_ISSET (i, &rfds))
91 type |= SELECT_READ;
92 if (writefds != NULL && FD_ISSET (i, &wfds))
93 type |= SELECT_WRITE;
94 if (exceptfds != NULL && FD_ISSET (i, &xfds))
95 type |= SELECT_URG;
8f0c527e 96 d[i].type = type;
28f540f4
RM
97 if (type)
98 {
8f0c527e
RM
99 d[i].cell = _hurd_dtable[i];
100 d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
101 if (d[i].io_port == MACH_PORT_NULL)
28f540f4
RM
102 {
103 /* If one descriptor is bogus, we fail completely. */
104 while (i-- > 0)
8f0c527e 105 _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
28f540f4
RM
106 errno = EBADF;
107 break;
108 }
109 lastfd = i;
110 if (firstfd == -1)
111 firstfd = i;
112 }
113 }
114
115 __mutex_unlock (&_hurd_dtable_lock);
116 HURD_CRITICAL_END;
117
118 if (i < nfds)
119 return -1;
120
28f540f4 121 /* Send them all io_select request messages. */
6d52618b 122
ebe3b3eb
TBB
123 if (firstfd == -1)
124 /* But not if there were no ports to deal with at all. */
125 portset = __mach_reply_port ();
126 else
127 {
128 err = 0;
129 got = 0;
130 portset = MACH_PORT_NULL;
6d52618b 131
ebe3b3eb
TBB
132 for (i = firstfd; i <= lastfd; ++i)
133 if (d[i].type)
28f540f4 134 {
ebe3b3eb
TBB
135 int type = d[i].type;
136 d[i].reply_port = __mach_reply_port ();
137 err = __io_select (d[i].io_port, d[i].reply_port,
138 /* Poll only if there's a single descriptor. */
139 (firstfd == lastfd) ? to : 0,
140 &type);
141 switch (err)
28f540f4 142 {
ebe3b3eb
TBB
143 case MACH_RCV_TIMED_OUT:
144 /* No immediate response. This is normal. */
145 err = 0;
146 if (firstfd == lastfd)
147 /* When there's a single descriptor, we don't need a
148 portset, so just pretend we have one, but really
149 use the single reply port. */
150 portset = d[i].reply_port;
151 else if (got == 0)
152 /* We've got multiple reply ports, so we need a port set to
153 multiplex them. */
154 {
155 /* We will wait again for a reply later. */
156 if (portset == MACH_PORT_NULL)
157 /* Create the portset to receive all the replies on. */
158 err = __mach_port_allocate (__mach_task_self (),
159 MACH_PORT_RIGHT_PORT_SET,
160 &portset);
161 if (! err)
162 /* Put this reply port in the port set. */
163 __mach_port_move_member (__mach_task_self (),
164 d[i].reply_port, portset);
165 }
166 break;
167
168 default:
169 /* No other error should happen. Callers of select
170 don't expect to see errors, so we simulate
171 readiness of the erring object and the next call
172 hopefully will get the error again. */
173 type = SELECT_ALL;
174 /* FALLTHROUGH */
175
176 case 0:
177 /* We got an answer. */
178 if ((type & SELECT_ALL) == 0)
179 /* Bogus answer; treat like an error, as a fake positive. */
180 type = SELECT_ALL;
6d52618b 181
ebe3b3eb
TBB
182 /* This port is already ready already. */
183 d[i].type &= type;
184 d[i].type |= SELECT_RETURNED;
185 ++got;
186 break;
28f540f4 187 }
ebe3b3eb 188 _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
28f540f4 189 }
ebe3b3eb 190 }
6d52618b 191
28f540f4 192 /* Now wait for reply messages. */
8f0c527e 193 if (!err && got == 0)
28f540f4
RM
194 {
195 /* Now wait for io_select_reply messages on PORT,
196 timing out as appropriate. */
197
198 union
199 {
200 mach_msg_header_t head;
201 struct
202 {
203 mach_msg_header_t head;
204 mach_msg_type_t err_type;
205 error_t err;
206 } error;
207 struct
208 {
209 mach_msg_header_t head;
210 mach_msg_type_t err_type;
211 error_t err;
212 mach_msg_type_t result_type;
213 int result;
28f540f4
RM
214 } success;
215 } msg;
216 mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
217 error_t msgerr;
218 while ((msgerr = __mach_msg (&msg.head,
219 MACH_RCV_MSG | options,
8f0c527e 220 0, sizeof msg, portset, to,
28f540f4
RM
221 MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
222 {
223 /* We got a message. Decode it. */
224#define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
225 const mach_msg_type_t inttype =
226 { MACH_MSG_TYPE_INTEGER_32, 32, 1, 1, 0, 0 };
227 if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
228 msg.head.msgh_size >= sizeof msg.error &&
229 !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
230 *(int *) &msg.error.err_type == *(int *) &inttype)
231 {
232 /* This is a properly formatted message so far.
233 See if it is a success or a failure. */
8f0c527e
RM
234 if (msg.error.err == EINTR &&
235 msg.head.msgh_size == sizeof msg.error)
28f540f4 236 {
8f0c527e
RM
237 /* EINTR response; poll for further responses
238 and then return quickly. */
239 err = EINTR;
240 goto poll;
28f540f4 241 }
8f0c527e
RM
242 if (msg.error.err ||
243 msg.head.msgh_size != sizeof msg.success ||
244 *(int *) &msg.success.result_type != *(int *) &inttype ||
245 (msg.success.result & SELECT_ALL) == 0)
28f540f4 246 {
8f0c527e 247 /* Error or bogus reply. Simulate readiness. */
ebe3b3eb 248 __mach_msg_destroy (&msg.head);
8f0c527e 249 msg.success.result = SELECT_ALL;
28f540f4 250 }
8f0c527e 251
6d52618b 252 /* Look up the respondent's reply port and record its
8f0c527e
RM
253 readiness. */
254 {
255 int had = got;
ebe3b3eb
TBB
256 if (firstfd != -1)
257 for (i = firstfd; i <= lastfd; ++i)
258 if (d[i].type
259 && d[i].reply_port == msg.head.msgh_local_port)
260 {
261 d[i].type &= msg.success.result;
262 d[i].type |= SELECT_RETURNED;
263 ++got;
264 }
8f0c527e
RM
265 assert (got > had);
266 }
28f540f4
RM
267 }
268
269 if (msg.head.msgh_remote_port != MACH_PORT_NULL)
270 __mach_port_deallocate (__mach_task_self (),
271 msg.head.msgh_remote_port);
272
8f0c527e
RM
273 if (got)
274 poll:
28f540f4
RM
275 {
276 /* Poll for another message. */
277 to = 0;
278 options |= MACH_RCV_TIMEOUT;
279 }
280 }
281
e9ef1cf3
MB
282 if (err == MACH_RCV_TIMED_OUT)
283 /* This is the normal value for ERR. We might have timed out and
284 read no messages. Otherwise, after receiving the first message,
285 we poll for more messages. We receive with a timeout of 0 to
286 effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
287 message waiting. */
288 err = 0;
28f540f4 289
8f0c527e
RM
290 if (got)
291 /* At least one descriptor is known to be ready now, so we will
292 return success. */
28f540f4
RM
293 err = 0;
294 }
295
ebe3b3eb
TBB
296 if (firstfd != -1)
297 for (i = firstfd; i <= lastfd; ++i)
298 if (d[i].type)
299 __mach_port_destroy (__mach_task_self (), d[i].reply_port);
300 if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
cbd96c33
MB
301 /* Destroy PORTSET, but only if it's not actually the reply port for a
302 single descriptor (in which case it's destroyed in the previous loop;
303 not doing it here is just a bit more efficient). */
8f0c527e 304 __mach_port_destroy (__mach_task_self (), portset);
28f540f4 305
28f540f4
RM
306 if (err)
307 return __hurd_fail (err);
308
924940c1
MB
309 /* Below we recalculate GOT to include an increment for each operation
310 allowed on each fd. */
311 got = 0;
312
0c7b844d
MB
313 /* Set the user bitarrays. We only ever have to clear bits, as all desired
314 ones are initially set. */
ebe3b3eb
TBB
315 if (firstfd != -1)
316 for (i = firstfd; i <= lastfd; ++i)
317 {
318 int type = d[i].type;
6d52618b 319
ebe3b3eb
TBB
320 if ((type & SELECT_RETURNED) == 0)
321 type = 0;
322
323 if (type & SELECT_READ)
324 got++;
325 else if (readfds)
326 FD_CLR (i, readfds);
327 if (type & SELECT_WRITE)
328 got++;
329 else if (writefds)
330 FD_CLR (i, writefds);
331 if (type & SELECT_URG)
332 got++;
333 else if (exceptfds)
334 FD_CLR (i, exceptfds);
335 }
28f540f4
RM
336
337 return got;
338}
339
340weak_alias (__select, select)