diff --git a/components/esp_libc/src/poll.c b/components/esp_libc/src/poll.c index 4371c63b031..ca3cacda7d2 100644 --- a/components/esp_libc/src/poll.c +++ b/components/esp_libc/src/poll.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,7 +22,6 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) fd_set readfds; fd_set writefds; fd_set errorfds; - int ret = 0; if (fds == NULL) { errno = ENOENT; @@ -43,7 +42,6 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) if (fds[i].fd >= FD_SETSIZE) { fds[i].revents |= POLLNVAL; - ++ret; continue; } @@ -62,10 +60,17 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) const int select_ret = select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL : &tv); - if (select_ret > 0) { - ret += select_ret; + if (select_ret < 0) { + // keeping the errno from select() + return select_ret; + } + if (select_ret > 0) { for (unsigned int i = 0; i < nfds; ++i) { + if (fds[i].fd < 0 || fds[i].fd >= FD_SETSIZE) { + continue; + } + if (FD_ISSET(fds[i].fd, &readfds)) { fds[i].revents |= POLLIN; } @@ -78,9 +83,13 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) fds[i].revents |= POLLERR; } } - } else { - ret = select_ret; - // keeping the errno from select() + } + + int ret = 0; + for (unsigned int i = 0; i < nfds; ++i) { + if (fds[i].revents != 0) { + ++ret; + } } return ret; diff --git a/components/vfs/test_apps/main/test_vfs_select.c b/components/vfs/test_apps/main/test_vfs_select.c index 538c5e38170..761ddeeb4db 100644 --- a/components/vfs/test_apps/main/test_vfs_select.c +++ b/components/vfs/test_apps/main/test_vfs_select.c @@ -1,14 +1,16 @@ /* - * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include #include +#include #include "unity.h" #include "freertos/FreeRTOS.h" #include "driver/uart.h" @@ -37,6 +39,76 @@ typedef struct { static const char message[] = "Hello world!"; +typedef struct { + fd_set *readfds; + fd_set *writefds; + int local_fd; + bool ready_read; + bool ready_write; +} dummy_select_args_t; + +static int dummy_open(const char *path, int flags, int mode) +{ + return 0; // single local fd +} + +static int dummy_close(int fd) +{ + return 0; +} + +static esp_err_t dummy_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args) +{ + (void) nfds; + (void) exceptfds; + + dummy_select_args_t *args = calloc(1, sizeof(dummy_select_args_t)); + if (args == NULL) { + return ESP_ERR_NO_MEM; + } + args->local_fd = 0; + args->readfds = readfds; + args->writefds = writefds; + args->ready_read = readfds && FD_ISSET(args->local_fd, readfds); + args->ready_write = writefds && FD_ISSET(args->local_fd, writefds); + + if (!(args->ready_read || args->ready_write)) { + free(args); + *end_select_args = NULL; + return ESP_OK; + } + + *end_select_args = args; + esp_vfs_select_triggered(sem); + return ESP_OK; +} + +static esp_err_t dummy_end_select(void *end_select_args) +{ + dummy_select_args_t *args = end_select_args; + if (!args) { + return ESP_OK; + } + + if (args->ready_read && args->readfds) { + FD_SET(args->local_fd, args->readfds); + } + if (args->ready_write && args->writefds) { + FD_SET(args->local_fd, args->writefds); + } + + free(args); + return ESP_OK; +} + +static const esp_vfs_t dummy_vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .open = dummy_open, + .close = dummy_close, + .start_select = dummy_start_select, + .end_select = dummy_end_select, +}; + static int open_dummy_socket(void) { const struct addrinfo hints = { @@ -526,6 +598,33 @@ TEST_CASE("UART can do poll() with POLLIN event", "[vfs]") deinit(uart_fd, socket_fd); } +TEST_CASE("poll() counts fd once when multiple events are set", "[vfs]") +{ + ESP_ERROR_CHECK(esp_vfs_register("/dummy", &dummy_vfs, NULL)); + const int fd = open("/dummy/test", O_RDONLY); + TEST_ASSERT_GREATER_OR_EQUAL(0, fd); + + struct pollfd poll_fds[] = { + { + .fd = fd, + .events = POLLIN | POLLOUT, + }, + { + .fd = -1, + }, + }; + + int s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100); + TEST_ASSERT_EQUAL(1, s); + TEST_ASSERT_EQUAL(fd, poll_fds[0].fd); + TEST_ASSERT_EQUAL(POLLIN | POLLOUT, poll_fds[0].revents); + TEST_ASSERT_EQUAL(-1, poll_fds[1].fd); + TEST_ASSERT_EQUAL(0, poll_fds[1].revents); + + close(fd); + ESP_ERROR_CHECK(esp_vfs_unregister("/dummy")); +} + TEST_CASE("UART can do poll() with POLLOUT event", "[vfs]") { int uart_fd;