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)
211