1
0
Fork 0
forked from nuttx/nuttx-update

net/netlink: Redesign the logic that handles notifications of when response data is available. Signal handlers are sub-optimal inside the OS (especially after the preceding change which forces the hand). Instead, use the work queue notifiers as is done with all other network notifiers.

This commit is contained in:
Gregory Nutt 2019-11-28 14:20:40 -06:00
parent 69318b1024
commit 4ae09a3b80
9 changed files with 385 additions and 303 deletions

View file

@ -290,7 +290,8 @@ enum work_evtype_e
WORK_TCP_WRITEBUFFER, /* Notify that TCP write buffer is empty */
WORK_TCP_DISCONNECT, /* Notify loss of TCP connection */
WORK_UDP_READAHEAD, /* Notify that UDP read-ahead data is available */
WORK_UDP_WRITEBUFFER /* Notify that UDP write buffer is empty */
WORK_UDP_WRITEBUFFER, /* Notify that UDP write buffer is empty */
WORK_NETLINK_RESPONSE /* Notify thtat Netlink response is available */
};
/* This structure describes one notification and is provided as input to
@ -562,7 +563,7 @@ int work_notifier_teardown(int key);
* need to call work_notifier_setup() once again.
*
* Input Parameters:
* evtype - The type of the event that just occurred.
* evtype - The type of the event that just occurred.
* qualifier - Event qualifier to distinguish different cases of the
* generic event type.
*

View file

@ -501,9 +501,9 @@ int netdev_ipv6_ifconf(FAR struct lifconf *lifc);
* Name: netdown_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function the network goes
* down. The worker function will execute on the high priority worker
* thread.
* Set up to perform a callback to the worker function when the network
* goes down. The worker function will execute on the high priority
* worker thread.
*
* Input Parameters:
* worker - The worker function to execute on the high priority work

View file

@ -58,9 +58,9 @@
* Name: netdown_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function the network goes
* down. The worker function will execute on the low priority worker
* thread.
* Set up to perform a callback to the worker function when the network
* goes down. The worker function will execute on the high priority
* worker thread.
*
* Input Parameters:
* worker - The worker function to execute on the low priority work

View file

@ -8,6 +8,8 @@ menu "Netlink Socket Support"
config NET_NETLINK
bool "Netlink socket support"
default n
depends on SCHED_WORKQUEUE
select WQUEUE_NOTIFIER
---help---
Enable support for Netlink-like IPC sockets that will permit user-
space applications to interact with network services.
@ -26,23 +28,6 @@ config NETLINK_CONNS
---help---
Maximum number of Netlink connections (all tasks).
config NETLINK_MAXPENDING
int "Max pending responses"
default 1
---help---
This defines the maximum number of threads that can be waiting for
a NetLink response. If there is never more than one recv() or
recvfrom() per socket, then there need be only 1. This only
accounts for a perverse case where more than one thread is waiting
on recv() or recvfrom().
config NETLINK_SIGNAL
int "Response notification signal"
default 15
---help---
This is the signal number that is used to wake up threads waiting
for a response to be received.
menu "Netlink Protocols"
config NETLINK_ROUTE

View file

@ -38,7 +38,7 @@
ifeq ($(CONFIG_NET_NETLINK),y)
SOCK_CSRCS += netlink_sockif.c
NET_CSRCS += netlink_conn.c
NET_CSRCS += netlink_conn.c netlink_notifier.c
ifeq ($(CONFIG_NETLINK_ROUTE),y)
NET_CSRCS += netlink_route.c

View file

@ -90,13 +90,9 @@ struct netlink_conn_s
/* poll() support */
int key; /* used to cancel notifications */
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];
/* Queued response data */
@ -180,6 +176,68 @@ FAR struct netlink_conn_s *netlink_nextconn(FAR struct netlink_conn_s *conn);
FAR struct netlink_conn_s *netlink_active(FAR struct sockaddr_nl *addr);
/****************************************************************************
* Name: netlink_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function the Netlink
* response data is received. The worker function will execute on the low
* priority worker thread.
*
* Input Parameters:
* worker - The worker function to execute on the low priority work
* queue when Netlink response data is available.
* conn - The Netlink connection where the response is expected.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* Zero (OK) is returned if the notification was successfully set up.
* A negated error value is returned if an unexpected error occurred
* and no notification will occur.
*
****************************************************************************/
int netlink_notifier_setup(worker_t worker, FAR struct netlink_conn_s *conn,
FAR void *arg);
/****************************************************************************
* Name: netlink_notifier_teardown
*
* Description:
* Eliminate a Netlink response notification previously setup by
* netlink_notifier_setup(). This function should only be called if the
* notification should be aborted prior to the notification. The
* notification will automatically be torn down after the notification.
*
* Input Parameters:
* conn - Teardown the notification for this Netlink connection.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int netlink_notifier_teardown(FAR struct netlink_conn_s *conn);
/****************************************************************************
* Name: netlink_notifier_signal
*
* Description:
* New Netlink response data is available. Execute worker thread
* functions for all threads that wait for response data.
*
* Input Parameters:
* conn - The Netlink connection where the response was just buffered.
*
* Returned Value:
* None.
*
****************************************************************************/
void netlink_notifier_signal(FAR struct netlink_conn_s *conn);
/****************************************************************************
* Name: netlink_tryget_response
*
@ -212,8 +270,9 @@ FAR struct netlink_response_s *
*
* Returned Value:
* The next response from the head of the pending response list is
* always returned. This function will block until a response is
* received if the pending response list is empty.
* returned. This function will block until a response is received if
* the pending response list is empty. NULL will be returned only in the
* event of a failure.
*
****************************************************************************/
@ -238,7 +297,7 @@ bool netlink_check_response(FAR struct socket *psock);
*
* Description:
* Notify a thread until a response be available. The thread will be
* notified via CONFIG_NETLINK_SIGNAL when the response becomes available.
* notified via work queue notifier when the response becomes available.
*
* Returned Value:
* Zero (OK) is returned if the response is already available. Not signal
@ -250,19 +309,6 @@ bool netlink_check_response(FAR struct socket *psock);
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

@ -50,7 +50,6 @@
#include <nuttx/kmalloc.h>
#include <nuttx/semaphore.h>
#include <nuttx/signal.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netlink.h>
@ -111,112 +110,40 @@ static void _netlink_semgive(FAR sem_t *sem)
}
/****************************************************************************
* Name: netlink_notify_waiters
* Name: netlink_response_available
*
* Description:
* Notify all threads waiting for a response.
* Handle a Netlink response available notification.
*
* Assumptions:
* The network is locked.
* Input Parameters:
* Standard work handler parameters
*
* Returned Value:
* None
*
****************************************************************************/
static void netlink_notify_waiters(FAR struct netlink_conn_s *conn)
static void netlink_response_available(FAR void *arg)
{
int ret;
int i;
/* Notify every pending thread. Lock the scheduler while we do this so
* that there is no thrashing: All waiters will be restarted, but only
* the highest priority waiter will get to run and it will receive the
* response.
/* The entire notifier entry is passed to us. That is because we are
* responsible for disposing of the entry via kmm_free() when we are
* finished with it.
*/
sched_lock();
for (i = 0; i < CONFIG_NETLINK_MAXPENDING; i++)
{
if (conn->waiter[i] > 0)
{
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value;
FAR struct work_notifier_entry_s *notifier =
(FAR struct work_notifier_entry_s *)arg;
FAR sem_t *waitsem;
/* Send the CONFIG_NETLINK_SIGNAL signal to the waiter. */
DEBUGASSERT(notifier != NULL && notifier->info.qualifier != NULL);
waitsem = (FAR sem_t *)notifier->info.arg;
value.sival_ptr = conn;
ret = nxsig_queue((int)conn->waiter[i],
(int)CONFIG_NETLINK_SIGNAL, value);
#else
ret = nxsig_queue((int)conn->waiter[i],
(int)CONFIG_NETLINK_SIGNAL, conn);
#endif
if (ret < 0)
{
nerr("ERROR: nxsig_queue() failed: %d\n", ret);
UNUSED(ret);
}
/* Free the notifier entry */
conn->waiter[i] = NETLINK_NO_WAITER;
}
}
kmm_free(notifier);
sched_unlock();
}
/* wakeup the waiter */
/****************************************************************************
* Name: netlink_add_waiter
*
* Description:
* Add one more waiter to the list of waiters.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static int netlink_add_waiter(FAR struct netlink_conn_s *conn)
{
int i;
for (i = 0; i < CONFIG_NETLINK_MAXPENDING; i++)
{
if (conn->waiter[i] <= 0)
{
conn->waiter[i] = getpid();
return OK;
}
}
nerr("ERROR: Too many waiters\n");
DEBUGPANIC();
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;
nxsem_post(waitsem);
}
/****************************************************************************
@ -265,7 +192,6 @@ void netlink_initialize(void)
FAR struct netlink_conn_s *netlink_alloc(void)
{
FAR struct netlink_conn_s *conn;
int i;
/* The free list is protected by a semaphore (that behaves like a mutex). */
@ -277,13 +203,6 @@ FAR struct netlink_conn_s *netlink_alloc(void)
memset(conn, 0, sizeof(*conn));
/* With no waiters */
for (i = 0; i < CONFIG_NETLINK_MAXPENDING; i++)
{
conn->waiter[i] = NETLINK_NO_WAITER;
}
/* Enqueue the connection into the active list */
dq_addlast(&conn->node, &g_active_netlink_connections);
@ -414,7 +333,7 @@ void netlink_add_response(NETLINK_HANDLE handle,
/* Notify any waiters that a response is available */
netlink_notify_waiters(conn);
netlink_notifier_signal(conn);
net_unlock();
}
@ -468,8 +387,9 @@ FAR struct netlink_response_s *
*
* Returned Value:
* The next response from the head of the pending response list is
* always returned. This function will block until a response is
* received if the pending response list is empty.
* returned. This function will block until a response is received if
* the pending response list is empty. NULL will be returned only in the
* event of a failure.
*
****************************************************************************/
@ -478,10 +398,6 @@ FAR struct netlink_response_s *
{
FAR struct netlink_response_s *resp;
FAR struct netlink_conn_s *conn;
FAR struct siginfo info;
unsigned int count;
sigset_t set;
irqstate_t flags;
int ret;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
@ -496,44 +412,64 @@ FAR struct netlink_response_s *
net_lock();
while ((resp = netlink_tryget_response(psock)) == NULL)
{
/* Add this task as a waiter */
sem_t waitsem;
ret = netlink_add_waiter(conn);
/* Set up a semaphore to notify us when a response is queued. */
(void)sem_init(&waitsem, 0, 0);
(void)nxsem_setprotocol(&waitsem, SEM_PRIO_NONE);
/* Set up a notifier to post the semaphore when a response is
* received.
*/
ret = netlink_notifier_setup(netlink_response_available, conn,
&waitsem);
if (ret < 0)
{
nerr("ERROR: netlink_add_waiter failed: %d\n", ret);
nerr("ERROR: netlink_notifier_setup() failed: %d\n", ret);
}
/* Break any network lock while we wait */
flags = enter_critical_section();
ret = net_breaklock(&count);
if (ret < 0)
else
{
/* net_breaklock() would only fail if we were not the holder of
* lock. But we do hold the lock?
/* Call netlink_notify_response() to receive a notification
* when a response has been queued.
*/
nerr("ERROR: net_breaklock failed: %d\n", ret);
DEBUGPANIC();
ret = netlink_notify_response(psock);
if (ret < 0)
{
nerr("ERROR: netlink_notify_response() failed: %d\n", ret);
}
else if (ret == 0)
{
/* The return value of zero means that a response is
* already available and that no notification is
* forthcoming.
*/
}
else
{
/* Otherwise, we have to wait */
_netlink_semtake(&waitsem);
}
}
/* Wait for a response */
/* Clean-up the semaphore */
sem_destroy(&waitsem);
netlink_notifier_teardown(conn);
/* Check for any failures */
sigemptyset(&set);
sigaddset(&set, CONFIG_NETLINK_SIGNAL);
ret = sigwaitinfo(&set, &info);
if (ret < 0)
{
nerr("ERROR: sigwaitinfo() failed: %d\n", ret);
resp = NULL;
break;
}
/* Restore the network lock */
net_restorelock(count);
leave_critical_section(flags);
}
net_unlock();
return resp;
}
@ -567,7 +503,7 @@ bool netlink_check_response(FAR struct socket *psock)
*
* Description:
* Notify a thread until a response be available. The thread will be
* notified via CONFIG_NETLINK_SIGNAL when the response becomes available.
* notified via work queue notifier when the response becomes available.
*
* Returned Value:
* Zero (OK) is returned if the response is already available. Not signal
@ -580,8 +516,6 @@ bool netlink_check_response(FAR struct socket *psock)
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);
@ -592,61 +526,57 @@ int netlink_notify_response(FAR struct socket *psock)
net_lock();
if (((FAR struct netlink_response_s *)sq_peek(&conn->resplist)) == NULL)
{
/* No.. Add this task as a waiter */
sem_t waitsem;
ret = netlink_add_waiter(conn);
/* No.. Set up a semaphore to notify us when a response is queued. */
(void)sem_init(&waitsem, 0, 0);
(void)nxsem_setprotocol(&waitsem, SEM_PRIO_NONE);
/* Set up a notifier to post the semaphore when a response is
* received.
*/
ret = netlink_notifier_setup(netlink_response_available, conn,
&waitsem);
if (ret < 0)
{
nerr("ERROR: netlink_add_waiter failed: %d\n", ret);
nerr("ERROR: netlink_notifier_setup() failed: %d\n", ret);
}
else
{
/* Set up to signal when a response is available */
/* Call netlink_notify_response() to receive a notification
* when a response has been queued.
*/
sigemptyset(&set);
sigaddset(&set, CONFIG_NETLINK_SIGNAL);
ret = sigwaitinfo(&set, &info);
ret = netlink_notify_response(psock);
if (ret < 0)
{
nerr("ERROR: sigwaitinfo() failed: %d\n", ret);
nerr("ERROR: netlink_notify_response() failed: %d\n", ret);
}
else if (ret == 0)
{
/* The return value of zero means that a response is
* already available and that no notification is
* forthcoming.
*/
}
else
{
ret = 1;
/* Otherwise, we have to wait */
_netlink_semtake(&waitsem);
}
}
/* Tear-down the notifier and the semaphore */
netlink_notifier_teardown(conn);
sem_destroy(&waitsem);
}
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;
return ret < 0 ? ret : OK;
}
#endif /* CONFIG_NET_NETLINK */

View file

@ -0,0 +1,148 @@
/****************************************************************************
* net/netlink/netlink_notifier.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <assert.h>
#include <nuttx/wqueue.h>
#include "netlink/netlink.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: netlink_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function the Netlink
* response data is received. The worker function will execute on the low
* priority worker thread.
*
* Input Parameters:
* worker - The worker function to execute on the low priority work
* queue when Netlink response data is available.
* conn - The Netlink connection where the response is expected.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* Zero (OK) is returned if the notification was successfully set up.
* A negated error value is returned if an unexpected error occurred
* and no notification will occur.
*
****************************************************************************/
int netlink_notifier_setup(worker_t worker, FAR struct netlink_conn_s *conn,
FAR void *arg)
{
struct work_notifier_s info;
DEBUGASSERT(worker != NULL && conn != NULL);
/* This is just a simple wrapper around work_notifer_setup(). */
info.evtype = WORK_NETLINK_RESPONSE;
info.qid = LPWORK;
info.qualifier = conn;
info.arg = arg;
info.worker = worker;
conn->key = work_notifier_setup(&info);
return OK;
}
/****************************************************************************
* Name: netlink_notifier_teardown
*
* Description:
* Eliminate a Netlink response notification previously setup by
* netlink_notifier_setup(). This function should only be called if the
* notification should be aborted prior to the notification. The
* notification will automatically be torn down after the notification.
*
* Input Parameters:
* conn - Teardown the notification for this Netlink connection.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int netlink_notifier_teardown(FAR struct netlink_conn_s *conn)
{
DEBUGASSERT(conn != NULL);
int ret = OK;
/* This is just a simple wrapper around work_notifier_teardown(). */
if (conn->key > 0)
{
ret = work_notifier_teardown(conn->key);
conn->key = 0;
}
return ret;
}
/****************************************************************************
* Name: netlink_notifier_signal
*
* Description:
* New Netlink response data is available. Execute worker thread
* functions for all threads that wait for response data.
*
* Input Parameters:
* conn - The Netlink connection where the response was just buffered.
*
* Returned Value:
* None.
*
****************************************************************************/
void netlink_notifier_signal(FAR struct netlink_conn_s *conn)
{
/* This is just a simple wrapper around work_notifier_signal(). */
return work_notifier_signal(WORK_NETLINK_RESPONSE, conn);
}

View file

@ -49,8 +49,9 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/semaphore.h>
#include <nuttx/signal.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/net.h>
#include "netlink/netlink.h"
@ -486,73 +487,45 @@ 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
* Handle a Netlink response available notification.
*
* Input Parameters:
* Standard signal handler parameters
* Standard work handler parameters
*
* Returned Value:
* None
*
****************************************************************************/
static void netlink_response_available(int signo, FAR siginfo_t *siginfo,
FAR void *context)
static void netlink_response_available(FAR void *arg)
{
FAR struct netlink_conn_s *conn;
/* The si_value member should be a reference to a Netlink connection
* structure.
/* The entire notifier entry is passed to us. That is because we are
* responsible for disposing of the entry via kmm_free() when we are
* finished with it.
*/
DEBUGASSERT(siginfo != NULL);
conn = (FAR struct netlink_conn_s *)siginfo->si_value.sival_ptr;
DEBUGASSERT(conn != NULL);
FAR struct work_notifier_entry_s *notifier =
(FAR struct work_notifier_entry_s *)arg;
FAR struct netlink_conn_s *conn;
/* 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?
DEBUGASSERT(notifier != NULL && notifier->info.qualifier != NULL);
conn = (FAR struct netlink_conn_s *)notifier->info.qualifier;
/* Free the notifier entry */
kmm_free(notifier);
/* The following should always be true ... but maybe not in some race
* condition?
*/
sched_lock();
net_lock();
if (conn->pollsem != NULL && conn->pollevent != NULL)
{
/* Wake up the poll() with POLLIN */
@ -565,7 +538,12 @@ static void netlink_response_available(int signo, FAR siginfo_t *siginfo,
nwarn("WARNING: Missing references in connection.\n");
}
netlink_notify_teardown(conn);
/* Allow another poll() */
conn->pollsem = NULL;
conn->pollevent = NULL;
net_unlock();
sched_unlock();
}
@ -632,57 +610,48 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
return OK;
}
/* Set up to be notified by signal when a response is available if
* POLLIN is requested.
/* Set up to be notified when a response is available if POLLIN is
* requested.
*/
if ((fds->events & POLLIN) != 0)
{
struct sigaction act;
/* Set up a signal handler to receive the notification when
* a response has been queued.
* REVISIT: Make sure that the CONFIG_NETLINK_SIGNAL is not
* blocked.
/* Some limitations: There can be only a single outstanding POLLIN
* on the Netlink connection.
*/
if (conn->pollsem != NULL || conn->pollevent != NULL)
{
nerr("ERROR: Multiple polls() on socket not supported.\n");
net_unlock();
return -EBUSY;
nerr("ERROR: Multiple polls() on socket not supported.\n");
net_unlock();
return -EBUSY;
}
/* Set up the notification */
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);
ret = netlink_notifier_setup(netlink_response_available, conn, conn);
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;
nerr("ERROR: netlink_notifier_setup() failed: %d\n", ret);
conn->pollsem = NULL;
conn->pollevent = NULL;
}
else
{
/* Call netlink_notify_response() to receive a signal when
* a response has been queued.
/* Call netlink_notify_response() to receive a notification
* when a response has been queued.
*/
ret = netlink_notify_response(psock);
ret = netlink_notify_response(psock);
if (ret < 0)
{
nerr("ERROR: netlink_notify_response() failed: %d\n", ret);
netlink_notify_teardown(conn);
netlink_notifier_teardown(conn);
conn->pollsem = NULL;
conn->pollevent = NULL;
}
else if (ret == 0)
{
@ -691,8 +660,10 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
* forthcoming.
*/
netlink_notify_teardown(conn);
fds->revents = POLLIN;
netlink_notifier_teardown(conn);
conn->pollsem = NULL;
conn->pollevent = NULL;
fds->revents = POLLIN;
nxsem_post(fds->sem);
}
else
@ -714,8 +685,9 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
{
/* Cancel any response notifications */
ret = netlink_notify_cancel(psock);
netlink_notify_teardown(conn);
ret = netlink_notifier_teardown(conn);
conn->pollsem = NULL;
conn->pollevent = NULL;
}
return ret;
@ -831,7 +803,7 @@ static ssize_t netlink_sendto(FAR struct socket *psock, FAR const void *buf,
#endif
default:
ret= -EOPNOTSUPP;
ret = -EOPNOTSUPP;
break;
}
@ -894,7 +866,7 @@ static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf,
#endif
default:
ret= -EOPNOTSUPP;
ret = -EOPNOTSUPP;
break;
}