2002-01-02 Roland McGrath <roland@frob.com>
[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   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           struct
283             {
284               mach_msg_header_t head;
285               mach_msg_type_t err_type;
286               error_t err;
287             } error;
288           struct
289             {
290               mach_msg_header_t head;
291               mach_msg_type_t err_type;
292               error_t err;
293               mach_msg_type_t result_type;
294               int result;
295             } success;
296         } msg;
297       mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
298       error_t msgerr;
299       while ((msgerr = __mach_msg (&msg.head,
300                                    MACH_RCV_MSG | options,
301                                    0, sizeof msg, portset, to,
302                                    MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
303         {
304           /* We got a message.  Decode it.  */
305 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
306           const mach_msg_type_t inttype =
307             { MACH_MSG_TYPE_INTEGER_T, sizeof (MACH_MSG_TYPE_INTEGER_T) * 8,
308               1, 1, 0, 0 };
309           if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
310               msg.head.msgh_size >= sizeof msg.error &&
311               !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
312               *(int *) &msg.error.err_type == *(int *) &inttype)
313             {
314               /* This is a properly formatted message so far.
315                  See if it is a success or a failure.  */
316               if (msg.error.err == EINTR &&
317                   msg.head.msgh_size == sizeof msg.error)
318                 {
319                   /* EINTR response; poll for further responses
320                      and then return quickly.  */
321                   err = EINTR;
322                   goto poll;
323                 }
324               if (msg.error.err ||
325                   msg.head.msgh_size != sizeof msg.success ||
326                   *(int *) &msg.success.result_type != *(int *) &inttype ||
327                   (msg.success.result & SELECT_ALL) == 0)
328                 {
329                   /* Error or bogus reply.  Simulate readiness.  */
330                   __mach_msg_destroy (&msg.head);
331                   msg.success.result = SELECT_ALL;
332                 }
333
334               /* Look up the respondent's reply port and record its
335                  readiness.  */
336               {
337                 int had = got;
338                 if (firstfd != -1)
339                   for (i = firstfd; i <= lastfd; ++i)
340                     if (d[i].type
341                         && d[i].reply_port == msg.head.msgh_local_port)
342                       {
343                         d[i].type &= msg.success.result;
344                         d[i].type |= SELECT_RETURNED;
345                         ++got;
346                       }
347                 assert (got > had);
348               }
349             }
350
351           if (msg.head.msgh_remote_port != MACH_PORT_NULL)
352             __mach_port_deallocate (__mach_task_self (),
353                                     msg.head.msgh_remote_port);
354
355           if (got)
356           poll:
357             {
358               /* Poll for another message.  */
359               to = 0;
360               options |= MACH_RCV_TIMEOUT;
361             }
362         }
363
364       if (err == MACH_RCV_TIMED_OUT)
365         /* This is the normal value for ERR.  We might have timed out and
366            read no messages.  Otherwise, after receiving the first message,
367            we poll for more messages.  We receive with a timeout of 0 to
368            effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
369            message waiting.  */
370         err = 0;
371
372       if (got)
373         /* At least one descriptor is known to be ready now, so we will
374            return success.  */
375         err = 0;
376     }
377
378   if (firstfd != -1)
379     for (i = firstfd; i <= lastfd; ++i)
380       if (d[i].type)
381         __mach_port_destroy (__mach_task_self (), d[i].reply_port);
382   if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
383     /* Destroy PORTSET, but only if it's not actually the reply port for a
384        single descriptor (in which case it's destroyed in the previous loop;
385        not doing it here is just a bit more efficient).  */
386     __mach_port_destroy (__mach_task_self (), portset);
387
388   if (err)
389     {
390       if (sigmask)
391         __sigprocmask (SIG_SETMASK, &oset, NULL);
392       return __hurd_fail (err);
393     }
394
395   if (pollfds)
396     /* Fill in the `revents' members of the user's array.  */
397     for (i = 0; i < nfds; ++i)
398       {
399         int type = d[i].type;
400         int_fast16_t revents = 0;
401
402         if (type & SELECT_RETURNED)
403           {
404             if (type & SELECT_READ)
405               revents |= POLLIN;
406             if (type & SELECT_WRITE)
407               revents |= POLLOUT;
408             if (type & SELECT_URG)
409               revents |= POLLPRI;
410           }
411
412         pollfds[i].revents = revents;
413       }
414   else
415     {
416       /* Below we recalculate GOT to include an increment for each operation
417          allowed on each fd.  */
418       got = 0;
419
420       /* Set the user bitarrays.  We only ever have to clear bits, as all
421          desired ones are initially set.  */
422       if (firstfd != -1)
423         for (i = firstfd; i <= lastfd; ++i)
424           {
425             int type = d[i].type;
426
427             if ((type & SELECT_RETURNED) == 0)
428               type = 0;
429
430             if (type & SELECT_READ)
431               got++;
432             else if (readfds)
433               FD_CLR (i, readfds);
434             if (type & SELECT_WRITE)
435               got++;
436             else if (writefds)
437               FD_CLR (i, writefds);
438             if (type & SELECT_URG)
439               got++;
440             else if (exceptfds)
441               FD_CLR (i, exceptfds);
442           }
443     }
444
445   if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
446     return -1;
447
448   return got;
449 }