|
35 | 35 | #include "libc/sysv/consts/sig.h"
|
36 | 36 | #include "libc/sysv/errfuns.h"
|
37 | 37 |
|
38 |
| -/** |
39 |
| - * Checks status on multiple file descriptors at once. |
40 |
| - * |
41 |
| - * This function is the same as saying: |
42 |
| - * |
43 |
| - * sigset_t old; |
44 |
| - * sigprocmask(SIG_SETMASK, sigmask, &old); |
45 |
| - * poll(fds, nfds, timeout); |
46 |
| - * sigprocmask(SIG_SETMASK, old, 0); |
47 |
| - * |
48 |
| - * Except it happens atomically when the kernel supports doing that. On |
49 |
| - * kernels such as XNU and NetBSD which don't, this wrapper will fall |
50 |
| - * back to using the example above. If you need ironclad assurances of |
51 |
| - * signal mask atomicity, then consider using pselect() which Cosmo Libc |
52 |
| - * guarantees to be atomic on all supported platforms. |
53 |
| - * |
54 |
| - * Servers that need to handle an unbounded number of client connections |
55 |
| - * should just create a separate thread for each client. poll(), ppoll() |
56 |
| - * and select() aren't scalable i/o solutions on any platform. |
57 |
| - * |
58 |
| - * On Windows it's only possible to poll 64 file descriptors at a time; |
59 |
| - * it's a limitation imposed by WSAPoll(). Cosmopolitan Libc's ppoll() |
60 |
| - * polyfill can go higher in some cases; for example, It's possible to |
61 |
| - * poll 64 sockets and 64 pipes/terminals at the same time. Furthermore, |
62 |
| - * elements whose fd field is set to a negative number are ignored and |
63 |
| - * will not count against this limit. |
64 |
| - * |
65 |
| - * One of the use cases for poll() is to quickly check if a number of |
66 |
| - * file descriptors are valid. The canonical way to do this is to set |
67 |
| - * events to 0 which prevents blocking and causes only the invalid, |
68 |
| - * hangup, and error statuses to be checked. |
69 |
| - * |
70 |
| - * On XNU, the POLLHUP and POLLERR statuses aren't checked unless either |
71 |
| - * POLLIN, POLLOUT, or POLLPRI are specified in the events field. Cosmo |
72 |
| - * will however polyfill the checking of POLLNVAL on XNU with the events |
73 |
| - * doesn't specify any of the above i/o events. |
74 |
| - * |
75 |
| - * When XNU and BSD OSes report POLLHUP, they will always set POLLIN too |
76 |
| - * when POLLIN is requested, even in cases when there isn't unread data. |
77 |
| - * |
78 |
| - * @param fds[𝑖].fd should be a socket, input pipe, or conosle input |
79 |
| - * and if it's a negative number then the entry is ignored, plus |
80 |
| - * revents will be set to zero |
81 |
| - * @param fds[𝑖].events flags can have POLLIN, POLLOUT, POLLPRI, |
82 |
| - * POLLRDNORM, POLLWRNORM, POLLRDBAND, POLLWRBAND as well as |
83 |
| - * POLLERR, POLLHUP, and POLLNVAL although the latter are |
84 |
| - * always implied (assuming fd≥0) so they're ignored here |
85 |
| - * @param timeout_ms if 0 means don't wait and negative waits forever |
86 |
| - * @return number of `fds` whose revents field has been set to a nonzero |
87 |
| - * number, 0 if the timeout elapsed without events, or -1 w/ errno |
88 |
| - * @return fds[𝑖].revents is always zero initializaed and then will |
89 |
| - * be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something |
90 |
| - * was determined about the file descriptor |
91 |
| - * @param timeout if null will block indefinitely |
92 |
| - * @param sigmask may be null in which case no mask change happens |
93 |
| - * @raise EINVAL if we exceeded the 64 socket limit on Windows |
94 |
| - * @raise ECANCELED if thread was cancelled in masked mode |
95 |
| - * @raise EINVAL if `nfds` exceeded `RLIMIT_NOFILE` |
96 |
| - * @raise ENOMEM on failure to allocate memory |
97 |
| - * @raise EINVAL if `*timeout` is invalid |
98 |
| - * @raise EINTR if signal was delivered |
99 |
| - * @cancelationpoint |
100 |
| - * @asyncsignalsafe |
101 |
| - * @norestart |
102 |
| - */ |
103 |
| -int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout, |
104 |
| - const sigset_t *sigmask) { |
| 38 | +static int ppoll_impl(struct pollfd *fds, size_t nfds, |
| 39 | + const struct timespec *timeout, const sigset_t *sigmask) { |
105 | 40 | int e, fdcount;
|
106 | 41 | sigset_t oldmask;
|
107 | 42 | struct timespec ts, *tsp;
|
108 |
| - BEGIN_CANCELATION_POINT; |
109 | 43 |
|
110 | 44 | // validate timeout
|
111 |
| - if (timeout && timeout->tv_nsec >= 1000000000) |
| 45 | + if (timeout && timeout->tv_nsec >= 1000000000ull) |
112 | 46 | return einval();
|
113 | 47 |
|
114 | 48 | // The OpenBSD poll() man pages claims it'll ignore POLLERR, POLLHUP,
|
@@ -192,6 +126,78 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
|
192 | 126 | }
|
193 | 127 | }
|
194 | 128 |
|
| 129 | + return fdcount; |
| 130 | +} |
| 131 | + |
| 132 | +/** |
| 133 | + * Checks status on multiple file descriptors at once. |
| 134 | + * |
| 135 | + * This function is the same as saying: |
| 136 | + * |
| 137 | + * sigset_t old; |
| 138 | + * sigprocmask(SIG_SETMASK, sigmask, &old); |
| 139 | + * poll(fds, nfds, timeout); |
| 140 | + * sigprocmask(SIG_SETMASK, old, 0); |
| 141 | + * |
| 142 | + * Except it happens atomically when the kernel supports doing that. On |
| 143 | + * kernels such as XNU and NetBSD which don't, this wrapper will fall |
| 144 | + * back to using the example above. If you need ironclad assurances of |
| 145 | + * signal mask atomicity, then consider using pselect() which Cosmo Libc |
| 146 | + * guarantees to be atomic on all supported platforms. |
| 147 | + * |
| 148 | + * Servers that need to handle an unbounded number of client connections |
| 149 | + * should just create a separate thread for each client. poll(), ppoll() |
| 150 | + * and select() aren't scalable i/o solutions on any platform. |
| 151 | + * |
| 152 | + * On Windows it's only possible to poll 64 file descriptors at a time; |
| 153 | + * it's a limitation imposed by WSAPoll(). Cosmopolitan Libc's ppoll() |
| 154 | + * polyfill can go higher in some cases; for example, It's possible to |
| 155 | + * poll 64 sockets and 64 pipes/terminals at the same time. Furthermore, |
| 156 | + * elements whose fd field is set to a negative number are ignored and |
| 157 | + * will not count against this limit. |
| 158 | + * |
| 159 | + * One of the use cases for poll() is to quickly check if a number of |
| 160 | + * file descriptors are valid. The canonical way to do this is to set |
| 161 | + * events to 0 which prevents blocking and causes only the invalid, |
| 162 | + * hangup, and error statuses to be checked. |
| 163 | + * |
| 164 | + * On XNU, the POLLHUP and POLLERR statuses aren't checked unless either |
| 165 | + * POLLIN, POLLOUT, or POLLPRI are specified in the events field. Cosmo |
| 166 | + * will however polyfill the checking of POLLNVAL on XNU with the events |
| 167 | + * doesn't specify any of the above i/o events. |
| 168 | + * |
| 169 | + * When XNU and BSD OSes report POLLHUP, they will always set POLLIN too |
| 170 | + * when POLLIN is requested, even in cases when there isn't unread data. |
| 171 | + * |
| 172 | + * @param fds[𝑖].fd should be a socket, input pipe, or conosle input |
| 173 | + * and if it's a negative number then the entry is ignored, plus |
| 174 | + * revents will be set to zero |
| 175 | + * @param fds[𝑖].events flags can have POLLIN, POLLOUT, POLLPRI, |
| 176 | + * POLLRDNORM, POLLWRNORM, POLLRDBAND, POLLWRBAND as well as |
| 177 | + * POLLERR, POLLHUP, and POLLNVAL although the latter are |
| 178 | + * always implied (assuming fd≥0) so they're ignored here |
| 179 | + * @param timeout_ms if 0 means don't wait and negative waits forever |
| 180 | + * @return number of `fds` whose revents field has been set to a nonzero |
| 181 | + * number, 0 if the timeout elapsed without events, or -1 w/ errno |
| 182 | + * @return fds[𝑖].revents is always zero initializaed and then will |
| 183 | + * be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something |
| 184 | + * was determined about the file descriptor |
| 185 | + * @param timeout if null will block indefinitely |
| 186 | + * @param sigmask may be null in which case no mask change happens |
| 187 | + * @raise ECANCELED if thread was cancelled in masked mode |
| 188 | + * @raise EINVAL if `nfds` exceeded `RLIMIT_NOFILE` |
| 189 | + * @raise ENOMEM on failure to allocate memory |
| 190 | + * @raise EINVAL if `*timeout` is invalid |
| 191 | + * @raise EINTR if signal was delivered |
| 192 | + * @cancelationpoint |
| 193 | + * @asyncsignalsafe |
| 194 | + * @norestart |
| 195 | + */ |
| 196 | +int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout, |
| 197 | + const sigset_t *sigmask) { |
| 198 | + int fdcount; |
| 199 | + BEGIN_CANCELATION_POINT; |
| 200 | + fdcount = ppoll_impl(fds, nfds, timeout, sigmask); |
195 | 201 | END_CANCELATION_POINT;
|
196 | 202 | STRACE("ppoll(%s, %'zu, %s, %s) → %d% lm",
|
197 | 203 | DescribePollFds(fdcount, fds, nfds), nfds,
|
|
0 commit comments