Skip to content

Commit f371289

Browse files
committed
Implement select. (#1162)
* Implement `select`. Add a `select` function, defined only on platforms where it doesn't have an `FD_SETSIZE` limitation. * Fix test hangs on macos. In the `waitpid` tests, ensure that the child process has exited, as dropping `Command` otherwise leaves the process running. This fixes test hangs on macos. * Wait for the child process after signaling it. * Fix the vector sizes in the test. * Add `fd_set` and other convenience functions. * Switch to a safe API. * Support `select` on Linux and Windows too. This uses a trick where we still allow users to allocate a `FdSetElement` array, but we just allocate a `FD_SET` on Windows out of it. And make `select` unsafe due to I/O safety. * Fix qemu to implment arbitrary-sized fd sets for `select`. * Support WASI. * Ignore "unstable name collisions" warnings for now.
1 parent 181f640 commit f371289

File tree

18 files changed

+1413
-13
lines changed

18 files changed

+1413
-13
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ jobs:
486486
patch -p1 < $GITHUB_WORKSPACE/ci/tiocgsid.patch
487487
patch -p1 < $GITHUB_WORKSPACE/ci/more-sockopts.patch
488488
patch -p1 < $GITHUB_WORKSPACE/ci/pidfd-open.patch
489+
patch -p1 < $GITHUB_WORKSPACE/ci/select-setsize.patch
489490
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
490491
ninja -C build install
491492
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -624,6 +625,7 @@ jobs:
624625
patch -p1 < $GITHUB_WORKSPACE/ci/tiocgsid.patch
625626
patch -p1 < $GITHUB_WORKSPACE/ci/more-sockopts.patch
626627
patch -p1 < $GITHUB_WORKSPACE/ci/pidfd-open.patch
628+
patch -p1 < $GITHUB_WORKSPACE/ci/select-setsize.patch
627629
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
628630
ninja -C build install
629631
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -718,6 +720,7 @@ jobs:
718720
patch -p1 < $GITHUB_WORKSPACE/ci/tiocgsid.patch
719721
patch -p1 < $GITHUB_WORKSPACE/ci/more-sockopts.patch
720722
patch -p1 < $GITHUB_WORKSPACE/ci/pidfd-open.patch
723+
patch -p1 < $GITHUB_WORKSPACE/ci/select-setsize.patch
721724
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
722725
ninja -C build install
723726
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'

ci/select-setsize.patch

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
From Dan Gohman <[email protected]>
2+
Subject: [PATCH] Remove the `FD_SETSIZE` limitation in `select`
3+
4+
The `fd_set` type is limited to a fixed `FD_SETSIZE` number of file
5+
descriptors, however Linux's `select has no such limitation. Change
6+
the `select` implementation to using manual bit-vector logic to better
7+
implement the Linux semantics.
8+
9+
diff -ur a/linux-user/syscall.c b/linux-user/syscall.c
10+
--- a/linux-user/syscall.c
11+
+++ b/linux-user/syscall.c
12+
@@ -664,8 +664,9 @@
13+
char **, argv, char **, envp, int, flags)
14+
#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \
15+
defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
16+
-safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
17+
- fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
18+
+safe_syscall6(int, pselect6, int, nfds, unsigned long *, readfds, \
19+
+ unsigned long *, writefds, unsigned long *, exceptfds, \
20+
+ struct timespec *, timeout, void *, sig)
21+
#endif
22+
#if defined(TARGET_NR_ppoll) || defined(TARGET_NR_ppoll_time64)
23+
safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
24+
@@ -861,7 +862,7 @@
25+
26+
#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \
27+
defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64)
28+
-static inline abi_long copy_from_user_fdset(fd_set *fds,
29+
+static inline abi_long copy_from_user_fdset(unsigned long *fds,
30+
abi_ulong target_fds_addr,
31+
int n)
32+
{
33+
@@ -875,7 +876,8 @@
34+
1)))
35+
return -TARGET_EFAULT;
36+
37+
- FD_ZERO(fds);
38+
+ memset(fds, 0, DIV_ROUND_UP(n, sizeof(unsigned long) * 8) *
39+
+ sizeof(unsigned long));
40+
k = 0;
41+
for (i = 0; i < nw; i++) {
42+
/* grab the abi_ulong */
43+
@@ -883,7 +885,8 @@
44+
for (j = 0; j < TARGET_ABI_BITS; j++) {
45+
/* check the bit inside the abi_ulong */
46+
if ((b >> j) & 1)
47+
- FD_SET(k, fds);
48+
+ fds[k / (sizeof(unsigned long) * 8)] |=
49+
+ 1ul << (k % (sizeof(unsigned long) * 8));
50+
k++;
51+
}
52+
}
53+
@@ -893,7 +896,8 @@
54+
return 0;
55+
}
56+
57+
-static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
58+
+static inline abi_ulong copy_from_user_fdset_ptr(unsigned long *fds,
59+
+ unsigned long **fds_ptr,
60+
abi_ulong target_fds_addr,
61+
int n)
62+
{
63+
@@ -908,7 +912,7 @@
64+
}
65+
66+
static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
67+
- const fd_set *fds,
68+
+ const unsigned long *fds,
69+
int n)
70+
{
71+
int i, nw, j, k;
72+
@@ -926,7 +930,10 @@
73+
for (i = 0; i < nw; i++) {
74+
v = 0;
75+
for (j = 0; j < TARGET_ABI_BITS; j++) {
76+
- v |= ((abi_ulong)(FD_ISSET(k, fds) != 0) << j);
77+
+ bool set =
78+
+ (fds[k / (sizeof(unsigned long) * 8)] &
79+
+ (1ul << (k % (sizeof(unsigned long) * 8)))) != 0;
80+
+ v |= ((abi_ulong)set << j);
81+
k++;
82+
}
83+
__put_user(v, &target_fds[i]);
84+
@@ -1295,28 +1302,40 @@
85+
abi_ulong rfd_addr, abi_ulong wfd_addr,
86+
abi_ulong efd_addr, abi_ulong target_tv_addr)
87+
{
88+
- fd_set rfds, wfds, efds;
89+
- fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
90+
+ unsigned long *rfds, *wfds, *efds;
91+
+ unsigned long *rfds_ptr, *wfds_ptr, *efds_ptr;
92+
struct timeval tv;
93+
struct timespec ts, *ts_ptr;
94+
abi_long ret;
95+
96+
- ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
97+
+ rfds = malloc(DIV_ROUND_UP(n, sizeof(unsigned long) * 8) *
98+
+ sizeof(unsigned long));
99+
+ wfds = malloc(DIV_ROUND_UP(n, sizeof(unsigned long) * 8) *
100+
+ sizeof(unsigned long));
101+
+ efds = malloc(DIV_ROUND_UP(n, sizeof(unsigned long) * 8) *
102+
+ sizeof(unsigned long));
103+
+
104+
+ ret = copy_from_user_fdset_ptr(rfds, &rfds_ptr, rfd_addr, n);
105+
if (ret) {
106+
+ free(rfds); free(wfds); free(efds);
107+
return ret;
108+
}
109+
- ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
110+
+ ret = copy_from_user_fdset_ptr(wfds, &wfds_ptr, wfd_addr, n);
111+
if (ret) {
112+
+ free(rfds); free(wfds); free(efds);
113+
return ret;
114+
}
115+
- ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
116+
+ ret = copy_from_user_fdset_ptr(efds, &efds_ptr, efd_addr, n);
117+
if (ret) {
118+
+ free(rfds); free(wfds); free(efds);
119+
return ret;
120+
}
121+
122+
if (target_tv_addr) {
123+
- if (copy_from_user_timeval(&tv, target_tv_addr))
124+
+ if (copy_from_user_timeval(&tv, target_tv_addr)) {
125+
+ free(rfds); free(wfds); free(efds);
126+
return -TARGET_EFAULT;
127+
+ }
128+
ts.tv_sec = tv.tv_sec;
129+
ts.tv_nsec = tv.tv_usec * 1000;
130+
ts_ptr = &ts;
131+
@@ -1328,22 +1347,30 @@
132+
ts_ptr, NULL));
133+
134+
if (!is_error(ret)) {
135+
- if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
136+
+ if (rfd_addr && copy_to_user_fdset(rfd_addr, rfds, n)) {
137+
+ free(rfds); free(wfds); free(efds);
138+
return -TARGET_EFAULT;
139+
- if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
140+
+ }
141+
+ if (wfd_addr && copy_to_user_fdset(wfd_addr, wfds, n)) {
142+
+ free(rfds); free(wfds); free(efds);
143+
return -TARGET_EFAULT;
144+
- if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
145+
+ }
146+
+ if (efd_addr && copy_to_user_fdset(efd_addr, efds, n)) {
147+
+ free(rfds); free(wfds); free(efds);
148+
return -TARGET_EFAULT;
149+
+ }
150+
151+
if (target_tv_addr) {
152+
tv.tv_sec = ts.tv_sec;
153+
tv.tv_usec = ts.tv_nsec / 1000;
154+
if (copy_to_user_timeval(target_tv_addr, &tv)) {
155+
+ free(rfds); free(wfds); free(efds);
156+
return -TARGET_EFAULT;
157+
}
158+
}
159+
}
160+
161+
+ free(rfds); free(wfds); free(efds);
162+
return ret;
163+
}
164+
165+
@@ -1377,8 +1404,8 @@
166+
bool time64)
167+
{
168+
abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
169+
- fd_set rfds, wfds, efds;
170+
- fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
171+
+ unsigned long *rfds, *wfds, *efds;
172+
+ unsigned long *rfds_ptr, *wfds_ptr, *efds_ptr;
173+
struct timespec ts, *ts_ptr;
174+
abi_long ret;
175+
176+
@@ -1399,16 +1426,26 @@
177+
efd_addr = arg4;
178+
ts_addr = arg5;
179+
180+
- ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
181+
+ rfds = malloc(DIV_ROUND_UP(n, sizeof(unsigned long) * 8) *
182+
+ sizeof(unsigned long));
183+
+ wfds = malloc(DIV_ROUND_UP(n, sizeof(unsigned long) * 8) *
184+
+ sizeof(unsigned long));
185+
+ efds = malloc(DIV_ROUND_UP(n, sizeof(unsigned long) * 8) *
186+
+ sizeof(unsigned long));
187+
+
188+
+ ret = copy_from_user_fdset_ptr(rfds, &rfds_ptr, rfd_addr, n);
189+
if (ret) {
190+
+ free(rfds); free(wfds); free(efds);
191+
return ret;
192+
}
193+
- ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
194+
+ ret = copy_from_user_fdset_ptr(wfds, &wfds_ptr, wfd_addr, n);
195+
if (ret) {
196+
+ free(rfds); free(wfds); free(efds);
197+
return ret;
198+
}
199+
- ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
200+
+ ret = copy_from_user_fdset_ptr(efds, &efds_ptr, efd_addr, n);
201+
if (ret) {
202+
+ free(rfds); free(wfds); free(efds);
203+
return ret;
204+
}
205+
206+
@@ -1419,10 +1456,12 @@
207+
if (ts_addr) {
208+
if (time64) {
209+
if (target_to_host_timespec64(&ts, ts_addr)) {
210+
+ free(rfds); free(wfds); free(efds);
211+
return -TARGET_EFAULT;
212+
}
213+
} else {
214+
if (target_to_host_timespec(&ts, ts_addr)) {
215+
+ free(rfds); free(wfds); free(efds);
216+
return -TARGET_EFAULT;
217+
}
218+
}
219+
@@ -1436,6 +1475,7 @@
220+
if (arg6) {
221+
arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
222+
if (!arg7) {
223+
+ free(rfds); free(wfds); free(efds);
224+
return -TARGET_EFAULT;
225+
}
226+
arg_sigset = tswapal(arg7[0]);
227+
@@ -1445,6 +1485,7 @@
228+
if (arg_sigset) {
229+
ret = process_sigsuspend_mask(&sig.set, arg_sigset, arg_sigsize);
230+
if (ret != 0) {
231+
+ free(rfds); free(wfds); free(efds);
232+
return ret;
233+
}
234+
sig_ptr = &sig;
235+
@@ -1460,25 +1501,31 @@
236+
}
237+
238+
if (!is_error(ret)) {
239+
- if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) {
240+
+ if (rfd_addr && copy_to_user_fdset(rfd_addr, rfds, n)) {
241+
+ free(rfds); free(wfds); free(efds);
242+
return -TARGET_EFAULT;
243+
}
244+
- if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) {
245+
+ if (wfd_addr && copy_to_user_fdset(wfd_addr, wfds, n)) {
246+
+ free(rfds); free(wfds); free(efds);
247+
return -TARGET_EFAULT;
248+
}
249+
- if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) {
250+
+ if (efd_addr && copy_to_user_fdset(efd_addr, efds, n)) {
251+
+ free(rfds); free(wfds); free(efds);
252+
return -TARGET_EFAULT;
253+
}
254+
if (time64) {
255+
if (ts_addr && host_to_target_timespec64(ts_addr, &ts)) {
256+
+ free(rfds); free(wfds); free(efds);
257+
return -TARGET_EFAULT;
258+
}
259+
} else {
260+
if (ts_addr && host_to_target_timespec(ts_addr, &ts)) {
261+
+ free(rfds); free(wfds); free(efds);
262+
return -TARGET_EFAULT;
263+
}
264+
}
265+
}
266+
+ free(rfds); free(wfds); free(efds);
267+
return ret;
268+
}
269+
#endif

0 commit comments

Comments
 (0)