diff --git a/src/lib/libsyscall.js b/src/lib/libsyscall.js index c813bf443f2ca..d4d6c98948f96 100644 --- a/src/lib/libsyscall.js +++ b/src/lib/libsyscall.js @@ -108,57 +108,70 @@ var SyscallsLibrary = { }, $parseSelectFDSet__internal: true, - $parseSelectFDSet: (readfds, writefds, exceptfds) => { - var total = 0; + $parseSelectFDSet: (readfds, writefds, exceptfds, nfds) => { + const FD_ISSET = (set, fd) => set[(fd / 32) >>> 0] & (1 << (fd & 31)); + const FD_CLR = (set, fd) => set[(fd / 32) >>> 0] &= ~(1 << (fd & 31)); + const FD_SET = (set, fd) => set[(fd / 32) >>> 0] |= (1 << (fd & 31)); + const numWords = ((nfds + 31) / 32) >>> 0; - var srcReadLow = (readfds ? {{{ makeGetValue('readfds', 0, 'i32') }}} : 0), - srcReadHigh = (readfds ? {{{ makeGetValue('readfds', 4, 'i32') }}} : 0); - var srcWriteLow = (writefds ? {{{ makeGetValue('writefds', 0, 'i32') }}} : 0), - srcWriteHigh = (writefds ? {{{ makeGetValue('writefds', 4, 'i32') }}} : 0); - var srcExceptLow = (exceptfds ? {{{ makeGetValue('exceptfds', 0, 'i32') }}} : 0), - srcExceptHigh = (exceptfds ? {{{ makeGetValue('exceptfds', 4, 'i32') }}} : 0); +#if ASSERTIONS + const FD_SETWORDS = {{{ cDefs.FD_SETSIZE }}} / 32; + assert(numWords <= FD_SETWORDS); +#endif - var dstReadLow = 0, - dstReadHigh = 0; - var dstWriteLow = 0, - dstWriteHigh = 0; - var dstExceptLow = 0, - dstExceptHigh = 0; + const srcMerged = new Array(numWords); + const srcRead = new Array(numWords).fill(0); + const srcWrite = new Array(numWords).fill(0); + const srcExcept = new Array(numWords).fill(0); + const dstRead = new Array(numWords).fill(0); + const dstWrite = new Array(numWords).fill(0); + const dstExcept = new Array(numWords).fill(0); - var check = (fd, low, high, val) => fd < 32 ? (low & val) : (high & val); + let total = 0; + + for (let i = 0; i < numWords; i++) { + if (readfds) { + srcRead[i] = {{{ makeGetValue('readfds', 'i * 4', 'i32') }}}; + } + if (writefds) { + srcWrite[i] = {{{ makeGetValue('writefds', 'i * 4', 'i32') }}}; + } + if (exceptfds) { + srcExcept[i] = {{{ makeGetValue('exceptfds', 'i * 4', 'i32') }}}; + } + srcMerged[i] = srcRead[i] | srcWrite[i] | srcExcept[i]; + } return { - allLow: srcReadLow | srcWriteLow | srcExceptLow, - allHigh: srcReadHigh | srcWriteHigh | srcExceptHigh, getTotal: () => total, + check: (fd) => { + return FD_ISSET(srcMerged, fd); + }, setFlags: (fd, flags) => { - var mask = 1 << (fd % 32); - - if ((flags & {{{ cDefs.POLLIN }}}) && check(fd, srcReadLow, srcReadHigh, mask)) { - fd < 32 ? (dstReadLow = dstReadLow | mask) : (dstReadHigh = dstReadHigh | mask); + if ((flags & {{{ cDefs.POLLIN }}}) && FD_ISSET(srcRead, fd)) { + FD_SET(dstRead, fd); total++; } - if ((flags & {{{ cDefs.POLLOUT }}}) && check(fd, srcWriteLow, srcWriteHigh, mask)) { - fd < 32 ? (dstWriteLow = dstWriteLow | mask) : (dstWriteHigh = dstWriteHigh | mask); + if ((flags & {{{ cDefs.POLLOUT }}}) && FD_ISSET(srcWrite, fd)) { + FD_SET(dstWrite, fd); total++; } - if ((flags & {{{ cDefs.POLLPRI }}}) && check(fd, srcExceptLow, srcExceptHigh, mask)) { - fd < 32 ? (dstExceptLow = dstExceptLow | mask) : (dstExceptHigh = dstExceptHigh | mask); + if ((flags & {{{ cDefs.POLLPRI }}}) && FD_ISSET(srcExcept, fd)) { + FD_SET(dstExcept, fd); total++; } }, commit: () => { - if (readfds) { - {{{ makeSetValue('readfds', '0', 'dstReadLow', 'i32') }}}; - {{{ makeSetValue('readfds', '4', 'dstReadHigh', 'i32') }}}; - } - if (writefds) { - {{{ makeSetValue('writefds', '0', 'dstWriteLow', 'i32') }}}; - {{{ makeSetValue('writefds', '4', 'dstWriteHigh', 'i32') }}}; - } - if (exceptfds) { - {{{ makeSetValue('exceptfds', '0', 'dstExceptLow', 'i32') }}}; - {{{ makeSetValue('exceptfds', '4', 'dstExceptHigh', 'i32') }}}; + for (let i = 0; i < numWords; i++) { + if (readfds) { + {{{ makeSetValue('readfds', 'i * 4', 'dstRead[i]', 'i32') }}}; + } + if (writefds) { + {{{ makeSetValue('writefds', 'i * 4', 'dstWrite[i]', 'i32') }}}; + } + if (exceptfds) { + {{{ makeSetValue('exceptfds', 'i * 4', 'dstExcept[i]', 'i32') }}}; + } } } }; @@ -405,7 +418,7 @@ var SyscallsLibrary = { __syscall_socket: (domain, type, protocol) => { var sock = SOCKFS.createSocket(domain, type, protocol); #if ASSERTIONS - assert(sock.stream.fd < 64); // XXX ? select() assumes socket fd values are in 0..63 + assert(sock.stream.fd < {{{ cDefs.FD_SETSIZE }}}); // XXX ? select() assumes socket fd values are in 0..63 #endif return sock.stream.fd; }, @@ -617,18 +630,13 @@ var SyscallsLibrary = { // timeout is supported, although on SOCKFS these are ignored and always treated as 0 - fully async // and PIPEFS supports timeout only when the select is called from a worker. #if ASSERTIONS - assert(nfds <= 64, 'nfds must be less than or equal to 64'); // fd sets have 64 bits // TODO: this could be 1024 based on current musl headers + assert(nfds <= {{{ cDefs.FD_SETSIZE }}}, 'nfds must be less than or equal to FD_SETSIZE'); #if PTHREADS assert(!ENVIRONMENT_IS_PTHREAD, '_newselect_js must be called in the main thread'); #endif #endif - var fdSet = parseSelectFDSet(readfds, writefds, exceptfds); - - var allLow = fdSet.allLow; - var allHigh = fdSet.allHigh; - - var check = (fd, low, high, val) => fd < 32 ? (low & val) : (high & val); + var fdSet = parseSelectFDSet(readfds, writefds, exceptfds, nfds); #if PTHREADS var makeNotifyCallback = null; @@ -661,8 +669,7 @@ var SyscallsLibrary = { #endif for (var fd = 0; fd < nfds; fd++) { - var mask = 1 << (fd % 32); - if (!(check(fd, allLow, allHigh, mask))) { + if (!fdSet.check(fd)) { continue; // index isn't in the set } diff --git a/src/struct_info.json b/src/struct_info.json index 04c86495b6c12..b2da3a69ffe56 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -295,6 +295,12 @@ "SIGTERM" ] }, + { + "file": "sys/select.h", + "defines": [ + "FD_SETSIZE" + ] + }, { "file": "sys/socket.h", "defines": [ diff --git a/src/struct_info_generated.json b/src/struct_info_generated.json index 2292ecd56ae48..ee4267b582c6f 100644 --- a/src/struct_info_generated.json +++ b/src/struct_info_generated.json @@ -292,6 +292,7 @@ "EWOULDBLOCK": 6, "EXDEV": 75, "EXFULL": 115, + "FD_SETSIZE": 1024, "FIONBIO": 21537, "FIONREAD": 21531, "F_DUPFD": 0, diff --git a/src/struct_info_generated_wasm64.json b/src/struct_info_generated_wasm64.json index 545192606f982..14adafa4938d7 100644 --- a/src/struct_info_generated_wasm64.json +++ b/src/struct_info_generated_wasm64.json @@ -292,6 +292,7 @@ "EWOULDBLOCK": 6, "EXDEV": 75, "EXFULL": 115, + "FD_SETSIZE": 1024, "FIONBIO": 21537, "FIONREAD": 21531, "F_DUPFD": 0, diff --git a/test/sockets/test_sockets_echo_client.c b/test/sockets/test_sockets_echo_client.c index 626e9686d6564..28a30f3e6686f 100644 --- a/test/sockets/test_sockets_echo_client.c +++ b/test/sockets/test_sockets_echo_client.c @@ -75,7 +75,7 @@ void main_loop() { FD_ZERO(&fdw); FD_SET(server.fd, &fdr); FD_SET(server.fd, &fdw); - res = select(64, &fdr, &fdw, NULL, &tv); + res = select(FD_SETSIZE, &fdr, &fdw, NULL, &tv); if (res == -1) { perror("select failed"); finish(EXIT_FAILURE); diff --git a/test/sockets/test_sockets_echo_server.c b/test/sockets/test_sockets_echo_server.c index ca2be0aa3b07a..d8e1e3d619d39 100644 --- a/test/sockets/test_sockets_echo_server.c +++ b/test/sockets/test_sockets_echo_server.c @@ -89,7 +89,7 @@ void main_loop() { if (client.fd) FD_SET(client.fd, &fdr); if (client.fd) FD_SET(client.fd, &fdw); #endif - res = select(64, &fdr, &fdw, NULL, &tv); + res = select(FD_SETSIZE, &fdr, &fdw, NULL, &tv); if (res == -1) { perror("select failed"); exit(EXIT_SUCCESS); diff --git a/test/sockets/test_sockets_partial_client.c b/test/sockets/test_sockets_partial_client.c index 4b3c675722b36..1bd13b8cf77dc 100644 --- a/test/sockets/test_sockets_partial_client.c +++ b/test/sockets/test_sockets_partial_client.c @@ -43,7 +43,7 @@ void iter() { // make sure that sockfd is ready to read FD_ZERO(&fdr); FD_SET(sockfd, &fdr); - res = select(64, &fdr, NULL, NULL, NULL); + res = select(FD_SETSIZE, &fdr, NULL, NULL, NULL); if (res == -1) { perror("select failed"); finish(EXIT_FAILURE); diff --git a/test/sockets/test_sockets_partial_server.c b/test/sockets/test_sockets_partial_server.c index 600d3c670e67b..83adbd965b2cd 100644 --- a/test/sockets/test_sockets_partial_server.c +++ b/test/sockets/test_sockets_partial_server.c @@ -80,7 +80,7 @@ void iter() { FD_ZERO(&fdw); FD_SET(serverfd, &fdr); if (clientfd) FD_SET(clientfd, &fdw); - res = select(64, &fdr, &fdw, NULL, NULL); + res = select(FD_SETSIZE, &fdr, &fdw, NULL, NULL); if (res == -1) { perror("select failed"); exit(EXIT_SUCCESS); diff --git a/test/sockets/test_sockets_select_server_closes_connection_client_rw.c b/test/sockets/test_sockets_select_server_closes_connection_client_rw.c index 16195657f56df..615369fc889c5 100644 --- a/test/sockets/test_sockets_select_server_closes_connection_client_rw.c +++ b/test/sockets/test_sockets_select_server_closes_connection_client_rw.c @@ -53,7 +53,7 @@ void main_loop() { // select should tell us 0 handles are ready FD_ZERO(&sett); FD_SET(sockfd, &sett); - selectRes = select(64, &sett, NULL, NULL, NULL); + selectRes = select(FD_SETSIZE, &sett, NULL, NULL, NULL); if (selectRes != 0) { printf("case 0: read select != 0 (%d)\n", selectRes); finish(EXIT_FAILURE); @@ -63,7 +63,7 @@ void main_loop() { // the connection either is setting up or is established and writing is possible FD_ZERO(&sett); FD_SET(sockfd, &sett); - selectRes = select(64, NULL, &sett, NULL, NULL); + selectRes = select(FD_SETSIZE, NULL, &sett, NULL, NULL); if (selectRes == -1) { printf("case 0: write select == -1\n"); finish(EXIT_FAILURE); @@ -86,7 +86,7 @@ void main_loop() { // has sent the data and then closed the connection FD_ZERO(&sett); FD_SET(sockfd, &sett); - selectRes = select(64, &sett, NULL, NULL, NULL); + selectRes = select(FD_SETSIZE, &sett, NULL, NULL, NULL); if (selectRes == -1) { printf("case 1: read selectRes == -1\n"); finish(EXIT_FAILURE); @@ -114,7 +114,7 @@ void main_loop() { // succeed, but the socket should not set in the set. FD_ZERO(&sett); FD_SET(sockfd, &sett); - selectRes = select(64, NULL, &sett, NULL, NULL); + selectRes = select(FD_SETSIZE, NULL, &sett, NULL, NULL); if (selectRes != 0 || FD_ISSET(sockfd, &sett)) { printf("case 2: write selectRes != 0 || FD_ISSET(sockfd, &sett)\n"); finish(EXIT_FAILURE); @@ -124,7 +124,7 @@ void main_loop() { // has to succeed because there is still data in the inQueue FD_ZERO(&sett); FD_SET(sockfd, &sett); - selectRes = select(64, &sett, NULL, NULL, NULL); + selectRes = select(FD_SETSIZE, &sett, NULL, NULL, NULL); if (selectRes != 1) { printf("case 2: read selectRes != 1\n"); finish(EXIT_FAILURE); @@ -152,7 +152,7 @@ void main_loop() { // should succeed FD_ZERO(&sett); FD_SET(sockfd, &sett); - selectRes = select(64, &sett, NULL, NULL, NULL); + selectRes = select(FD_SETSIZE, &sett, NULL, NULL, NULL); if (selectRes != 1) { printf("case 3: read selectRes != 1\n"); finish(EXIT_FAILURE);