Squashed commit of the following:

net/netlink/netlink_sockif.c:  At implementation of response available signal handler needed for POLLIN logic.
    net/netlink/netlink_sockif.c:  Add logic to set up signal handler to receive the response notification.
This commit is contained in:
Gregory Nutt 2019-11-27 21:30:01 -06:00
parent a8f3c3651a
commit d1593bb336
3 changed files with 164 additions and 17 deletions

View File

@ -45,6 +45,8 @@
#include <sys/types.h>
#include <queue.h>
#include <semaphore.h>
#include <signal.h>
#include <poll.h>
#include <netpacket/netlink.h>
#include <nuttx/net/netlink.h>
@ -86,6 +88,12 @@ struct netlink_conn_s
uint8_t crefs; /* Reference counts on this instance */
uint8_t protocol; /* See NETLINK_* definitions */
/* poll() support */
FAR sem_t *pollsem; /* Used to wakeup poll() */
FAR pollevent_t *pollevent; /* poll() wakeup event */
struct sigaction oact; /* Previous signal action */
/* Threads waiting for a response */
pid_t waiter[CONFIG_NETLINK_MAXPENDING];

View File

@ -144,13 +144,13 @@ static void netlink_notify_waiters(FAR struct netlink_conn_s *conn)
value.sival_ptr = conn;
ret = nxsig_queue((int)conn->waiter[i],
(int)CONFIG_NETLINK_SIGNAL, value);
(int)CONFIG_NETLINK_SIGNAL, value);
#else
ret = nxsig_queue((int)conn->waiter[i],
(int)CONFIG_NETLINK_SIGNAL, conn);
(int)CONFIG_NETLINK_SIGNAL, conn);
#endif
if (ret < 0)
{
{
nerr("ERROR: nxsig_queue() failed: %d\n", ret);
UNUSED(ret);
}

View File

@ -44,11 +44,13 @@
#include <stdbool.h>
#include <string.h>
#include <poll.h>
#include <sched.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/signal.h>
#include <nuttx/net/net.h>
#include "netlink/netlink.h"
@ -484,6 +486,89 @@ static int netlink_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
return -EOPNOTSUPP;
}
/****************************************************************************
* Name: netlink_notify_teardown
*
* Description:
* Teardown a Netlink response notification.
*
* Input Parameters:
* conn - Netlink connection structure.
*
* Returned Value:
* None
*
****************************************************************************/
static void netlink_notify_teardown(FAR struct netlink_conn_s *conn)
{
sched_lock();
if (conn->pollsem != NULL || conn->pollevent != NULL)
{
/* Allow another poll() */
conn->pollsem = NULL;
conn->pollevent = NULL;
/* Detach the signal handler by restoring the previous signal handler
* state.
*/
(void)nxsig_action(CONFIG_NETLINK_SIGNAL, &conn->oact, NULL, true);
}
sched_unlock();
}
/****************************************************************************
* Name: netlink_response_available
*
* Description:
* Handle a Netlink response available notification
*
* Input Parameters:
* Standard signal handler parameters
*
* Returned Value:
* None
*
****************************************************************************/
static void netlink_response_available(int signo, FAR siginfo_t *siginfo,
FAR void *context)
{
FAR struct netlink_conn_s *conn;
/* The si_value member should be a reference to a Netlink connection
* structure.
*/
DEBUGASSERT(siginfo != NULL);
conn = (FAR struct netlink_conn_s *)siginfo->si_value.sival_ptr;
DEBUGASSERT(conn != NULL);
/* This should always be true ... but maybe not in some race condition?
* REVISIT: Is locking the scheduler strong enough Kung Fu here? Could
* the awakened thread try to poll() again on another CPU?
*/
sched_lock();
if (conn->pollsem != NULL && conn->pollevent != NULL)
{
/* Wake up the poll() with POLLIN */
*conn->pollevent |= POLLIN;
(void)nxsem_post(conn->pollsem);
}
else
{
nwarn("WARNING: Missing references in connection.\n");
}
netlink_notify_teardown(conn);
sched_unlock();
}
/****************************************************************************
* Name: netlink_poll
*
@ -510,8 +595,12 @@ 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)
{
FAR struct netlink_conn_s *conn;
int ret;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
conn = (FAR struct netlink_conn_s *)psock->s_conn;
/* Check if we are setting up or tearing down the poll */
if (setup)
@ -549,32 +638,82 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
if ((fds->events & POLLIN) != 0)
{
#if 0
/* Call netlink_notify_response() to receive a signal when
struct sigaction act;
/* Set up a signal handler to recive the notification 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
if (conn->pollsem != NULL || conn->pollevent != NULL)
{
nerr("ERROR: Multiple polls() on socket not supported.\n");
net_unlock();
return -EBUSY;
}
conn->pollsem = fds->sem;
conn->pollevent = &fds->revents;
memset(&act, 0, sizeof(act));
act.sa_sigaction = netlink_response_available;
act.sa_flags = SA_SIGINFO;
ret = nxsig_action(CONFIG_NETLINK_SIGNAL, &act, &conn->oact,
true);
if (ret < 0)
{
nerr("ERROR: nxsig_action() failed: %d\n", ret);
}
else if (conn->oact.sa_handler != SIG_DFL &&
conn->oact.sa_handler != NULL)
{
nerr("ERROR: Signal being used for some other purpose\n");
netlink_notify_teardown(conn);
ret = -ENOEXEC;
}
else
{
/* Call netlink_notify_response() to receive a signal when
* a response has been queued.
*/
ret = netlink_notify_response(psock);
if (ret < 0)
{
nerr("ERROR: netlink_notify_response() failed: %d\n", ret);
netlink_notify_teardown(conn);
}
else if (ret == 0)
{
/* The return value of zero means that a response is
* already available and that no notification is
* forthcoming.
*/
netlink_notify_teardown(conn);
fds->revents = POLLIN;
nxsem_post(fds->sem);
}
else
{
ret = OK;
}
}
}
else
{
/* There will not be any wakeups coming? Probably an error? */
ret = OK;
}
/* There will not be any wakeups coming? Probably an error? */
net_unlock();
ret = OK;
}
else
{
/* Cancel any response notifications */
ret = netlink_notify_cancel(psock);
netlink_notify_teardown(conn);
}
return ret;