From e4e355d16454123d7d93e991825e12dc47f43795 Mon Sep 17 00:00:00 2001 From: yinshengkai Date: Tue, 27 Aug 2024 15:31:32 +0800 Subject: [PATCH] fs: Set the poll return value according to the man manual The man manual describes that poll only has EFAULT, EINTR, EINVAL, and ENOMEM return values. If a file returns an error, the POLLERR event should be set and OK should be returned https://man7.org/linux/man-pages/man2/poll.2.html When using libuv to poll the socket, the socket poll returned an EBUSY error, causing libuv to abort. The expected logic should be to return OK, allowing libuv to notify the event listener that the POLLERR event occurred. Signed-off-by: yinshengkai Signed-off-by: ligd --- fs/vfs/fs_poll.c | 149 ++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 79 deletions(-) diff --git a/fs/vfs/fs_poll.c b/fs/vfs/fs_poll.c index 43f2740d42..4f626103eb 100644 --- a/fs/vfs/fs_poll.c +++ b/fs/vfs/fs_poll.c @@ -56,6 +56,48 @@ struct pollfd_s * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: poll_teardown + * + * Description: + * Teardown the poll operation for each descriptor in the list and return + * the count of non-zero poll events. + * + ****************************************************************************/ + +static inline void poll_teardown(FAR struct pollfd *fds, nfds_t nfds, + FAR int *count) +{ + unsigned int i; + + /* Process each descriptor in the list */ + + *count = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd >= 0) + { + int status = poll_fdsetup(fds[i].fd, &fds[i], false); + if (status < 0) + { + fds[i].revents |= POLLERR; + } + } + + /* Check if any events were posted */ + + if (fds[i].revents != 0) + { + (*count)++; + } + + /* Un-initialize the poll structure */ + + fds[i].arg = NULL; + fds[i].cb = NULL; + } +} + /**************************************************************************** * Name: poll_setup * @@ -68,8 +110,8 @@ static inline int poll_setup(FAR struct pollfd *fds, nfds_t nfds, FAR sem_t *sem) { unsigned int i; - unsigned int j; int ret = OK; + int count = 0; /* Process each descriptor in the list */ @@ -101,76 +143,31 @@ static inline int poll_setup(FAR struct pollfd *fds, nfds_t nfds, if (fds[i].fd >= 0) { ret = poll_fdsetup(fds[i].fd, &fds[i], true); - } - - if (ret < 0) - { - /* Setup failed for fds[i]. We now need to teardown previously - * setup fds[0 .. (i - 1)] to release allocated resources and - * to prevent memory corruption by access to freed/released 'fds' - * and 'sem'. - */ - - for (j = 0; j < i; j++) + if (ret < 0) { - poll_fdsetup(fds[j].fd, &fds[j], false); + poll_teardown(fds, i, &count); + fds[i].revents |= POLLERR; + fds[i].arg = NULL; + fds[i].cb = NULL; + return count + 1; + } + else if (fds[i].revents != 0) + { + count++; } - - /* Indicate an error on the file descriptor */ - - fds[i].revents |= POLLERR; - return ret; } } - return OK; -} - -/**************************************************************************** - * Name: poll_teardown - * - * Description: - * Teardown the poll operation for each descriptor in the list and return - * the count of non-zero poll events. - * - ****************************************************************************/ - -static inline int poll_teardown(FAR struct pollfd *fds, nfds_t nfds, - FAR int *count) -{ - unsigned int i; - int status = OK; - int ret = OK; - - /* Process each descriptor in the list */ - - *count = 0; - for (i = 0; i < nfds; i++) + if (count > 0) { - if (fds[i].fd >= 0) - { - status = poll_fdsetup(fds[i].fd, &fds[i], false); - } + /* If there are already events available in poll_setup, + * we execute teardown and return immediately. + */ - if (status < 0) - { - ret = status; - } - - /* Check if any events were posted */ - - if (fds[i].revents != 0) - { - (*count)++; - } - - /* Un-initialize the poll structure */ - - fds[i].arg = NULL; - fds[i].cb = NULL; + poll_teardown(fds, i, &count); } - return ret; + return count; } /**************************************************************************** @@ -425,8 +422,7 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout) FAR struct pollfd *kfds; sem_t sem; int count = 0; - int ret2; - int ret; + int ret = OK; DEBUGASSERT(nfds == 0 || fds != NULL); @@ -458,8 +454,13 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout) /* Set up the poll structure */ nxsem_init(&sem, 0, 0); - ret = poll_setup(kfds, nfds, &sem); - if (ret >= 0) + + /* If there are already events available in poll_setup, + * we return immediately + */ + + count = poll_setup(kfds, nfds, &sem); + if (count == 0) { struct pollfd_s fdsinfo; @@ -471,13 +472,7 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout) fdsinfo.nfds = nfds; tls_cleanup_push(tls_get_info(), poll_cleanup, &fdsinfo); - if (timeout == 0) - { - /* Poll returns immediately whether we have a poll event or not. */ - - ret = OK; - } - else if (timeout > 0) + if (timeout > 0) { /* "Implementations may place limitations on the granularity of * timeout intervals. If the requested timeout interval requires @@ -509,7 +504,7 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout) /* EINTR is the only other error expected in normal operation */ } } - else + else if (timeout < 0) { /* Wait for the poll event or signal with no timeout */ @@ -522,11 +517,7 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout) * Preserve ret, if negative, since it holds the result of the wait. */ - ret2 = poll_teardown(kfds, nfds, &count); - if (ret2 < 0 && ret >= 0) - { - ret = ret2; - } + poll_teardown(kfds, nfds, &count); /* Pop the cancellation point */