88
99#include <wasi/api.h>
1010#include <errno.h>
11+ #include <poll.h>
1112
1213int pselect (int nfds , fd_set * restrict readfds , fd_set * restrict writefds ,
1314 fd_set * restrict errorfds , const struct timespec * restrict timeout ,
@@ -33,93 +34,66 @@ int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
3334 if (writefds == NULL )
3435 writefds = & empty ;
3536
36- // Determine the maximum number of events.
37- size_t maxevents = readfds -> __nfds + writefds -> __nfds + 1 ;
38- __wasi_subscription_t subscriptions [maxevents ];
39- size_t nsubscriptions = 0 ;
40-
41- // Convert the readfds set.
37+ struct pollfd poll_fds [readfds -> __nfds + writefds -> __nfds ];
38+ size_t poll_nfds = 0 ;
39+
4240 for (size_t i = 0 ; i < readfds -> __nfds ; ++ i ) {
4341 int fd = readfds -> __fds [i ];
4442 if (fd < nfds ) {
45- __wasi_subscription_t * subscription = & subscriptions [nsubscriptions ++ ];
46- * subscription = (__wasi_subscription_t ){
47- .userdata = fd ,
48- .u .tag = __WASI_EVENTTYPE_FD_READ ,
49- .u .u .fd_read .file_descriptor = fd ,
50- };
43+ poll_fds [poll_nfds ++ ] = (struct pollfd ){
44+ .fd = fd ,
45+ .events = POLLRDNORM ,
46+ .revents = 0
47+ };
5148 }
5249 }
53-
54- // Convert the writefds set.
50+
5551 for (size_t i = 0 ; i < writefds -> __nfds ; ++ i ) {
5652 int fd = writefds -> __fds [i ];
5753 if (fd < nfds ) {
58- __wasi_subscription_t * subscription = & subscriptions [nsubscriptions ++ ];
59- * subscription = (__wasi_subscription_t ){
60- .userdata = fd ,
61- .u .tag = __WASI_EVENTTYPE_FD_WRITE ,
62- .u .u .fd_write .file_descriptor = fd ,
54+ poll_fds [poll_nfds ++ ] = (struct pollfd ){
55+ .fd = fd ,
56+ .events = POLLWRNORM ,
57+ .revents = 0
6358 };
6459 }
6560 }
6661
67- // Create extra event for the timeout.
68- if (timeout != NULL ) {
69- __wasi_subscription_t * subscription = & subscriptions [nsubscriptions ++ ];
70- * subscription = (__wasi_subscription_t ){
71- .u .tag = __WASI_EVENTTYPE_CLOCK ,
72- .u .u .clock .id = __WASI_CLOCKID_REALTIME ,
73- };
74- if (!timespec_to_timestamp_clamp (timeout , & subscription -> u .u .clock .timeout )) {
62+ int poll_timeout ;
63+ if (timeout ) {
64+ uint64_t timeout_u64 ;
65+ if (!timespec_to_timestamp_clamp (timeout , & timeout_u64 ) ) {
7566 errno = EINVAL ;
7667 return -1 ;
7768 }
78- }
7969
80- // Execute poll().
81- size_t nevents ;
82- __wasi_event_t events [nsubscriptions ];
83- __wasi_errno_t error =
84- __wasi_poll_oneoff (subscriptions , events , nsubscriptions , & nevents );
85- if (error != 0 ) {
86- // WASI's poll requires at least one subscription, or else it returns
87- // `EINVAL`. Since a `pselect` with nothing to wait for is valid in POSIX,
88- // return `ENOTSUP` to indicate that we don't support that case.
89- //
90- // Wasm has no signal handling, so if none of the user-provided `pollfd`
91- // elements, nor the timeout, led us to producing even one subscription
92- // to wait for, there would be no way for the poll to wake up. WASI
93- // returns `EINVAL` in this case, but for users of `poll`, `ENOTSUP` is
94- // more likely to be understood.
95- if (nsubscriptions == 0 )
96- errno = ENOTSUP ;
97- else
98- errno = error ;
99- return -1 ;
100- }
70+ // Convert nanoseconds to milliseconds:
71+ timeout_u64 /= 1000000 ;
10172
102- // Test for EBADF.
103- for (size_t i = 0 ; i < nevents ; ++ i ) {
104- const __wasi_event_t * event = & events [i ];
105- if ((event -> type == __WASI_EVENTTYPE_FD_READ ||
106- event -> type == __WASI_EVENTTYPE_FD_WRITE ) &&
107- event -> error == __WASI_ERRNO_BADF ) {
108- errno = EBADF ;
109- return -1 ;
73+ if (timeout_u64 > INT_MAX ) {
74+ timeout_u64 = INT_MAX ;
11075 }
76+
77+ poll_timeout = (int ) timeout_u64 ;
78+ } else {
79+ poll_timeout = -1 ;
80+ };
81+
82+ if (poll (poll_fds , poll_nfds , poll_timeout ) < 0 ) {
83+ return -1 ;
11184 }
11285
113- // Clear and set entries in the result sets.
11486 FD_ZERO (readfds );
11587 FD_ZERO (writefds );
116- for (size_t i = 0 ; i < nevents ; ++ i ) {
117- const __wasi_event_t * event = & events [i ];
118- if (event -> type == __WASI_EVENTTYPE_FD_READ ) {
119- readfds -> __fds [readfds -> __nfds ++ ] = event -> userdata ;
120- } else if (event -> type == __WASI_EVENTTYPE_FD_WRITE ) {
121- writefds -> __fds [writefds -> __nfds ++ ] = event -> userdata ;
88+ for (size_t i = 0 ; i < poll_nfds ; ++ i ) {
89+ struct pollfd * pollfd = poll_fds + i ;
90+ if ((pollfd -> revents & POLLRDNORM ) != 0 ) {
91+ readfds -> __fds [readfds -> __nfds ++ ] = pollfd -> fd ;
92+ }
93+ if ((pollfd -> revents & POLLWRNORM ) != 0 ) {
94+ writefds -> __fds [writefds -> __nfds ++ ] = pollfd -> fd ;
12295 }
12396 }
97+
12498 return readfds -> __nfds + writefds -> __nfds ;
12599}
0 commit comments