diff --git a/qkernel/src/syscalls/sys_poll.rs b/qkernel/src/syscalls/sys_poll.rs index 42aa76950..4cbbee0b8 100644 --- a/qkernel/src/syscalls/sys_poll.rs +++ b/qkernel/src/syscalls/sys_poll.rs @@ -205,7 +205,7 @@ pub fn DoSelect( if (events & SELECT_EXCEPT_EVENTS) != 0 { bitSetCount += 1; } else { - w[i] &= !m; + e[i] &= !m; } } } diff --git a/test/c/makefile b/test/c/makefile index a43bba1de..e23bf7cc8 100644 --- a/test/c/makefile +++ b/test/c/makefile @@ -1,4 +1,4 @@ -all: std server client server_conn client_conn unixcli unixsrv socketpair stat dev fork signal futex multithread epoll mkdir fifo timerfd eventfd seek gettimeofday server_benchmark client_benchmark epoll_client epoll_server multithread_client multithread_server multithread_pp_client multithread_pp_server poll udpcli udpsrv udpclidual udpsrvdual +all: std server client server_conn client_conn unixcli unixsrv socketpair stat dev fork signal futex multithread epoll mkdir fifo timerfd eventfd seek gettimeofday server_benchmark client_benchmark epoll_client epoll_server multithread_client multithread_server multithread_pp_client multithread_pp_server poll select_except_connect udpcli udpsrv udpclidual udpsrvdual std: std.c gcc -o std std.c @@ -6,6 +6,8 @@ dnstest: dnstest.c gcc -o dnstest dnstest.c poll: poll.c gcc -o poll poll.c +select_except_connect: select_except_connect.c + gcc -Wall -Wextra -o select_except_connect select_except_connect.c server: server.c gcc -o server server.c client: client.c @@ -79,4 +81,4 @@ udpclidual: udpclidual.c udpsrvdual: udpsrvdual.c gcc -o udpsrvdual udpsrvdual.c clean: - rm std server client unixcli unixsrv socketpair stat dev fork signal futex multithread epoll mkdir fifo timerfd eventfd seek gettimeofday + rm -f std server client select_except_connect unixcli unixsrv socketpair stat dev fork signal futex multithread epoll mkdir fifo timerfd eventfd seek gettimeofday diff --git a/test/c/select_except_connect.c b/test/c/select_except_connect.c new file mode 100644 index 000000000..93676ef69 --- /dev/null +++ b/test/c/select_except_connect.c @@ -0,0 +1,141 @@ +// Copyright (c) 2026 Quark Container Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void fail(const char *msg) +{ + perror(msg); + exit(1); +} + +int main(void) +{ + int listener = socket(AF_INET, SOCK_STREAM, 0); + if (listener < 0) { + fail("socket(listener)"); + } + + int one = 1; + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { + fail("setsockopt(SO_REUSEADDR)"); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = 0; + + if (bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fail("bind(listener)"); + } + if (listen(listener, 1) < 0) { + fail("listen(listener)"); + } + + socklen_t addr_len = sizeof(addr); + if (getsockname(listener, (struct sockaddr *)&addr, &addr_len) < 0) { + fail("getsockname(listener)"); + } + + pid_t child = fork(); + if (child < 0) { + fail("fork"); + } + if (child == 0) { + int accepted = accept(listener, NULL, NULL); + if (accepted < 0) { + fail("accept"); + } + char byte; + (void)read(accepted, &byte, sizeof(byte)); + close(accepted); + close(listener); + return 0; + } + + int client = socket(AF_INET, SOCK_STREAM, 0); + if (client < 0) { + fail("socket(client)"); + } + int flags = fcntl(client, F_GETFL, 0); + if (flags < 0 || fcntl(client, F_SETFL, flags | O_NONBLOCK) < 0) { + fail("fcntl(O_NONBLOCK)"); + } + + int rc = connect(client, (struct sockaddr *)&addr, sizeof(addr)); + if (rc < 0 && errno != EINPROGRESS) { + fail("connect(client)"); + } + + fd_set readfds; + fd_set writefds; + fd_set exceptfds; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(client, &readfds); + FD_SET(client, &writefds); + FD_SET(client, &exceptfds); + + struct timeval timeout; + timeout.tv_sec = 5; + timeout.tv_usec = 0; + rc = select(client + 1, &readfds, &writefds, &exceptfds, &timeout); + if (rc < 0) { + fail("select"); + } + if (rc == 0) { + fprintf(stderr, "select timed out\n"); + return 1; + } + + int err = 0; + socklen_t err_len = sizeof(err); + if (getsockopt(client, SOL_SOCKET, SO_ERROR, &err, &err_len) < 0) { + fail("getsockopt(SO_ERROR)"); + } + + printf("select rc=%d read=%d write=%d except=%d so_error=%d\n", + rc, + FD_ISSET(client, &readfds) != 0, + FD_ISSET(client, &writefds) != 0, + FD_ISSET(client, &exceptfds) != 0, + err); + + if (err != 0) { + fprintf(stderr, "SO_ERROR=%d (%s)\n", err, strerror(err)); + return 1; + } + if (!FD_ISSET(client, &writefds)) { + fprintf(stderr, "client socket was not in writefds\n"); + return 1; + } + if (FD_ISSET(client, &exceptfds)) { + fprintf(stderr, "client socket was incorrectly left in exceptfds\n"); + return 1; + } + + (void)write(client, "x", 1); + close(client); + close(listener); + + int status = 0; + if (waitpid(child, &status, 0) < 0) { + fail("waitpid"); + } + return status == 0 ? 0 : 1; +}