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