]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/sysdeps/linux/common/poll.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / sysdeps / linux / common / poll.c
1 /* Copyright (C) 1994,1996,1997,1998,1999,2001,2002
2    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, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <sys/syscall.h>
20 #include <sys/poll.h>
21 #include <bits/kernel-features.h>
22 #include <cancel.h>
23
24 #if defined __ASSUME_POLL_SYSCALL && defined __NR_poll
25
26 #define __NR___poll_nocancel __NR_poll
27 static _syscall3(int, __NC(poll), struct pollfd *, fds,
28                  unsigned long int, nfds, int, timeout)
29
30 #else /* !__NR_poll */
31
32 #include <alloca.h>
33 #include <sys/types.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <sys/param.h>
38 #include <unistd.h>
39 #include <sys/select.h>
40
41 /* uClinux 2.0 doesn't have poll, emulate it using select */
42
43 /* Poll the file descriptors described by the NFDS structures starting at
44    FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
45    an event to occur; if TIMEOUT is -1, block until an event occurs.
46    Returns the number of file descriptors with events, zero if timed out,
47    or -1 for errors.  */
48
49 int __NC(poll)(struct pollfd *fds, nfds_t nfds, int timeout)
50 {
51     static int max_fd_size;
52     struct timeval tv;
53     fd_set *rset, *wset, *xset;
54     struct pollfd *f;
55     int ready;
56     int maxfd = 0;
57     int bytes;
58
59     if (!max_fd_size)
60         max_fd_size = getdtablesize ();
61
62     bytes = howmany (max_fd_size, __NFDBITS);
63     rset = alloca (bytes);
64     wset = alloca (bytes);
65     xset = alloca (bytes);
66
67     /* We can't call FD_ZERO, since FD_ZERO only works with sets
68        of exactly __FD_SETSIZE size.  */
69     memset (rset, 0, bytes);
70     memset (wset, 0, bytes);
71     memset (xset, 0, bytes);
72
73     for (f = fds; f < &fds[nfds]; ++f)
74     {
75         f->revents = 0;
76         if (f->fd >= 0)
77         {
78             if (f->fd >= max_fd_size)
79             {
80                 /* The user provides a file descriptor number which is higher
81                    than the maximum we got from the `getdtablesize' call.
82                    Maybe this is ok so enlarge the arrays.  */
83                 fd_set *nrset, *nwset, *nxset;
84                 int nbytes;
85
86                 max_fd_size = roundup (f->fd, __NFDBITS);
87                 nbytes = howmany (max_fd_size, __NFDBITS);
88
89                 nrset = alloca (nbytes);
90                 nwset = alloca (nbytes);
91                 nxset = alloca (nbytes);
92
93                 memset ((char *) nrset + bytes, 0, nbytes - bytes);
94                 memset ((char *) nwset + bytes, 0, nbytes - bytes);
95                 memset ((char *) nxset + bytes, 0, nbytes - bytes);
96
97                 rset = memcpy (nrset, rset, bytes);
98                 wset = memcpy (nwset, wset, bytes);
99                 xset = memcpy (nxset, xset, bytes);
100
101                 bytes = nbytes;
102             }
103
104             if (f->events & POLLIN)
105                 FD_SET (f->fd, rset);
106             if (f->events & POLLOUT)
107                 FD_SET (f->fd, wset);
108             if (f->events & POLLPRI)
109                 FD_SET (f->fd, xset);
110             if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
111                 maxfd = f->fd;
112         }
113     }
114
115     tv.tv_sec = timeout / 1000;
116     tv.tv_usec = (timeout % 1000) * 1000;
117
118     while (1)
119     {
120         ready = __NC(select) (maxfd + 1, rset, wset, xset,
121                 timeout == -1 ? NULL : &tv);
122
123         /* It might be that one or more of the file descriptors is invalid.
124            We now try to find and mark them and then try again.  */
125         if (ready == -1 && errno == EBADF)
126         {
127             fd_set *sngl_rset = alloca (bytes);
128             fd_set *sngl_wset = alloca (bytes);
129             fd_set *sngl_xset = alloca (bytes);
130             struct timeval sngl_tv;
131
132             /* Clear the original set.  */
133             memset (rset, 0, bytes);
134             memset (wset, 0, bytes);
135             memset (xset, 0, bytes);
136
137             /* This means we don't wait for input.  */
138             sngl_tv.tv_sec = 0;
139             sngl_tv.tv_usec = 0;
140
141             maxfd = -1;
142
143             /* Reset the return value.  */
144             ready = 0;
145
146             for (f = fds; f < &fds[nfds]; ++f)
147                 if (f->fd != -1 && (f->events & (POLLIN|POLLOUT|POLLPRI))
148                         && (f->revents & POLLNVAL) == 0)
149                 {
150                     int n;
151
152                     memset (sngl_rset, 0, bytes);
153                     memset (sngl_wset, 0, bytes);
154                     memset (sngl_xset, 0, bytes);
155
156                     if (f->events & POLLIN)
157                         FD_SET (f->fd, sngl_rset);
158                     if (f->events & POLLOUT)
159                         FD_SET (f->fd, sngl_wset);
160                     if (f->events & POLLPRI)
161                         FD_SET (f->fd, sngl_xset);
162
163                     n = __NC(select) (f->fd + 1, sngl_rset, sngl_wset, sngl_xset,
164                             &sngl_tv);
165                     if (n != -1)
166                     {
167                         /* This descriptor is ok.  */
168                         if (f->events & POLLIN)
169                             FD_SET (f->fd, rset);
170                         if (f->events & POLLOUT)
171                             FD_SET (f->fd, wset);
172                         if (f->events & POLLPRI)
173                             FD_SET (f->fd, xset);
174                         if (f->fd > maxfd)
175                             maxfd = f->fd;
176                         if (n > 0)
177                             /* Count it as being available.  */
178                             ++ready;
179                     }
180                     else if (errno == EBADF)
181                         f->revents |= POLLNVAL;
182                 }
183             /* Try again.  */
184             continue;
185         }
186
187         break;
188     }
189
190     if (ready > 0)
191         for (f = fds; f < &fds[nfds]; ++f)
192         {
193             if (f->fd >= 0)
194             {
195                 if (FD_ISSET (f->fd, rset))
196                     f->revents |= POLLIN;
197                 if (FD_ISSET (f->fd, wset))
198                     f->revents |= POLLOUT;
199                 if (FD_ISSET (f->fd, xset))
200                     f->revents |= POLLPRI;
201             }
202         }
203
204     return ready;
205 }
206
207 #endif
208 CANCELLABLE_SYSCALL(int, poll, (struct pollfd *fds, nfds_t nfds, int timeout),
209                     (fds, nfds, timeout))
210 lt_libc_hidden(poll)