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 <yinshengkai@xiaomi.com>
Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
yinshengkai 2024-08-27 15:31:32 +08:00 committed by Xiang Xiao
parent 36ddb46dba
commit e4e355d164

View file

@ -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 */