Signals were not a good choice of IPC to implement the poll function for several reasons: In order to handle the asynchrnous poll-related event, a substantial amount of state information is needed. Signals are only capable of passing minimal amounts of data. There are also complexities with performing kernel space signal handlers in kernel space code that is better to avoid. So, instead of signals, the equivalent logic was converted to run via a callback that executes on the high-priority work queue.

Squashed commit of the following:

    Fix up some final compile isses.

    net/netdev:  Convert the network down notification logic to use the new wqueue-based notification factility.

    net/udp:  Convert the UDP readahead notification logic to use the new wqueue-based notification factility.

    net/tcp:  Convert the TCP readahead notification logic to use the new wqueue-based notification factility.

    mm/iob:  Convert the IOB notification logic to use the new wqueue-based notification factility.

    sched/wqueue:  Signals are not good IPCs to support the target poll functionality for several reasons including the amount of data that can be passed with a signal and in the fact that in protected and kernel modes, user threads executing signal handlers in protected, kernel memory is problematic.  Instead, convert the same logic to perform the notifications via function callback on the high priority work queue.
This commit is contained in:
Gregory Nutt 2018-09-09 15:01:44 -06:00
parent 20814acad2
commit 9d3148406c
23 changed files with 570 additions and 448 deletions

View File

@ -45,6 +45,10 @@
#include <stdint.h>
#include <stdbool.h>
#ifdef CONFIG_IOB_NOTIFIER
# include <nuttx/wqueue.h>
#endif
#ifdef CONFIG_MM_IOB
/****************************************************************************
@ -208,16 +212,15 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob);
* Name: iob_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
* Set up to perform a callback to the worker function when an IOB is
* available. The worker function will execute on the high priority
* worker thread.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work queue
* when the event occurs.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
@ -232,7 +235,7 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob);
****************************************************************************/
#ifdef CONFIG_IOB_NOTIFIER
int iob_notifier_setup(int pid, int signo);
int iob_notifier_setup(worker_t worker, FAR void *arg);
#endif
/****************************************************************************
@ -258,6 +261,30 @@ int iob_notifier_setup(int pid, int signo);
int iob_notifier_teardown(int key);
#endif
/****************************************************************************
* Name: iob_notifier_signal
*
* Description:
* An IOB has become available. Signal all threads waiting for an IOB
* that an IOB is available.
*
* When an IOB becomes available, *all* of the workers waiting for an
* IOB will be executed. If there are multiple workers for waiting an IOB
* then only the first to execute will get the IOB. Others will
* need to call iob_notify_setup() once again.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_IOB_NOTIFIER
void iob_notifier_signal(void);
#endif
/****************************************************************************
* Name: iob_free_chain
*

View File

@ -46,23 +46,6 @@
#include <stdbool.h>
#include <signal.h>
/****************************************************************************
* Public Types
****************************************************************************/
/* This is an enumeration of the various signal events that may be
* notified via nxig_notifier_signal().
*/
enum nxsig_evtype_e
{
NXSIG_IOB_AVAIL = 1, /* Signal availability of an IOB */
NXSIG_NET_DOWN, /* Signal that the network is down */
NXSIG_TCP_READAHEAD, /* Signal that TCP read-ahead data is available */
NXSIG_TCP_DISCONNECT, /* Signal loss of TCP connection */
NXSIG_UDP_READAHEAD, /* Signal that TCP read-ahead data is available */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@ -471,94 +454,4 @@ int nxsig_usleep(useconds_t usec);
int nxsig_evthread(pid_t pid, FAR struct sigevent *event);
#endif
/****************************************************************************
* Name: nxsig_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then qualifier value may be recovered in the sival_ptr value of
* the struct siginfo instance.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided,
* then the PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* evtype - The event type.
* qualifier - Event qualifier to distinguish different cases of the
* generic event type.
*
* Returned Value:
* > 0 - The key which may be used later in a call to
* nxsig_notifier_teardown().
* == 0 - Not used (reserved for wrapper functions).
* < 0 - An unexpected error occurred and no signal will be sent. The
* returned value is a negated errno value that indicates the
* nature of the failure.
*
****************************************************************************/
#ifdef CONFIG_SIG_NOTIFIER
int nxsig_notifier_setup(int pid, int signo, enum nxsig_evtype_e evtype,
FAR void *qualifier);
#endif
/****************************************************************************
* Name: nxsig_notifier_teardown
*
* Description:
* Eliminate a notification previously setup by nxsig_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 signal is sent.
*
* Input Parameters:
* key - The key value returned from a previous call to
* nxsig_notifier_setup().
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
#ifdef CONFIG_SIG_NOTIFIER
int nxsig_notifier_teardown(int key);
#endif
/****************************************************************************
* Name: nxsig_notifier_signal
*
* Description:
* An event has just occurred. Signal all threads waiting for that event.
*
* When an IOB becomes available, *all* of the waiters in this thread will
* be signaled. If there are multiple waiters for a resource then only
* the highest priority thread will get the resource. Lower priority
* threads will need to call nxsig_notify once again.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then qualifier value may be obtained in the sival_ptr value of
* the struct siginfo instance.
*
* Input Parameters:
* evtype - The type of the event that just occurred.
* qualifier - Event qualifier to distinguish different cases of the
* generic event type.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_SIG_NOTIFIER
void nxsig_notifier_signal(enum nxsig_evtype_e evtype,
FAR void *qualifier);
#endif
#endif /* __INCLUDE_NUTTX_SIGNAL_H */

View File

@ -278,6 +278,29 @@ struct work_s
clock_t delay; /* Delay until work performed */
};
/* This is an enumeration of the various events that may be
* notified via nxig_notifier_signal().
*/
enum work_evtype_e
{
WORK_IOB_AVAIL = 1, /* Notify availability of an IOB */
WORK_NET_DOWN, /* Notify that the network is down */
WORK_TCP_READAHEAD, /* Notify that TCP read-ahead data is available */
WORK_TCP_DISCONNECT, /* Notify loss of TCP connection */
WORK_UDP_READAHEAD, /* Notify that TCP read-ahead data is available */
};
/* This structure describes one notification */
struct work_notifier_s
{
uint8_t evtype; /* See enum work_evtype_e */
FAR void *qualifier; /* Event qualifier value */
FAR void *arg; /* User-defined worker function argument */
worker_t worker; /* The worker function to schedule */
};
/****************************************************************************
* Public Data
****************************************************************************/
@ -444,6 +467,78 @@ void lpwork_boostpriority(uint8_t reqprio);
void lpwork_restorepriority(uint8_t reqprio);
#endif
/****************************************************************************
* Name: work_notifier_setup
*
* Description:
* Set up to provide a notification when event is signaled.
*
* Input Parameters:
* info - Describes the work notification.
*
* Returned Value:
* > 0 - The key which may be used later in a call to
* work_notifier_teardown().
* == 0 - Not used (reserved for wrapper functions).
* < 0 - An unexpected error occurred and no signal will be sent. The
* returned value is a negated errno value that indicates the
* nature of the failure.
*
****************************************************************************/
#ifdef CONFIG_WQUEUE_NOTIFIER
int work_notifier_setup(FAR struct work_notifier_s *info);
#endif
/****************************************************************************
* Name: work_notifier_teardown
*
* Description:
* Eliminate a notification previously setup by work_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 signal is sent.
*
* Input Parameters:
* key - The key value returned from a previous call to
* work_notifier_setup().
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
#ifdef CONFIG_WQUEUE_NOTIFIER
int work_notifier_teardown(int key);
#endif
/****************************************************************************
* Name: work_notifier_signal
*
* Description:
* An event has just occurred. Signal all threads waiting for that event.
*
* When an event of interest occurs, *all* of the workers waiting for this
* event will be executed. If there are multiple workers for a resource
* then only the first to execute will get the resource. Others will
* need to call work_notifier_setup() once again.
*
* Input Parameters:
* evtype - The type of the event that just occurred.
* qualifier - Event qualifier to distinguish different cases of the
* generic event type.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_WQUEUE_NOTIFIER
void work_notifier_signal(enum work_evtype_e evtype,
FAR void *qualifier);
#endif
#undef EXTERN
#ifdef __cplusplus
}

View File

@ -62,13 +62,13 @@ config IOB_THROTTLE
config IOB_NOTIFIER
bool "Support IOB notifications"
default n
select SIG_NOTIFIER
depends on !DISABLE_SIGNALS
depends on SCHED_HPWORK
---help---
Enable building of IOB notifier logic that will send a signal to
a kernel thread when an IOB is available. This is is a general
purpose notifier, but was developed specifically to support poll()
logic where the poll must wait for an IOB to become available.
Enable building of IOB notifier logic that will execute a worker
function on the high priority work queue when an IOB is available.
This is is a general purpose notifier, but was developed specifically to
support poll() logic where the poll must wait for an IOB to become
available.
config IOB_DEBUG
bool "Force I/O buffer debug"

View File

@ -40,8 +40,9 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <assert.h>
#include <nuttx/signal.h>
#include <nuttx/wqueue.h>
#include <nuttx/mm/iob.h>
#include "iob.h"
@ -56,16 +57,15 @@
* Name: iob_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
* Set up to perform a callback to the worker function when an IOB is
* available. The worker function will execute on the high priority
* worker thread.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work queue
* when the event occurs.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
@ -79,8 +79,12 @@
*
****************************************************************************/
int iob_notifier_setup(int pid, int signo)
int iob_notifier_setup(worker_t worker, FAR void *arg)
{
struct work_notifier_s info;
DEBUGASSERT(worker != NULL);
/* If there are already free IOBs, then return zero without setting up the
* notification.
*/
@ -90,9 +94,14 @@ int iob_notifier_setup(int pid, int signo)
return 0;
}
/* Otherwise, this is just a simple wrapper around nxsig_notifer_setup(). */
/* Otherwise, this is just a simple wrapper around work_notifer_setup(). */
return nxsig_notifier_setup(pid, signo, NXSIG_IOB_AVAIL, NULL);
info.evtype = WORK_IOB_AVAIL;
info.qualifier = NULL;
info.arg = arg;
info.worker = worker;
return work_notifier_setup(&info);
}
/****************************************************************************
@ -116,9 +125,9 @@ int iob_notifier_setup(int pid, int signo)
int iob_notifier_teardown(int key)
{
/* This is just a simple wrapper around nxsig_notifier_teardown(). */
/* This is just a simple wrapper around work_notifier_teardown(). */
return nxsig_notifier_teardown(key);
return work_notifier_teardown(key);
}
/****************************************************************************
@ -128,10 +137,10 @@ int iob_notifier_teardown(int key)
* An IOB has become available. Signal all threads waiting for an IOB
* that an IOB is available.
*
* When an IOB becomes available, *all* of the waiters in this thread will
* be signaled. If there are multiple waiters then only the highest
* priority thread will get the IOB. Lower priority threads will need to
* call iob_notifier_setup() once again.
* When an IOB becomes available, *all* of the workers waiting for an
* IOB will be executed. If there are multiple workers waiting for an IOB
* then only the first to execute will get the IOB. Others will
* need to call iob_notify_setup() once again.
*
* Input Parameters:
* None.
@ -143,9 +152,9 @@ int iob_notifier_teardown(int key)
void iob_notifier_signal(void)
{
/* This is just a simple wrapper around nxsig_notifier_signal(). */
/* This is just a simple wrapper around work_notifier_signal(). */
return nxsig_notifier_signal(NXSIG_IOB_AVAIL, NULL);
return work_notifier_signal(WORK_IOB_AVAIL, NULL);
}
#endif /* CONFIG_IOB_NOTIFIER */

View File

@ -39,10 +39,9 @@ config NETDEV_IFINDEX
config NETDOWN_NOTIFIER
bool "Support network down notifications"
default n
select SIG_NOTIFIER
depends on !DISABLE_SIGNALS
depends on SCHED_HPWORK
---help---
Enable building of logic that will send a signal to a kernel
Enable building of logic that will execute on the high priority work
thread when the network is taken down. This is is a general purpose
notifier, but was developed specifically to support SIGHUP poll()
logic.

View File

@ -47,6 +47,10 @@
#include <nuttx/net/ip.h>
#ifdef CONFIG_NETDOWN_NOTIFIER
# include <nuttx/wqueue.h>
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -464,24 +468,24 @@ int netdev_ipv6_ifconf(FAR struct lifconf *lifc);
*
****************************************************************************/
#ifdef CONFIG_NETDOWN_NOTIFIER
int netdev_dev_lladdrsize(FAR struct net_driver_s *dev);
#endif
/****************************************************************************
* Name: netdown_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
* 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.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work
* queue when data is available in the UDP readahead buffer.
* dev - The network driver to be monitored
*
* arg - A user-defined argument that will be available to the worker
* function when it runs.
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
* key that may be used later in a call to
@ -495,14 +499,15 @@ int netdev_dev_lladdrsize(FAR struct net_driver_s *dev);
****************************************************************************/
#ifdef CONFIG_NETDOWN_NOTIFIER
int netdown_notifier_setup(int pid, int signo, FAR struct net_driver_s *dev);
int netdown_notifier_setup(worker_t worker, FAR struct net_driver_s *dev,
FAR void *arg);
#endif
/****************************************************************************
* Name: netdown_notifier_teardown
*
* Description:
* Eliminate a TCP read-ahead notification previously setup by
* Eliminate a network down notification previously setup by
* netdown_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 signal is sent.
@ -525,13 +530,8 @@ int netdown_notifier_teardown(int key);
* Name: netdown_notifier_signal
*
* Description:
* Read-ahead data has been buffered. Signal all threads waiting for
* read-ahead data to become available.
*
* When the read-ahead data becomes available, *all* of the waiters in
* this thread will be signaled. If there are multiple waiters then only
* the highest priority thread will get the data. Lower priority threads
* will need to call netdown_notifier_setup() once again.
* A network has gone down has been buffered. Execute worker thread
* functions for all threads monitoring the state of the device.
*
* Input Parameters:
* dev - The TCP connection where read-ahead data was just buffered.

View File

@ -40,8 +40,9 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <assert.h>
#include <nuttx/signal.h>
#include <nuttx/wqueue.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
@ -57,18 +58,16 @@
* Name: netdown_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
* 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.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work
* queue when data is available in the UDP readahead buffer.
* dev - The network driver to be monitored
*
* arg - A user-defined argument that will be available to the worker
* function when it runs.
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
* key that may be used later in a call to
@ -81,8 +80,13 @@
*
****************************************************************************/
int netdown_notifier_setup(int pid, int signo, FAR struct net_driver_s *dev)
int netdown_notifier_setup(worker_t worker, FAR struct net_driver_s *dev,
FAR void *arg)
{
struct work_notifier_s info;
DEBUGASSERT(worker != NULL);
/* If network driver is already down, then return zero without setting up
* the notification.
*/
@ -92,16 +96,21 @@ int netdown_notifier_setup(int pid, int signo, FAR struct net_driver_s *dev)
return 0;
}
/* Otherwise, this is just a simple wrapper around nxsig_notifer_setup(). */
/* Otherwise, this is just a simple wrapper around work_notifer_setup(). */
return nxsig_notifier_setup(pid, signo, NXSIG_NET_DOWN, dev);
info.evtype = WORK_NET_DOWN;
info.qualifier = dev;
info.arg = arg;
info.worker = worker;
return work_notifier_setup(&info);
}
/****************************************************************************
* Name: netdown_notifier_teardown
*
* Description:
* Eliminate a TCP read-ahead notification previously setup by
* Eliminate a network down notification previously setup by
* netdown_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 signal is sent.
@ -118,22 +127,17 @@ int netdown_notifier_setup(int pid, int signo, FAR struct net_driver_s *dev)
int netdown_notifier_teardown(int key)
{
/* This is just a simple wrapper around nxsig_notifier_teardown(). */
/* This is just a simple wrapper around work_notifier_teardown(). */
return nxsig_notifier_teardown(key);
return work_notifier_teardown(key);
}
/****************************************************************************
* Name: netdown_notifier_signal
*
* Description:
* Read-ahead data has been buffered. Signal all threads waiting for
* read-ahead data to become available.
*
* When the read-ahead data becomes available, *all* of the waiters in
* this thread will be signaled. If there are multiple waiters then only
* the highest priority thread will get the data. Lower priority threads
* will need to call netdown_notifier_setup() once again.
* A network has gone down has been buffered. Execute worker thread
* functions for all threads monitoring the state of the device.
*
* Input Parameters:
* dev - The TCP connection where read-ahead data was just buffered.
@ -145,9 +149,9 @@ int netdown_notifier_teardown(int key)
void netdown_notifier_signal(FAR struct net_driver_s *dev)
{
/* This is just a simple wrapper around nxsig_notifier_signal(). */
/* This is just a simple wrapper around work_notifier_signal(). */
return nxsig_notifier_signal(NXSIG_NET_DOWN, dev);
return work_notifier_signal(WORK_NET_DOWN, dev);
}
#endif /* CONFIG_NETDOWN_NOTIFIER */

View File

@ -69,14 +69,13 @@ config NET_TCP_READAHEAD
config TCP_READAHEAD_NOTIFIER
bool "Support TCP read-ahead notifications"
default n
select SIG_NOTIFIER
depends on NET_TCP_READAHEAD && !DISABLE_SIGNALS
depends on NET_TCP_READAHEAD && SCHED_HPWORK
---help---
Enable building of TCP read-ahead notifier logic that will send a
signal to a kernel thread when an TCP read-ahead data has been
buffered. This is is a general purpose notifier, but was developed
specifically to support TCP poll() logic where the poll must wait
for incoming TCP data to be buffered.
Enable building of TCP read-ahead notifier logic that will execute a
worker function on the high priority work queue when read-ahead data
is available. This is is a general purpose notifier, but was
developed specifically to support poll() logic where the poll must
wait for read-ahead data to become available.
config NET_TCP_WRITE_BUFFERS
bool "Enable TCP/IP write buffering"

View File

@ -49,6 +49,10 @@
#include <nuttx/mm/iob.h>
#include <nuttx/net/ip.h>
#ifdef CONFIG_TCP_READAHEAD_NOTIFIER
# include <nuttx/wqueue.h>
#endif
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
/****************************************************************************
@ -1546,21 +1550,16 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
* Name: tcp_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then TCP connection structure pointer may be recovered in the
* sival_ptr value of the struct siginfo instance.
* Set up to perform a callback to the worker function when an TCP data
* is added to the read-ahead buffer. The worker function will execute
* on the high priority worker thread.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work
* queue when data is available in the TCP readahead buffer.
* conn - The TCP connection where read-ahead data is needed.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
@ -1575,7 +1574,8 @@ int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
****************************************************************************/
#ifdef CONFIG_TCP_READAHEAD_NOTIFIER
int tcp_notifier_setup(int pid, int signo, FAR struct tcp_conn_s *conn);
int tcp_notifier_setup(worker_t worker, FAR struct tcp_conn_s *conn,
FAR void *arg);
#endif
/****************************************************************************
@ -1608,14 +1608,10 @@ int tcp_notifier_teardown(int key);
* Read-ahead data has been buffered. Signal all threads waiting for
* read-ahead data to become available.
*
* When the read-ahead data becomes available, *all* of the waiters in
* this thread will be signaled. If there are multiple waiters then only
* the highest priority thread will get the data. Lower priority threads
* will need to call tcp_notifier_setup() once again.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then TCP connection structure pointer may be obtained in the
* sival_ptr value of the struct siginfo instance.
* When read-ahead data becomes available, *all* of the workers waiting
* for read-ahead data will be executed. If there are multiple workers
* waiting for read-ahead data then only the first to execute will get the
* data. Others will need to call tcp_notifier_setup() once again.
*
* Input Parameters:
* conn - The TCP connection where read-ahead data was just buffered.

View File

@ -40,8 +40,9 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <assert.h>
#include <nuttx/signal.h>
#include <nuttx/wqueue.h>
#include <nuttx/mm/iob.h>
#include "tcp/tcp.h"
@ -56,21 +57,16 @@
* Name: tcp_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then TCP connection structure pointer may be recovered in the
* sival_ptr value of the struct siginfo instance.
* Set up to perform a callback to the worker function when an TCP data
* is added to the read-ahead buffer. The worker function will execute
* on the high priority worker thread.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work
* queue when data is available in the TCP readahead buffer.
* conn - The TCP connection where read-ahead data is needed.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
@ -84,8 +80,13 @@
*
****************************************************************************/
int tcp_notifier_setup(int pid, int signo, FAR struct tcp_conn_s *conn)
int tcp_notifier_setup(worker_t worker, FAR struct tcp_conn_s *conn,
FAR void *arg)
{
struct work_notifier_s info;
DEBUGASSERT(worker != NULL);
/* If there is already buffered read-ahead data, then return zero without
* setting up the notification.
*/
@ -95,9 +96,14 @@ int tcp_notifier_setup(int pid, int signo, FAR struct tcp_conn_s *conn)
return 0;
}
/* Otherwise, this is just a simple wrapper around nxsig_notifer_setup(). */
/* Otherwise, this is just a simple wrapper around work_notifer_setup(). */
return nxsig_notifier_setup(pid, signo, NXSIG_TCP_READAHEAD, conn);
info.evtype = WORK_TCP_READAHEAD;
info.qualifier = conn;
info.arg = arg;
info.worker = worker;
return work_notifier_setup(&info);
}
/****************************************************************************
@ -121,9 +127,9 @@ int tcp_notifier_setup(int pid, int signo, FAR struct tcp_conn_s *conn)
int tcp_notifier_teardown(int key)
{
/* This is just a simple wrapper around nxsig_notifier_teardown(). */
/* This is just a simple wrapper around work_notifier_teardown(). */
return nxsig_notifier_teardown(key);
return work_notifier_teardown(key);
}
/****************************************************************************
@ -133,14 +139,10 @@ int tcp_notifier_teardown(int key)
* Read-ahead data has been buffered. Signal all threads waiting for
* read-ahead data to become available.
*
* When the read-ahead data becomes available, *all* of the waiters in
* this thread will be signaled. If there are multiple waiters then only
* the highest priority thread will get the data. Lower priority threads
* will need to call tcp_notifier_setup() once again.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then TCP connection structure pointer may be obtained in the
* sival_ptr value of the struct siginfo instance.
* When read-ahead data becomes available, *all* of the workers waiting
* for read-ahead data will be executed. If there are multiple workers
* waiting for read-ahead data then only the first to execute will get the
* data. Others will need to call tcp_notifier_setup() once again.
*
* Input Parameters:
* conn - The TCP connection where read-ahead data was just buffered.
@ -152,9 +154,9 @@ int tcp_notifier_teardown(int key)
void tcp_notifier_signal(FAR struct tcp_conn_s *conn)
{
/* This is just a simple wrapper around nxsig_notifier_signal(). */
/* This is just a simple wrapper around work_notifier_signal(). */
return nxsig_notifier_signal(NXSIG_TCP_READAHEAD, conn);
return work_notifier_signal(WORK_TCP_READAHEAD, conn);
}
#endif /* CONFIG_TCP_READAHEAD_NOTIFIER */

View File

@ -60,14 +60,13 @@ config NET_UDP_READAHEAD
config UDP_READAHEAD_NOTIFIER
bool "Support UDP read-ahead notifications"
default n
select SIG_NOTIFIER
depends on NET_UDP_READAHEAD && !DISABLE_SIGNALS
depends on NET_UDP_READAHEAD && SCHED_HPWORK
---help---
Enable building of UDP read-ahead notifier logic that will send a
signal to a kernel thread when an UDP read-ahead data has been
buffered. This is is a general purpose notifier, but was developed
specifically to support UDP poll() logic where the poll must wait
for incoming UDP data to be buffered.
Enable building of UDP read-ahead notifier logic that will execute a
worker function on the high priority work queue when read-ahead data
is available. This is is a general purpose notifier, but was
developed specifically to support poll() logic where the poll must
wait for read-ahead data to become available.
config NET_UDP_WRITE_BUFFERS
bool "Enable UDP/IP write buffering"

View File

@ -53,6 +53,10 @@
# include <nuttx/mm/iob.h>
#endif
#ifdef CONFIG_UDP_READAHEAD_NOTIFIER
# include <nuttx/wqueue.h>
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
/****************************************************************************
@ -647,21 +651,16 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
* Name: udp_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then UDP connection structure pointer may be recovered in the
* sival_ptr value of the struct siginfo instance.
* Set up to perform a callback to the worker function when an UDP data
* is added to the read-ahead buffer. The worker function will execute
* on the high priority worker thread.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work
* queue when data is available in the UDP readahead buffer.
* conn - The UDP connection where read-ahead data is needed.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
@ -676,7 +675,8 @@ int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
****************************************************************************/
#ifdef CONFIG_UDP_READAHEAD_NOTIFIER
int udp_notifier_setup(int pid, int signo, FAR struct udp_conn_s *conn);
int udp_notifier_setup(worker_t worker, FAR struct udp_conn_s *conn,
FAR void *arg);
#endif
/****************************************************************************
@ -709,14 +709,10 @@ int udp_notifier_teardown(int key);
* Read-ahead data has been buffered. Signal all threads waiting for
* read-ahead data to become available.
*
* When the read-ahead data becomes available, *all* of the waiters in
* this thread will be signaled. If there are multiple waiters then only
* the highest priority thread will get the data. Lower priority threads
* will need to call udp_notifier_setup() once again.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then UDP connection structure pointer may be obtained in the
* sival_ptr value of the struct siginfo instance.
* When read-ahead data becomes available, *all* of the workers waiting
* for read-ahead data will be executed. If there are multiple workers
* waiting for read-ahead data then only the first to execute will get the
* data. Others will need to call udp_notifier_setup() once again.
*
* Input Parameters:
* conn - The UDP connection where read-ahead data was just buffered.

View File

@ -40,8 +40,9 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <assert.h>
#include <nuttx/signal.h>
#include <nuttx/wqueue.h>
#include <nuttx/mm/iob.h>
#include "udp/udp.h"
@ -56,21 +57,16 @@
* Name: udp_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then UDP connection structure pointer may be recovered in the
* sival_ptr value of the struct siginfo instance.
* Set up to perform a callback to the worker function when an UDP data
* is added to the read-ahead buffer. The worker function will execute
* on the high priority worker thread.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided, then the
* PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* worker - The worker function to execute on the high priority work
* queue when data is available in the UDP readahead buffer.
* conn - The UDP connection where read-ahead data is needed.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
@ -84,8 +80,13 @@
*
****************************************************************************/
int udp_notifier_setup(int pid, int signo, FAR struct udp_conn_s *conn)
int udp_notifier_setup(worker_t worker, FAR struct udp_conn_s *conn,
FAR void *arg)
{
struct work_notifier_s info;
DEBUGASSERT(worker != NULL);
/* If there is already buffered read-ahead data, then return zero without
* setting up the notification.
*/
@ -95,9 +96,14 @@ int udp_notifier_setup(int pid, int signo, FAR struct udp_conn_s *conn)
return 0;
}
/* Otherwise, this is just a simple wrapper around nxsig_notifer_setup(). */
/* Otherwise, this is just a simple wrapper around work_notifer_setup(). */
return nxsig_notifier_setup(pid, signo, NXSIG_UDP_READAHEAD, conn);
info.evtype = WORK_UDP_READAHEAD;
info.qualifier = conn;
info.arg = arg;
info.worker = worker;
return work_notifier_setup(&info);
}
/****************************************************************************
@ -121,9 +127,9 @@ int udp_notifier_setup(int pid, int signo, FAR struct udp_conn_s *conn)
int udp_notifier_teardown(int key)
{
/* This is just a simple wrapper around nxsig_notifier_teardown(). */
/* This is just a simple wrapper around work_notifier_teardown(). */
return nxsig_notifier_teardown(key);
return work_notifier_teardown(key);
}
/****************************************************************************
@ -133,14 +139,10 @@ int udp_notifier_teardown(int key)
* Read-ahead data has been buffered. Signal all threads waiting for
* read-ahead data to become available.
*
* When the read-ahead data becomes available, *all* of the waiters in
* this thread will be signaled. If there are multiple waiters then only
* the highest priority thread will get the data. Lower priority threads
* will need to call udp_notifier_setup() once again.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then UDP connection structure pointer may be obtained in the
* sival_ptr value of the struct siginfo instance.
* When read-ahead data becomes available, *all* of the workers waiting
* for read-ahead data will be executed. If there are multiple workers
* waiting for read-ahead data then only the first to execute will get the
* data. Others will need to call udp_notifier_setup() once again.
*
* Input Parameters:
* conn - The UDP connection where read-ahead data was just buffered.
@ -152,9 +154,9 @@ int udp_notifier_teardown(int key)
void udp_notifier_signal(FAR struct udp_conn_s *conn)
{
/* This is just a simple wrapper around nxsig_notifier_signal(). */
/* This is just a simple wrapper around work_notifier_signal(). */
return nxsig_notifier_signal(NXSIG_UDP_READAHEAD, conn);
return work_notifier_signal(WORK_UDP_READAHEAD, conn);
}
#endif /* CONFIG_UDP_READAHEAD_NOTIFIER */

View File

@ -1174,26 +1174,6 @@ endmenu # RTOS hooks
menu "Signal Configuration"
config SIG_NOTIFIER
bool "Generic Signal notifier"
default n
---help---
Enable building of signal notifier logic that will send a signal to
a kernel thread when an event occurs. This is is a general
purpose notifier, but was developed specifically to support poll()
logic where the poll must wait for an resources to become available.
config SIG_NOTIFIER_NWAITERS
int "Number of signal waiters"
default 8
range 1 32766
depends on SIG_NOTIFIER
---help---
If CONFIG_SIG_NOTIFIER is selected, then a pre-allocated pool of
notification structures will be allocated to hold information about
pending notifications. This then determines an upper limit for the
number of waiters that can be supported.
config SIG_EVTHREAD
bool "Support SIGEV_THHREAD"
default n
@ -1480,6 +1460,26 @@ config SCHED_HPWORKSTACKSIZE
---help---
The stack size allocated for the worker thread. Default: 2K.
config WQUEUE_NOTIFIER
bool "Generic work notifier"
default n
---help---
Enable building of work queue notifier logic that will execute a
worker function an event occurs. This is is a general purpose
notifier, but was developed specifically to support poll() logic
where the poll must wait for an resources to become available.
config WQUEUE_NOTIFIER_NWAITERS
int "Number of notifications"
default 16
range 1 32766
depends on WQUEUE_NOTIFIER
---help---
If CONFIG_WQUEUE_NOTIFIER is selected, then a pre-allocated pool of
notification structures will be used to hold information about
pending notifications. This then determines an upper limit for the
number of waiters that can be supported.
endif # SCHED_HPWORK
config SCHED_LPWORK

View File

@ -68,6 +68,9 @@
#ifndef CONFIG_DISABLE_PTHREAD
# include "pthread/pthread.h"
#endif
#ifdef CONFIG_SCHED_WORKQUEUE
# include "wqueue/wqueue.h"
#endif
#include "clock/clock.h"
#include "timer/timer.h"
#include "irq/irq.h"
@ -702,6 +705,12 @@ void os_start(void)
net_setup();
#endif
#ifdef CONFIG_SCHED_WORKQUEUE
/* Initialize work queue data structures */
work_initialize();
#endif
/* The processor specific details of running the operating system
* will be handled here. Such things as setting up interrupt
* service routines and starting the clock are some of the things

View File

@ -52,10 +52,6 @@ ifeq ($(CONFIG_SIG_EVTHREAD),y)
CSRCS += sig_evthread.c
endif
ifeq ($(CONFIG_SIG_NOTIFIER),y)
CSRCS += sig_notifier.c
endif
# Include signal build support
DEPPATH += --dep-path signal

View File

@ -234,12 +234,6 @@ void nxsig_initialize(void)
nxsig_alloc_pendingsignalblock(&g_sigpendingirqsignal,
NUM_INT_SIGNALS_PENDING,
SIG_ALLOC_IRQ);
#ifdef CONFIG_SIG_NOTIFIER
/* Initialize the generic notifier facility */
nxsig_notifier_initialize();
#endif
}
/****************************************************************************

View File

@ -167,12 +167,6 @@ struct task_group_s;
void weak_function nxsig_initialize(void);
void nxsig_alloc_actionblock(void);
/* sig_notifier.c */
#ifdef CONFIG_SIG_NOTIFIER
void nxsig_notifier_initialize(void);
#endif
/* sig_action.c */
void nxsig_release_action(FAR sigactq_t *sigact);

View File

@ -37,7 +37,8 @@
ifeq ($(CONFIG_SCHED_WORKQUEUE),y)
CSRCS += kwork_queue.c kwork_process.c kwork_cancel.c kwork_signal.c
CSRCS += kwork_initialize.c kwork_queue.c kwork_process.c kwork_cancel.c
CSRCS += kwork_signal.c
# Add high priority work queue files
@ -54,6 +55,12 @@ CSRCS += kwork_inherit.c
endif # CONFIG_PRIORITY_INHERITANCE
endif # CONFIG_SCHED_LPWORK
# Add work queue notifier support
ifeq ($(CONFIG_WQUEUE_NOTIFIER),y)
CSRCS += kwork_notifier.c
endif
# Include wqueue build support
DEPPATH += --dep-path wqueue

View File

@ -0,0 +1,73 @@
/****************************************************************************
* sched/wqueue/kwork_initialize.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 "wqueue/wqueue.h"
#ifdef CONFIG_SCHED_WORKQUEUE
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: work_initialize
*
* Description:
* One time initialization of the work queue data structures.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void work_initialize(void)
{
#ifdef CONFIG_WQUEUE_NOTIFIER
/* Initialize work queue notifier data structures */
work_notifier_initialize();
#endif
}
#endif /* CONFIG_SCHED_WORKQUEUE */

View File

@ -1,5 +1,5 @@
/****************************************************************************
* sched/signal/sig_notifier.c
* sched/wqueue/kwork_notifier.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@ -43,31 +43,40 @@
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <sched.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/signal.h>
#include <nuttx/kmalloc.h>
#include <nuttx/semaphore.h>
#include <nuttx/wqueue.h>
#include "signal/signal.h"
#ifdef CONFIG_SIG_NOTIFIER
#ifdef CONFIG_WQUEUE_NOTIFIER
/****************************************************************************
* Private Types
****************************************************************************/
/* This is the saved information for one notification */
/* The full allocated notification will hold additional information. The
* allocated notification information persist until the work is executed
* and must be freed using kmm_free() by the work.
*/
struct nxsig_notifier_s
struct work_notifier_alloc_s
{
FAR struct nxsig_notifier_s *flink; /* Supports a singly linked list */
FAR void *qualifier; /* Event qualifier value */
uint8_t signo; /* The signal number for notification */
uint8_t evtype; /* See enum nxsig_evtype_e */
pid_t pid; /* The PID to be notified */
int16_t key; /* Unique ID for this notification */
struct work_notifier_s info; /* The notification info */
struct work_s work; /* Used for scheduling the work */
};
/* This structure describes one notification list entry */
struct work_notifier_entry_s
{
FAR struct work_notifier_entry_s *flink;
FAR struct work_notifier_alloc_s *alloc; /* Allocated notification info copy */
int16_t key; /* Unique ID for the notification */
};
/****************************************************************************
@ -76,21 +85,22 @@ struct nxsig_notifier_s
/* This is a statically allocated pool of notification structures */
static struct nxsig_notifier_s g_notifier_pool[CONFIG_SIG_NOTIFIER_NWAITERS];
static struct work_notifier_entry_s
g_notifier_pool[CONFIG_WQUEUE_NOTIFIER_NWAITERS];
/* This is a list of free notification structures */
static FAR struct nxsig_notifier_s *g_notifier_free;
static FAR struct work_notifier_entry_s *g_notifier_free;
/* This is a singly linked list of pending notifications. When an event
* occurs available, *all* of the waiters for that event in this list will
* be signaled and the entry will be freed. If there are multiple waiters
* for some resource, then only the highest priority thread will get the
* resource. Lower priority threads will need to call nxsig_notifier_setup()
* resource. Lower priority threads will need to call work_notifier_setup()
* once again.
*/
static FAR struct nxsig_notifier_s *g_notifier_pending;
static FAR struct work_notifier_entry_s *g_notifier_pending;
/* This semaphore is used as mutex to enforce mutually exclusive access to
* the notification data structures.
@ -107,16 +117,16 @@ static uint16_t g_notifier_key;
****************************************************************************/
/****************************************************************************
* Name: nxsig_notifier_alloc
* Name: work_notifier_alloc
*
* Description:
* Allocate a notification structure by removing it from the free list.
*
****************************************************************************/
static FAR struct nxsig_notifier_s *nxsig_notifier_alloc(void)
static FAR struct work_notifier_entry_s *work_notifier_alloc(void)
{
FAR struct nxsig_notifier_s *notifier;
FAR struct work_notifier_entry_s *notifier;
notifier = g_notifier_free;
if (notifier != NULL)
@ -129,7 +139,7 @@ static FAR struct nxsig_notifier_s *nxsig_notifier_alloc(void)
}
/****************************************************************************
* Name: nxsig_notifier_free
* Name: work_notifier_free
*
* Description:
* Free a notification structure by returning it to the head of the free
@ -137,14 +147,15 @@ static FAR struct nxsig_notifier_s *nxsig_notifier_alloc(void)
*
****************************************************************************/
static void nxsig_notifier_free(FAR struct nxsig_notifier_s *notifier)
static inline void
work_notifier_free(FAR struct work_notifier_entry_s *notifier)
{
notifier->flink = g_notifier_free;
g_notifier_free = notifier;
}
/****************************************************************************
* Name: nxsig_notifier_find
* Name: work_notifier_find
*
* Description:
* Given a unique key for notification, find the corresponding notification
@ -152,11 +163,11 @@ static void nxsig_notifier_free(FAR struct nxsig_notifier_s *notifier)
*
****************************************************************************/
static FAR struct nxsig_notifier_s *
nxsig_notifier_find(int16_t key, FAR struct nxsig_notifier_s **pprev)
static FAR struct work_notifier_entry_s *
work_notifier_find(int16_t key, FAR struct work_notifier_entry_s **pprev)
{
FAR struct nxsig_notifier_s *notifier;
FAR struct nxsig_notifier_s *prev;
FAR struct work_notifier_entry_s *notifier;
FAR struct work_notifier_entry_s *prev;
/* Find the entry matching this key in the g_notifier_pending list. */
@ -183,14 +194,14 @@ static FAR struct nxsig_notifier_s *
}
/****************************************************************************
* Name: nxsig_notifier_key
* Name: work_notifier_key
*
* Description:
* Generate a unique key for this notification.
*
****************************************************************************/
static int16_t nxsig_notifier_key(void)
static int16_t work_notifier_key(void)
{
int16_t key;
@ -205,7 +216,7 @@ static int16_t nxsig_notifier_key(void)
key = (int16_t)++g_notifier_key;
}
while (nxsig_notifier_find(key, NULL) != NULL);
while (work_notifier_find(key, NULL) != NULL);
return key;
}
@ -215,22 +226,22 @@ static int16_t nxsig_notifier_key(void)
****************************************************************************/
/****************************************************************************
* Name: nxsig_notifier_initialize
* Name: work_notifier_initialize
*
* Description:
* Set up the notification structure for normal operation.
* Set up the notification data structures for normal operation.
*
****************************************************************************/
void nxsig_notifier_initialize(void)
void work_notifier_initialize(void)
{
int i;
/* Add each notification structure to the free list */
for (i = 0; i < CONFIG_SIG_NOTIFIER_NWAITERS; i++)
for (i = 0; i < CONFIG_WQUEUE_NOTIFIER_NWAITERS; i++)
{
FAR struct nxsig_notifier_s *notifier = &g_notifier_pool[i];
FAR struct work_notifier_entry_s *notifier = &g_notifier_pool[i];
/* Add the pre-allocated notification to the head of the free list */
@ -246,30 +257,17 @@ void nxsig_notifier_initialize(void)
}
/****************************************************************************
* Name: nxsig_notifier_setup
* Name: work_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
*
* NOTE: To avoid race conditions, the caller should set the sigprocmask
* to block signal delivery. The signal will be delivered once the
* signal is removed from the sigprocmask.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then qualifier value may be recovered in the sival_ptr value of
* the struct siginfo instance.
* Set up to provide a notification when event is signaled.
*
* Input Parameters:
* pid - The PID to be notified. If a zero value is provided,
* then the PID of the calling thread will be used.
* signo - The signal number to use with the notification.
* evtype - The event type.
* qualifier - Event qualifier to distinguish different cases of the
* generic event type.
* info - Describes the work notification.
*
* Returned Value:
* > 0 - The key which may be used later in a call to
* nxsig_notifier_teardown().
* work_notifier_teardown().
* == 0 - Not used (reserved for wrapper functions).
* < 0 - An unexpected error occurred and no signal will be sent. The
* returned value is a negated errno value that indicates the
@ -277,18 +275,10 @@ void nxsig_notifier_initialize(void)
*
****************************************************************************/
int nxsig_notifier_setup(int pid, int signo, enum nxsig_evtype_e evtype,
FAR void *qualifier)
int work_notifier_setup(FAR struct work_notifier_s *info)
{
int ret;
/* If the 'pid' is zero, then use the PID of the calling thread */
if (pid <= 0)
{
pid = getpid();
}
/* Get exclusive access to the notifier data structures */
ret = nxsem_wait(&g_notifier_sem);
@ -299,30 +289,39 @@ int nxsig_notifier_setup(int pid, int signo, enum nxsig_evtype_e evtype,
/* Allocate a new notification */
FAR struct nxsig_notifier_s *notifier = nxsig_notifier_alloc();
FAR struct work_notifier_entry_s *notifier = work_notifier_alloc();
if (notifier == NULL)
{
ret = -ENOSPC;
}
else
{
FAR struct work_notifier_alloc_s *alloc;
int16_t key;
/* Duplicate the notification info */
alloc = kmm_malloc(sizeof(struct work_notifier_alloc_s));
if (alloc == NULL)
{
work_notifier_free(notifier);
return -ENOMEM;
}
memcpy(&alloc->info, info, sizeof(struct work_notifier_s));
/* Generate a unique key for this notification */
int16_t key = nxsig_notifier_key();
key = work_notifier_key();
/* Initialize the notification structure */
/* Add the notification to the head of the pending list */
notifier->pid = pid;
notifier->signo = signo;
notifier->evtype = evtype;
notifier->key = key;
notifier->qualifier = qualifier;
notifier->flink = g_notifier_pending;
notifier->alloc = alloc;
notifier->key = key;
/* And add it to the head of the pending list */
notifier->flink = g_notifier_pending;
g_notifier_pending = notifier;
ret = key;
g_notifier_pending = notifier;
ret = key;
}
(void)nxsem_post(&g_notifier_sem);
@ -330,17 +329,17 @@ int nxsig_notifier_setup(int pid, int signo, enum nxsig_evtype_e evtype,
}
/****************************************************************************
* Name: nxsig_notifier_teardown
* Name: work_notifier_teardown
*
* Description:
* Eliminate a notification previously setup by nxsig_notifier_setup().
* Eliminate a notification previously setup by work_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 signal is sent.
*
* Input Parameters:
* key - The key value returned from a previous call to
* nxsig_notifier_setup().
* work_notifier_setup().
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
@ -348,10 +347,10 @@ int nxsig_notifier_setup(int pid, int signo, enum nxsig_evtype_e evtype,
*
****************************************************************************/
int nxsig_notifier_teardown(int key)
int work_notifier_teardown(int key)
{
FAR struct nxsig_notifier_s *notifier;
FAR struct nxsig_notifier_s *prev;
FAR struct work_notifier_entry_s *notifier;
FAR struct work_notifier_entry_s *prev;
int ret;
/* Get exclusive access to the notifier data structures */
@ -366,7 +365,7 @@ int nxsig_notifier_teardown(int key)
* assume that there is only one.
*/
notifier = nxsig_notifier_find(key, &prev);
notifier = work_notifier_find(key, &prev);
if (notifier == NULL)
{
/* There is no notification with this key in the pending list */
@ -386,9 +385,14 @@ int nxsig_notifier_teardown(int key)
prev->flink = notifier->flink;
}
/* And add it to the free list */
/* Free the contained information */
nxsig_notifier_free(notifier);
DEBUGASSERT(notifier->alloc != NULL);
kmm_free(notifier->alloc);
/* And return the notification to the free list */
work_notifier_free(notifier);
ret = OK;
}
@ -397,19 +401,15 @@ int nxsig_notifier_teardown(int key)
}
/****************************************************************************
* Name: nxsig_notifier_signal
* Name: work_notifier_signal
*
* Description:
* An event has just occurred. Signal all threads waiting for that event.
*
* When an IOB becomes available, *all* of the waiters in this thread will
* be signaled. If there are multiple waiters for a resource then only
* the highest priority thread will get the resource. Lower priority
* threads will need to call nxsig_notify once again.
*
* NOTE: If sigwaitinfo() or sigtimedwait() are used to catch the signal
* then then qualifier value may be obtained in the sival_ptr value of
* the struct siginfo instance.
* When an event of interest occurs, *all* of the workers waiting for this
* event will be executed. If there are multiple workers for a resource
* then only the first to execute will get the resource. Others will
* need to call work_notifier_setup() once again.
*
* Input Parameters:
* evtype - The type of the event that just occurred.
@ -421,12 +421,12 @@ int nxsig_notifier_teardown(int key)
*
****************************************************************************/
void nxsig_notifier_signal(enum nxsig_evtype_e evtype,
void work_notifier_signal(enum work_evtype_e evtype,
FAR void *qualifier)
{
FAR struct nxsig_notifier_s *notifier;
FAR struct nxsig_notifier_s *prev;
FAR struct nxsig_notifier_s *next;
FAR struct work_notifier_entry_s *notifier;
FAR struct work_notifier_entry_s *prev;
FAR struct work_notifier_entry_s *next;
int ret;
/* Get exclusive access to the notifier data structure */
@ -449,12 +449,11 @@ void nxsig_notifier_signal(enum nxsig_evtype_e evtype,
/* Find the entry matching this key in the g_notifier_pending list. */
for (prev = NULL, notifier = g_notifier_pending;
notifier != NULL;
notifier != NULL;
notifier = next)
{
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value;
#endif
FAR struct work_notifier_alloc_s *alloc;
FAR struct work_notifier_s *info;
/* Set up for the next time through the loop (in case the entry is
* removed from the list).
@ -466,8 +465,13 @@ void nxsig_notifier_signal(enum nxsig_evtype_e evtype,
* just occurred.
*/
if (notifier->evtype == evtype && notifier->qualifier == qualifier)
alloc = notifier->alloc;
DEBUGASSERT(alloc != NULL);
info = &alloc->info;
if (info->evtype == evtype && info->qualifier == qualifier)
{
/* Yes.. Remove the notification from the pending list */
if (prev == NULL)
@ -479,18 +483,13 @@ void nxsig_notifier_signal(enum nxsig_evtype_e evtype,
prev->flink = next;
}
/* Signal the waiter */
/* Schedule the work */
(void)work_queue(HPWORK, &alloc->work, info->worker, info, 0);
#ifdef CONFIG_CAN_PASS_STRUCTS
value.sival_ptr = notifier->qualifier;
(void)nxsig_queue(notifier->pid, notifier->signo, value);
#else
(void)nxsig_queue(notifier->pid, notifier->signo,
notifier->qualifier);
#endif
/* Free the notification by returning it to the free list */
nxsig_notifier_free(notifier);
work_notifier_free(notifier);
}
else
{
@ -506,4 +505,4 @@ void nxsig_notifier_signal(enum nxsig_evtype_e evtype,
(void)nxsem_post(&g_notifier_sem);
}
#endif /* CONFIG_SIG_NOTIFIER */
#endif /* CONFIG_WQUEUE_NOTIFIER */

View File

@ -54,7 +54,7 @@
* Pre-processor Definitions
****************************************************************************/
/* Kkernel thread names */
/* Kernel thread names */
#define HPWORKNAME "hpwork"
#define LPWORKNAME "lpwork"
@ -62,6 +62,7 @@
/****************************************************************************
* Public Type Definitions
****************************************************************************/
/* This represents one worker */
struct kworker_s
@ -128,6 +129,22 @@ extern struct lp_wqueue_s g_lpwork;
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: work_initialize
*
* Description:
* One time initialization of the work queue data structures.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void work_initialize(void);
/****************************************************************************
* Name: work_hpstart
*
@ -186,5 +203,17 @@ int work_lpstart(void);
void work_process(FAR struct kwork_wqueue_s *wqueue, int wndx);
/****************************************************************************
* Name: work_notifier_initialize
*
* Description:
* Set up the notification data structures for normal operation.
*
****************************************************************************/
#ifdef CONFIG_WQUEUE_NOTIFIER
void work_notifier_initialize(void);
#endif
#endif /* CONFIG_SCHED_WORKQUEUE */
#endif /* __SCHED_WQUEUE_WQUEUE_H */