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