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