net/netlink: Add partial support for the NETLINK poll() operation. Still missing is some signal handling logic that actually wakes up the poll() when an asynchronous NETLLINK response is available.

So although the poll() implemenation is still not yet usable, the commit is useful because it (1) does not harm, and (2) incidentally fixes a few other issues in the NETLONK response queuing that I noted in the process.
This commit is contained in:
Gregory Nutt 2019-11-26 18:52:22 -06:00
parent c2211d8d3c
commit 93ed8b66d9
3 changed files with 267 additions and 8 deletions

View File

@ -212,6 +212,49 @@ FAR struct netlink_response_s *
FAR struct netlink_response_s *
netlink_get_response(FAR struct socket *psock);
/****************************************************************************
* Name: netlink_check_response
*
* Description:
* Return true is a response is pending now.
*
* Returned Value:
* True: A response is available; False; No response is available.
*
****************************************************************************/
bool netlink_check_response(FAR struct socket *psock);
/****************************************************************************
* Name: netlink_notify_response
*
* Description:
* Notify a thread until a response be available. The thread will be
* notified via CONFIG_NETLINK_SIGNAL when the response becomes available.
*
* Returned Value:
* Zero (OK) is returned if the response is already available. Not signal
* will be sent.
* One is returned if the notification was successfully setup.
* A negated errno value is returned on any failure.
*
****************************************************************************/
int netlink_notify_response(FAR struct socket *psock);
/****************************************************************************
* Name: netlink_notify_cancel
*
* Description:
* Cancel a notification previously created with netlink_notify_response().
*
* Returned Value:
* Zero (OK) is always returned.
*
****************************************************************************/
int netlink_notify_cancel(FAR struct socket *psock);
/****************************************************************************
* Name: netlink_route_sendto()
*

View File

@ -143,6 +143,8 @@ static void netlink_notify_waiters(FAR struct netlink_conn_s *conn)
nerr("ERROR: nxsig_kill() failed: %d\n", ret);
UNUSED(ret);
}
conn->waiter[i] = NETLINK_NO_WAITER;
}
}
@ -178,6 +180,34 @@ static int netlink_add_waiter(FAR struct netlink_conn_s *conn)
return -ENOSPC;
}
/****************************************************************************
* Name: netlink_remove_waiter
*
* Description:
* Remove a waiter to the list of waiters.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static int netlink_remove_waiter(FAR struct netlink_conn_s *conn,
pid_t waiter)
{
int i;
for (i = 0; i < CONFIG_NETLINK_MAXPENDING; i++)
{
if (conn->waiter[i] == waiter)
{
conn->waiter[i] = NETLINK_NO_WAITER;
break;
}
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -484,7 +514,7 @@ FAR struct netlink_response_s *
ret = sigwaitinfo(&set, &info);
if (ret < 0)
{
nerr("ERROR: sigwaitinfo failed: %d\n", ret);
nerr("ERROR: sigwaitinfo() failed: %d\n", ret);
}
/* Restore the network lock */
@ -496,4 +526,116 @@ FAR struct netlink_response_s *
return resp;
}
/****************************************************************************
* Name: netlink_check_response
*
* Description:
* Return true is a response is pending now.
*
* Returned Value:
* True: A response is available; False; No response is available.
*
****************************************************************************/
bool netlink_check_response(FAR struct socket *psock)
{
FAR struct netlink_conn_s *conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
conn = (FAR struct netlink_conn_s *)psock->s_conn;
/* Check if the response is available. It is not necessary to lock the
* network because the sq_peek() is an atomic operation.
*/
return (sq_peek(&conn->resplist) != NULL);
}
/****************************************************************************
* Name: netlink_notify_response
*
* Description:
* Notify a thread until a response be available. The thread will be
* notified via CONFIG_NETLINK_SIGNAL when the response becomes available.
*
* Returned Value:
* Zero (OK) is returned if the response is already available. Not signal
* will be sent.
* One is returned if the notification was successfully setup.
* A negated errno value is returned on any failure.
*
****************************************************************************/
int netlink_notify_response(FAR struct socket *psock)
{
FAR struct netlink_conn_s *conn;
FAR struct siginfo info;
sigset_t set;
int ret = 0;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
conn = (FAR struct netlink_conn_s *)psock->s_conn;
/* Check if the response is available */
net_lock();
if (((FAR struct netlink_response_s *)sq_peek(&conn->resplist)) == NULL)
{
/* No.. Add this task as a waiter */
ret = netlink_add_waiter(conn);
if (ret < 0)
{
nerr("ERROR: netlink_add_waiter failed: %d\n", ret);
}
else
{
/* Set up to signal when a response is available */
sigemptyset(&set);
sigaddset(&set, CONFIG_NETLINK_SIGNAL);
ret = sigwaitinfo(&set, &info);
if (ret < 0)
{
nerr("ERROR: sigwaitinfo() failed: %d\n", ret);
}
else
{
ret = 1;
}
}
}
net_unlock();
return ret;
}
/****************************************************************************
* Name: netlink_notify_cancel
*
* Description:
* Cancel a notification previously created with netlink_notify_response().
*
* Returned Value:
* Zero (OK) is always returned.
*
****************************************************************************/
int netlink_notify_cancel(FAR struct socket *psock)
{
FAR struct netlink_conn_s *conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
conn = (FAR struct netlink_conn_s *)psock->s_conn;
/* Remove this thread as waiter for response notifications for this
* socket.
*/
net_lock();
(void)netlink_remove_waiter(conn, getpid());
net_unlock();
return OK;
}
#endif /* CONFIG_NET_NETLINK */

View File

@ -43,10 +43,12 @@
#include <sys/socket.h>
#include <stdbool.h>
#include <string.h>
#include <poll.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include "netlink/netlink.h"
@ -489,6 +491,12 @@ static int netlink_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
* The standard poll() operation redirects operations on socket descriptors
* to this function.
*
* POLLUP: Will never be reported
* POLLERR: Reported in the event of any failure.
* POLLOUT: Always reported if requested.
* POLLIN: Reported if requested but only when pending response data is
* available
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* fds - The structure describing the events to be monitored.
@ -502,8 +510,74 @@ static int netlink_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
bool setup)
{
#warning Missing logic for NETLINK poll
return -EOPNOTSUPP;
int ret;
/* Check if we are setting up or tearing down the poll */
if (setup)
{
/* If POLLOUT is selected, return immediately (maybe) */
pollevent_t revents = POLLOUT;
/* If POLLIN is selected and a response is available, return
* immediately (maybe).
*/
net_lock();
if (netlink_check_response(psock))
{
revents |= POLLIN;
}
/* But return ONLY if POLLIN and/or POLLIN are included in the
* requested event set.
*/
revents &= fds->events;
if (revents != 0)
{
fds->revents = revents;
nxsem_post(fds->sem);
net_unlock();
return OK;
}
/* Set up to be notified by signal when a response is available if
* POLLIN is requested.
*/
if ((fds->events & POLLIN) != 0)
{
#if 0
/* Call netlink_notify_response() to receive a signal when
* a response has been queued.
*
* REVISIT: How shall we pass the FDS info to the signal
* handler?
*/
#else
#warning Missing logic for NETLINK POLLIN
nxsem_post(fds->sem);
net_unlock();
return -ENOSYS;
#endif
}
/* There will not be any wakeups coming? Probably an error? */
net_unlock();
ret = OK;
}
else
{
/* Cancel any response notifications */
ret = netlink_notify_cancel(psock);
}
return ret;
}
/****************************************************************************
@ -514,10 +588,10 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
* a connected state (so that the intended recipient is known).
*
* Input Parameters:
* psock An instance of the internal socket structure.
* buf Data to send
* len Length of data to send
* flags Send flags (ignored)
* psock - An instance of the internal socket structure.
* buf - Data to send
* len - Length of data to send
* flags - Send flags (ignored)
*
* Returned Value:
* On success, returns the number of characters sent. On error, a negated
@ -717,7 +791,7 @@ static int netlink_close(FAR struct socket *psock)
{
/* Yes... inform user-space daemon of socket close. */
#warning Missing logic
#warning Missing logic in NETLINK close()
/* Free the connection structure */