1 /* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
20 #include <sys/types.h>
26 /* All user select types. */
27 #define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
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)
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. */
39 DEFUN(__select
, (nfds
, readfds
, writefds
, exceptfds
, timeout
),
40 int nfds AND fd_set
*readfds AND fd_set
*writefds AND
41 fd_set
*exceptfds AND
struct timeval
*timeout
)
47 struct hurd_userlink
*ulink
;
49 struct hurd_fd
**cells
;
51 fd_set rfds
, wfds
, xfds
;
53 mach_msg_timeout_t to
= (timeout
!= NULL
?
54 (timeout
->tv_sec
* 1000 +
55 timeout
->tv_usec
/ 1000) :
58 /* Use local copies so we can't crash from user bogosity. */
67 if (exceptfds
== NULL
)
73 __mutex_lock (&_hurd_dtable_lock
);
75 if (nfds
> _hurd_dtablesize
)
76 nfds
= _hurd_dtablesize
;
78 /* Collect the ports for interesting FDs. */
79 cells
= __alloca (nfds
* sizeof (*cells
));
80 ports
= __alloca (nfds
* sizeof (*ports
));
81 types
= __alloca (nfds
* sizeof (*types
));
82 ulink
= __alloca (nfds
* sizeof (*ulink
));
83 firstfd
= lastfd
= -1;
84 for (i
= 0; i
< nfds
; ++i
)
87 if (readfds
!= NULL
&& FD_ISSET (i
, &rfds
))
89 if (writefds
!= NULL
&& FD_ISSET (i
, &wfds
))
91 if (exceptfds
!= NULL
&& FD_ISSET (i
, &xfds
))
96 cells
[i
] = _hurd_dtable
[i
];
97 ports
[i
] = _hurd_port_get (&cells
[i
]->port
, &ulink
[i
]);
98 if (ports
[i
] == MACH_PORT_NULL
)
100 /* If one descriptor is bogus, we fail completely. */
102 _hurd_port_free (&cells
[i
]->port
, &ulink
[i
], ports
[i
]);
112 __mutex_unlock (&_hurd_dtable_lock
);
118 /* Get a port to receive the io_select_reply messages on. */
119 port
= __mach_reply_port ();
121 /* Send them all io_select request messages. */
124 for (i
= firstfd
; i
<= lastfd
; ++i
)
131 err
= __io_select (ports
[i
], port
,
132 /* Poll for each but the last. */
133 (i
== lastfd
&& got
== 0) ? to
: 0,
137 case MACH_RCV_TIMED_OUT
:
138 /* No immediate response. This is normal. */
143 /* We got an answer. This is not necessarily the answer to
144 the query we sent just now. It may correspond to any
145 prior query which timed out before its answer arrived. */
146 if (tag
< 0 || tag
> i
|| (type
& SELECT_ALL
) == 0)
147 /* This is not a proper answer to any query we have yet
152 /* Some port is ready. TAG tells us which. */
154 types
[tag
] |= SELECT_RETURNED
;
160 /* Any other error kills us.
161 But we must continue to loop to free the ports. */
165 _hurd_port_free (&cells
[i
]->port
, &ulink
[i
], ports
[i
]);
168 /* Now wait for reply messages. */
169 if (!err
&& got
== 0 && port
!= MACH_PORT_NULL
)
171 /* Now wait for io_select_reply messages on PORT,
172 timing out as appropriate. */
176 mach_msg_header_t head
;
179 mach_msg_header_t head
;
180 mach_msg_type_t err_type
;
185 mach_msg_header_t head
;
186 mach_msg_type_t err_type
;
188 mach_msg_type_t result_type
;
190 mach_msg_type_t tag_type
;
194 mach_msg_option_t options
= (timeout
== NULL
? 0 : MACH_RCV_TIMEOUT
);
196 while ((msgerr
= __mach_msg (&msg
.head
,
197 MACH_RCV_MSG
| options
,
198 0, sizeof msg
, port
, to
,
199 MACH_PORT_NULL
)) == MACH_MSG_SUCCESS
)
201 /* We got a message. Decode it. */
202 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
203 const mach_msg_type_t inttype
=
204 { MACH_MSG_TYPE_INTEGER_32
, 32, 1, 1, 0, 0 };
205 if (msg
.head
.msgh_id
== IO_SELECT_REPLY_MSGID
&&
206 msg
.head
.msgh_size
>= sizeof msg
.error
&&
207 !(msg
.head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) &&
208 *(int *) &msg
.error
.err_type
== *(int *) &inttype
)
210 /* This is a properly formatted message so far.
211 See if it is a success or a failure. */
215 if (msg
.head
.msgh_size
!= sizeof msg
.error
)
216 __mach_msg_destroy (&msg
);
218 else if (msg
.head
.msgh_size
!= sizeof msg
.success
||
219 *(int *) &msg
.success
.tag_type
!= *(int *) &inttype
||
220 *(int *) &msg
.success
.result_type
!= *(int *) &inttype
)
221 __mach_msg_destroy (&msg
);
222 else if ((msg
.success
.result
& SELECT_ALL
) == 0 ||
223 msg
.success
.tag
< firstfd
|| msg
.success
.tag
> lastfd
)
227 /* This is a winning io_select_reply message!
228 Record the readiness it indicates and send a reply. */
229 types
[msg
.success
.tag
] &= msg
.success
.result
;
230 types
[msg
.success
.tag
] |= SELECT_RETURNED
;
235 if (msg
.head
.msgh_remote_port
!= MACH_PORT_NULL
)
236 __mach_port_deallocate (__mach_task_self (),
237 msg
.head
.msgh_remote_port
);
239 if (got
|| err
== EINTR
)
241 /* Poll for another message. */
243 options
|= MACH_RCV_TIMEOUT
;
247 if (err
== MACH_RCV_TIMED_OUT
)
248 /* This is the normal value for ERR. We might have timed out and
249 read no messages. Otherwise, after receiving the first message,
250 we poll for more messages. We receive with a timeout of 0 to
251 effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
255 if (got
&& err
== EINTR
)
256 /* Some calls were interrupted, but at least one descriptor
257 is known to be ready now, so we will return success. */
261 if (port
!= MACH_PORT_NULL
)
262 /* We must destroy the port if we made some select requests
263 that might send notification on that port after we no longer care.
264 If the port were reused, that notification could confuse the next
265 select call to use the port. The notification might be valid,
266 but the descriptor may have changed to a different server. */
267 __mach_port_destroy (__mach_task_self (), port
);
270 return __hurd_fail (err
);
272 /* Below we recalculate GOT to include an increment for each operation
273 allowed on each fd. */
276 /* Set the user bitarrays. We only ever have to clear bits, as all desired
277 ones are initially set. */
278 for (i
= firstfd
; i
<= lastfd
; ++i
)
282 if ((type
& SELECT_RETURNED
) == 0)
285 if (type
& SELECT_READ
)
289 if (type
& SELECT_WRITE
)
292 FD_CLR (i
, writefds
);
293 if (type
& SELECT_URG
)
296 FD_CLR (i
, exceptfds
);
302 weak_alias (__select
, select
)