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