Updated to fedora-glibc-20070117T0857
[kopensolaris-gnu/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   union typeword                /* Use this to avoid unkosher casts.  */
68     {
69       mach_msg_type_t type;
70       uint32_t word;
71     };
72   assert (sizeof (union typeword) == sizeof (mach_msg_type_t));
73   assert (sizeof (uint32_t) == sizeof (mach_msg_type_t));
74
75   if (sigmask && __sigprocmask (SIG_SETMASK, sigmask, &oset))
76     return -1;
77
78   if (pollfds)
79     {
80       /* Collect interesting descriptors from the user's `pollfd' array.
81          We do a first pass that reads the user's array before taking
82          any locks.  The second pass then only touches our own stack,
83          and gets the port references.  */
84
85       for (i = 0; i < nfds; ++i)
86         if (pollfds[i].fd >= 0)
87           {
88             int type = 0;
89             if (pollfds[i].events & POLLIN)
90               type |= SELECT_READ;
91             if (pollfds[i].events & POLLOUT)
92               type |= SELECT_WRITE;
93             if (pollfds[i].events & POLLPRI)
94               type |= SELECT_URG;
95
96             d[i].io_port = pollfds[i].fd;
97             d[i].type = type;
98           }
99         else
100           d[i].type = 0;
101
102       HURD_CRITICAL_BEGIN;
103       __mutex_lock (&_hurd_dtable_lock);
104
105       for (i = 0; i < nfds; ++i)
106         if (d[i].type != 0)
107           {
108             const int fd = (int) d[i].io_port;
109
110             if (fd < _hurd_dtablesize)
111               {
112                 d[i].cell = _hurd_dtable[fd];
113                 d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
114                 if (d[i].io_port != MACH_PORT_NULL)
115                   continue;
116               }
117
118             /* If one descriptor is bogus, we fail completely.  */
119             while (i-- > 0)
120               if (d[i].type != 0)
121                 _hurd_port_free (&d[i].cell->port,
122                                  &d[i].ulink, d[i].io_port);
123             break;
124           }
125
126       __mutex_unlock (&_hurd_dtable_lock);
127       HURD_CRITICAL_END;
128
129       if (i < nfds)
130         {
131           if (sigmask)
132             __sigprocmask (SIG_SETMASK, &oset, NULL);
133           errno = EBADF;
134           return -1;
135         }
136
137       lastfd = i - 1;
138       firstfd = i == 0 ? lastfd : 0;
139     }
140   else
141     {
142       /* Collect interested descriptors from the user's fd_set arguments.
143          Use local copies so we can't crash from user bogosity.  */
144
145       if (readfds == NULL)
146         FD_ZERO (&rfds);
147       else
148         rfds = *readfds;
149       if (writefds == NULL)
150         FD_ZERO (&wfds);
151       else
152         wfds = *writefds;
153       if (exceptfds == NULL)
154         FD_ZERO (&xfds);
155       else
156         xfds = *exceptfds;
157
158       HURD_CRITICAL_BEGIN;
159       __mutex_lock (&_hurd_dtable_lock);
160
161       if (nfds > _hurd_dtablesize)
162         nfds = _hurd_dtablesize;
163
164       /* Collect the ports for interesting FDs.  */
165       firstfd = lastfd = -1;
166       for (i = 0; i < nfds; ++i)
167         {
168           int type = 0;
169           if (readfds != NULL && FD_ISSET (i, &rfds))
170             type |= SELECT_READ;
171           if (writefds != NULL && FD_ISSET (i, &wfds))
172             type |= SELECT_WRITE;
173           if (exceptfds != NULL && FD_ISSET (i, &xfds))
174             type |= SELECT_URG;
175           d[i].type = type;
176           if (type)
177             {
178               d[i].cell = _hurd_dtable[i];
179               d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
180               if (d[i].io_port == MACH_PORT_NULL)
181                 {
182                   /* If one descriptor is bogus, we fail completely.  */
183                   while (i-- > 0)
184                     if (d[i].type != 0)
185                       _hurd_port_free (&d[i].cell->port, &d[i].ulink,
186                                        d[i].io_port);
187                   break;
188                 }
189               lastfd = i;
190               if (firstfd == -1)
191                 firstfd = i;
192             }
193         }
194
195       __mutex_unlock (&_hurd_dtable_lock);
196       HURD_CRITICAL_END;
197
198       if (i < nfds)
199         {
200           if (sigmask)
201             __sigprocmask (SIG_SETMASK, &oset, NULL);
202           errno = EBADF;
203           return -1;
204         }
205     }
206
207
208   err = 0;
209   got = 0;
210
211   /* Send them all io_select request messages.  */
212
213   if (firstfd == -1)
214     /* But not if there were no ports to deal with at all.
215        We are just a pure timeout.  */
216     portset = __mach_reply_port ();
217   else
218     {
219       portset = MACH_PORT_NULL;
220
221       for (i = firstfd; i <= lastfd; ++i)
222         if (d[i].type)
223           {
224             int type = d[i].type;
225             d[i].reply_port = __mach_reply_port ();
226             err = __io_select (d[i].io_port, d[i].reply_port,
227                                /* Poll only if there's a single descriptor.  */
228                                (firstfd == lastfd) ? to : 0,
229                                &type);
230             switch (err)
231               {
232               case MACH_RCV_TIMED_OUT:
233                 /* No immediate response.  This is normal.  */
234                 err = 0;
235                 if (firstfd == lastfd)
236                   /* When there's a single descriptor, we don't need a
237                      portset, so just pretend we have one, but really
238                      use the single reply port.  */
239                   portset = d[i].reply_port;
240                 else if (got == 0)
241                   /* We've got multiple reply ports, so we need a port set to
242                      multiplex them.  */
243                   {
244                     /* We will wait again for a reply later.  */
245                     if (portset == MACH_PORT_NULL)
246                       /* Create the portset to receive all the replies on.  */
247                       err = __mach_port_allocate (__mach_task_self (),
248                                                   MACH_PORT_RIGHT_PORT_SET,
249                                                   &portset);
250                     if (! err)
251                       /* Put this reply port in the port set.  */
252                       __mach_port_move_member (__mach_task_self (),
253                                                d[i].reply_port, portset);
254                   }
255                 break;
256
257               default:
258                 /* No other error should happen.  Callers of select
259                    don't expect to see errors, so we simulate
260                    readiness of the erring object and the next call
261                    hopefully will get the error again.  */
262                 type = SELECT_ALL;
263                 /* FALLTHROUGH */
264
265               case 0:
266                 /* We got an answer.  */
267                 if ((type & SELECT_ALL) == 0)
268                   /* Bogus answer; treat like an error, as a fake positive.  */
269                   type = SELECT_ALL;
270
271                 /* This port is already ready already.  */
272                 d[i].type &= type;
273                 d[i].type |= SELECT_RETURNED;
274                 ++got;
275                 break;
276               }
277             _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
278           }
279     }
280
281   /* Now wait for reply messages.  */
282   if (!err && got == 0)
283     {
284       /* Now wait for io_select_reply messages on PORT,
285          timing out as appropriate.  */
286
287       union
288         {
289           mach_msg_header_t head;
290 #ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
291           struct
292             {
293               mach_msg_header_t head;
294               NDR_record_t ndr;
295               error_t err;
296             } error;
297           struct
298             {
299               mach_msg_header_t head;
300               NDR_record_t ndr;
301               error_t err;
302               int result;
303               mach_msg_trailer_t trailer;
304             } success;
305 #else
306           struct
307             {
308               mach_msg_header_t head;
309               union typeword err_type;
310               error_t err;
311             } error;
312           struct
313             {
314               mach_msg_header_t head;
315               union typeword err_type;
316               error_t err;
317               union typeword result_type;
318               int result;
319             } success;
320 #endif
321         } msg;
322       mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
323       error_t msgerr;
324       while ((msgerr = __mach_msg (&msg.head,
325                                    MACH_RCV_MSG | options,
326                                    0, sizeof msg, portset, to,
327                                    MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
328         {
329           /* We got a message.  Decode it.  */
330 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
331 #ifdef MACH_MSG_TYPE_BIT
332           const union typeword inttype =
333           { type:
334             { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8, 1, 1, 0, 0 }
335           };
336 #endif
337           if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
338               msg.head.msgh_size >= sizeof msg.error &&
339               !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
340 #ifdef MACH_MSG_TYPE_BIT
341               msg.error.err_type.word == inttype.word
342 #endif
343               )
344             {
345               /* This is a properly formatted message so far.
346                  See if it is a success or a failure.  */
347               if (msg.error.err == EINTR &&
348                   msg.head.msgh_size == sizeof msg.error)
349                 {
350                   /* EINTR response; poll for further responses
351                      and then return quickly.  */
352                   err = EINTR;
353                   goto poll;
354                 }
355               if (msg.error.err ||
356                   msg.head.msgh_size != sizeof msg.success ||
357 #ifdef MACH_MSG_TYPE_BIT
358                   msg.success.result_type.word != inttype.word ||
359 #endif
360                   (msg.success.result & SELECT_ALL) == 0)
361                 {
362                   /* Error or bogus reply.  Simulate readiness.  */
363                   __mach_msg_destroy (&msg.head);
364                   msg.success.result = SELECT_ALL;
365                 }
366
367               /* Look up the respondent's reply port and record its
368                  readiness.  */
369               {
370                 int had = got;
371                 if (firstfd != -1)
372                   for (i = firstfd; i <= lastfd; ++i)
373                     if (d[i].type
374                         && d[i].reply_port == msg.head.msgh_local_port)
375                       {
376                         d[i].type &= msg.success.result;
377                         d[i].type |= SELECT_RETURNED;
378                         ++got;
379                       }
380                 assert (got > had);
381               }
382             }
383
384           if (msg.head.msgh_remote_port != MACH_PORT_NULL)
385             __mach_port_deallocate (__mach_task_self (),
386                                     msg.head.msgh_remote_port);
387
388           if (got)
389           poll:
390             {
391               /* Poll for another message.  */
392               to = 0;
393               options |= MACH_RCV_TIMEOUT;
394             }
395         }
396
397       if (err == MACH_RCV_TIMED_OUT)
398         /* This is the normal value for ERR.  We might have timed out and
399            read no messages.  Otherwise, after receiving the first message,
400            we poll for more messages.  We receive with a timeout of 0 to
401            effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
402            message waiting.  */
403         err = 0;
404
405       if (got)
406         /* At least one descriptor is known to be ready now, so we will
407            return success.  */
408         err = 0;
409     }
410
411   if (firstfd != -1)
412     for (i = firstfd; i <= lastfd; ++i)
413       if (d[i].type)
414         __mach_port_destroy (__mach_task_self (), d[i].reply_port);
415   if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
416     /* Destroy PORTSET, but only if it's not actually the reply port for a
417        single descriptor (in which case it's destroyed in the previous loop;
418        not doing it here is just a bit more efficient).  */
419     __mach_port_destroy (__mach_task_self (), portset);
420
421   if (err)
422     {
423       if (sigmask)
424         __sigprocmask (SIG_SETMASK, &oset, NULL);
425       return __hurd_fail (err);
426     }
427
428   if (pollfds)
429     /* Fill in the `revents' members of the user's array.  */
430     for (i = 0; i < nfds; ++i)
431       {
432         int type = d[i].type;
433         int_fast16_t revents = 0;
434
435         if (type & SELECT_RETURNED)
436           {
437             if (type & SELECT_READ)
438               revents |= POLLIN;
439             if (type & SELECT_WRITE)
440               revents |= POLLOUT;
441             if (type & SELECT_URG)
442               revents |= POLLPRI;
443           }
444
445         pollfds[i].revents = revents;
446       }
447   else
448     {
449       /* Below we recalculate GOT to include an increment for each operation
450          allowed on each fd.  */
451       got = 0;
452
453       /* Set the user bitarrays.  We only ever have to clear bits, as all
454          desired ones are initially set.  */
455       if (firstfd != -1)
456         for (i = firstfd; i <= lastfd; ++i)
457           {
458             int type = d[i].type;
459
460             if ((type & SELECT_RETURNED) == 0)
461               type = 0;
462
463             if (type & SELECT_READ)
464               got++;
465             else if (readfds)
466               FD_CLR (i, readfds);
467             if (type & SELECT_WRITE)
468               got++;
469             else if (writefds)
470               FD_CLR (i, writefds);
471             if (type & SELECT_URG)
472               got++;
473             else if (exceptfds)
474               FD_CLR (i, exceptfds);
475           }
476     }
477
478   if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
479     return -1;
480
481   return got;
482 }