1
0
Fork 0
forked from nuttx/nuttx-update

sched/signal: Add a generic signal notification facility. Modify the custom IOB available notifier so that it is now just a wrapper around this generic signal notification. This generic signal notification faility will, eventually, be used to support network polling.

Squashed commit of the following:

    mm/iob:  The IOB available notifier is now just a wrapper around the common signal notifier.

    sched/signal:  Add a generic signal notification facility.

    sched/signal/sig_evthread.c:  More trivial naming changes.

    sched/signal:  Rename nxsig_notification() to nxsig_evthread() to make forthcoming naming additions more consistent.
This commit is contained in:
Gregory Nutt 2018-09-09 08:32:37 -06:00
parent 0eb1beee63
commit fc127fd297
19 changed files with 820 additions and 466 deletions

View file

@ -111,10 +111,10 @@ int aio_signal(pid_t pid, FAR struct aiocb *aiocbp)
else if (aiocbp->aio_sigevent.sigev_notify == SIGEV_THREAD)
{
ret = nxsig_notification(pid, &aiocbp->aio_sigevent);
ret = nxsig_evthread(pid, &aiocbp->aio_sigevent);
if (ret < 0)
{
ferr("ERROR: nxsig_notification failed: %d\n", ret);
ferr("ERROR: nxsig_evthread failed: %d\n", ret);
}
}
#endif

View file

@ -205,7 +205,7 @@ int iob_navail(void);
FAR struct iob_s *iob_free(FAR struct iob_s *iob);
/****************************************************************************
* Name: iob_notify_setup
* Name: iob_notifier_setup
*
* Description:
* Set up to notify the specified PID with the provided signal number.
@ -220,14 +220,11 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob);
* signo - The signal number to use with the notification.
*
* Returned Value:
* > 0 - There are already free IOBs and this this number of free IOBs
* (CAUTION: This value is volatile). No signal notification
* will be provided.
* == 0 - There are no free IOBs. A signal will be sent to 'pid' when
* at least one IOB is available. That IOB is *not* reserved for
* the caller. Hence, due to race conditions, it could be taken
* by some other task. In that event, the caller should call
* sig_notify again.
* > 0 - The signal notification is in place. The returned value is a
* key that may be used later in a call to
* iob_notifier_teardown().
* == 0 - There are already free IOBs. No signal notification will be
* provided.
* < 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.
@ -235,21 +232,21 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob);
****************************************************************************/
#ifdef CONFIG_IOB_NOTIFIER
int iob_notify_setup(int pid, int signo);
int iob_notifier_setup(int pid, int signo);
#endif
/****************************************************************************
* Name: iob_notify_teardown
* Name: iob_notifier_teardown
*
* Description:
* Eliminate an IOB notification previously setup by iob_notify_setup().
* Eliminate an IOB notification previously setup by iob_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:
* pid - The PID whose notification will be torn down. If a zero value
* is provided, then the PID of the calling thread will be used.
* key - The key value returned from a previous call to
* iob_notifier_setup().
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
@ -258,7 +255,7 @@ int iob_notify_setup(int pid, int signo);
****************************************************************************/
#ifdef CONFIG_IOB_NOTIFIER
int iob_notify_teardown(int pid, int signo);
int iob_notifier_teardown(int key);
#endif
/****************************************************************************

View file

@ -46,6 +46,22 @@
#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_UDP_READAHEAD, /* Signal that TCP read-ahead data is available */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@ -431,7 +447,7 @@ unsigned int nxsig_sleep(unsigned int seconds);
int nxsig_usleep(useconds_t usec);
/****************************************************************************
* Name: nxsig_notification
* Name: nxsig_evthread
*
* Description:
* Notify a client a signal event via a function call. This function is
@ -451,7 +467,89 @@ int nxsig_usleep(useconds_t usec);
****************************************************************************/
#if defined(CONFIG_SIG_EVTHREAD) && defined(CONFIG_BUILD_FLAT)
int nxsig_notification(pid_t pid, FAR struct sigevent *event);
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.
*
* 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.
*
* 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

@ -207,7 +207,7 @@ static void lio_sighandler(int signo, siginfo_t *info, void *ucontext)
else if (ighand->sig->sigev_notify == SIGEV_THREAD)
{
DEBUGASSERT(nxsig_notification(sighand->pid, &sighand->sig));
DEBUGASSERT(nxsig_evthread(sighand->pid, &sighand->sig));
}
#endif
@ -713,7 +713,7 @@ int lio_listio(int mode, FAR struct aiocb *const list[], int nent,
else if (sig && sig->sigev_notify == SIGEV_THREAD)
{
status = nxsig_notification(sighand->pid, &sighand->sig);
status = nxsig_evthread(sighand->pid, &sighand->sig);
if (status < 0 && ret == OK)
{
/* Something bad happened while performing the notification

View file

@ -62,23 +62,13 @@ config IOB_THROTTLE
config IOB_NOTIFIER
bool "Support IOB notifications"
default n
select SIG_NOTIFIER
---help---
Enable building of IOB notifier logic that will send a signla 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.
config IOB_NWAITERS
int "Number of IOB waiters"
default 4
range 1 32767
depends on IOB_NOTIFIER
---help---
If CONFIG_IOB_NOTIFIER is selected, then a static array 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 IOB_DEBUG
bool "Force I/O buffer debug"
default n

View file

@ -45,7 +45,7 @@ CSRCS += iob_trimhead.c iob_trimhead_queue.c iob_trimtail.c
CSRCS += iob_navail.c
ifeq ($(CONFIG_IOB_NOTIFIER),y)
CSRCS += iob_notify.c
CSRCS += iob_notifier.c
endif
ifeq ($(CONFIG_DEBUG_FEATURES),y)

View file

@ -155,19 +155,7 @@ FAR struct iob_qentry_s *iob_tryalloc_qentry(void);
FAR struct iob_qentry_s *iob_free_qentry(FAR struct iob_qentry_s *iobq);
/****************************************************************************
* Name: iob_notify_initialize
*
* Description:
* Set up the notification structure for normal operation.
*
****************************************************************************/
#ifdef CONFIG_IOB_NOTIFIER
void iob_notify_initialize(void);
#endif
/****************************************************************************
* Name: iob_notify_signal
* Name: iob_notifier_signal
*
* Description:
* An IOB has become available. Signal all threads waiting for an IOB
@ -176,7 +164,7 @@ void iob_notify_initialize(void);
* 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_notify once again.
* call iob_notifier_setup() once again.
*
* Input Parameters:
* None.
@ -187,9 +175,8 @@ void iob_notify_initialize(void);
****************************************************************************/
#ifdef CONFIG_IOB_NOTIFIER
void iob_notify_signal(void);
void iob_notifier_signal(void);
#endif
#endif /* CONFIG_MM_IOB */
#endif /* __MM_IOB_IOB_H */

View file

@ -148,7 +148,7 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
* when an IOB becomes available.
*/
iob_notify_signal();
iob_notifier_signal();
}
#endif

View file

@ -155,12 +155,6 @@ void iob_initialize(void)
nxsem_init(&g_qentry_sem, 0, CONFIG_IOB_NCHAINS);
#endif
#ifdef CONFIG_IOB_NOTIFIER
/* Initialize the IOB notification data structures */
iob_notify_initialize();
#endif
initialized = true;
}
}

151
mm/iob/iob_notifier.c Normal file
View file

@ -0,0 +1,151 @@
/****************************************************************************
* mm/iob/iob_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 <nuttx/signal.h>
#include <nuttx/mm/iob.h>
#include "iob.h"
#ifdef CONFIG_IOB_NOTIFIER
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* 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.
*
* 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.
*
* Returned Value:
* > 0 - The signal notification is in place. The returned value is a
* key that may be used later in a call to
* iob_notifier_teardown().
* == 0 - There are already free IOBs. No signal notification will be
* provided.
* < 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.
*
****************************************************************************/
int iob_notifier_setup(int pid, int signo)
{
/* If there are already free IOBs, then return zero without setting up the
* notification.
*/
if (iob_navail() > 0)
{
return 0;
}
/* Otherwise, this is just a simple wrapper around nxsig_notifer_setup(). */
return nxsig_notifier_setup(pid, signo, NXSIG_IOB_AVAIL, NULL);
}
/****************************************************************************
* Name: iob_notifier_teardown
*
* Description:
* Eliminate an IOB notification previously setup by iob_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
* iob_notifier_setup().
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int iob_notifier_teardown(int key)
{
/* This is just a simple wrapper around nxsig_notifier_teardown(). */
return nxsig_notifier_teardown(key);
}
/****************************************************************************
* 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 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.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void iob_notifier_signal(void)
{
/* This is just a simple wrapper around nxsig_notifier_signal(). */
return nxsig_notifier_signal(NXSIG_IOB_AVAIL, NULL);
}
#endif /* CONFIG_IOB_NOTIFIER */

View file

@ -1,394 +0,0 @@
/****************************************************************************
* mm/iob/iob_notify.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 <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <sched.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/signal.h>
#include <nuttx/semaphore.h>
#include <nuttx/mm/iob.h>
#include "iob.h"
#ifdef CONFIG_IOB_NOTIFIER
/****************************************************************************
* Private Types
****************************************************************************/
/* This is the saved information for one IOB notification */
struct iob_notify_s
{
FAR struct iob_notify_s *flink; /* Supports a singly linked list */
uint8_t signo; /* The signal number for notification */
pid_t pid; /* The PID to be notified */
};
/****************************************************************************
* Private Data
****************************************************************************/
/* This is a statically allocated pool of notification structures */
static struct iob_notify_s g_iobnotify_pool[CONFIG_IOB_NWAITERS];
/* This is a list of free notification structures */
static FAR struct iob_notify_s *g_iobnotify_free;
/* This is a singly linked list pending notifications. When an IOB becomes
* available, *all* of the waiters in this list will be signaled and the
* entry will be freed. If there are multiple waiters then only the highest
* priority thread will get the IOB. Lower priority threads will need to
* call iob_notify_setup() once again.
*/
static FAR struct iob_notify_s *g_iobnotify_pending;
/* This semaphore is used as mutex to enforce mutually exclusive access to
* the IOB notification structures.
*/
static sem_t g_iobnotify_sem;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: iob_notify_alloc
*
* Description:
* Allocate a notification structure by removing it from the free list.
*
****************************************************************************/
static FAR struct iob_notify_s *iob_notify_alloc(void)
{
FAR struct iob_notify_s *notify;
notify = g_iobnotify_free;
if (notify != NULL)
{
g_iobnotify_free = notify->flink;
notify->flink = NULL;
}
return notify;
}
/****************************************************************************
* Name: iob_notify_free
*
* Description:
* Free a notification structure by returning it to the head of the free
* list.
*
****************************************************************************/
static void iob_notify_free(FAR struct iob_notify_s *notify)
{
notify->flink = g_iobnotify_free;
g_iobnotify_free = notify;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: iob_notify_initialize
*
* Description:
* Set up the notification structure for normal operation.
*
****************************************************************************/
void iob_notify_initialize(void)
{
int i;
/* Add each notification structure to the free list */
for (i = 0; i < CONFIG_IOB_NWAITERS; i++)
{
FAR struct iob_notify_s *notify = &g_iobnotify_pool[i];
/* Add the pre-allocated notification to the head of the free list */
notify->flink = g_iobnotify_free;
g_iobnotify_free = notify;
}
/* Initialize the semaphore that enforces mutually exclusive access to the
* notification data structures.
*/
nxsem_init(&g_iobnotify_sem, 0, 1);
}
/****************************************************************************
* Name: iob_notify_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.
*
* 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.
*
* Returned Value:
* > 0 - There are already free IOBs and this this number of free IOBs
* (CAUTION: This value is volatile). No signal notification
* will be provided.
* == 0 - There are no free IOBs. A signal will be sent to 'pid' when
* at least one IOB is available. That IOB is *not* reserved for
* the caller. Hence, due to race conditions, it could be taken
* by some other task. In that event, the caller should call
* sig_notify again.
* < 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.
*
****************************************************************************/
int iob_notify_setup(int pid, int signo)
{
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_iobnotify_sem);
if (ret < 0)
{
return ret;
}
/* If there are already free IOBs, then just return the number of free
* IOBs.
*/
ret = iob_navail();
if (ret <= 0)
{
/* Allocate a new notification */
FAR struct iob_notify_s *notify = iob_notify_alloc();
if (notify == NULL)
{
ret = -ENOSPC;
}
else
{
/* Initialize the notification structure */
notify->pid = pid;
notify->signo = signo;
/* And add it to the head of the pending list */
notify->flink = g_iobnotify_pending;
g_iobnotify_pending = notify;
ret = OK;
}
}
(void)nxsem_post(&g_iobnotify_sem);
return ret;
}
/****************************************************************************
* Name: iob_notify_teardown
*
* Description:
* Eliminate an IOB notification previously setup by iob_notify_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:
* pid - The PID whose notification will be torn down. If a zero value
* is provided, then the PID of the calling thread will be used.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int iob_notify_teardown(int pid, int signo)
{
FAR struct iob_notify_s *notify;
FAR struct iob_notify_s *prev;
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_iobnotify_sem);
if (ret < 0)
{
return ret;
}
/* Find the entry matching this PID in the g_iobnotify_pending list. We
* assume that there is only one.
*/
ret = -ENOENT;
for (prev = NULL, notify = g_iobnotify_pending;
notify != NULL;
prev = notify, notify = notify->flink)
{
/* Is this the one we were looking for? */
if (notify->pid == pid)
{
/* Yes, remove it from the pending list */
if (prev == NULL)
{
g_iobnotify_pending = notify->flink;
}
else
{
prev->flink = notify->flink;
}
/* And add it to the free list */
iob_notify_free(notify);
ret = OK;
break;
}
}
(void)nxsem_post(&g_iobnotify_sem);
return ret;
}
/****************************************************************************
* Name: iob_notify_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 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_notify once again.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void iob_notify_signal(void)
{
FAR struct iob_notify_s *notify;
int ret;
/* Get exclusive access to the notifier data structure */
ret = nxsem_wait(&g_iobnotify_sem);
while (ret < 0)
{
DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
}
/* Don't let any newly started threads block this thread until all of
* the notifications and been sent.
*/
sched_lock();
/* Process the notification at the head of the pending list until the
* pending list is empty */
while ((notify = g_iobnotify_pending) != NULL)
{
/* Remove the notification from the pending list */
g_iobnotify_pending = notify->flink;
/* Signal the waiter */
(void)nxsig_kill(notify->pid, notify->signo);
/* Free the notification by returning it to the free list */
iob_notify_free(notify);
}
sched_unlock();
(void)nxsem_post(&g_iobnotify_sem);
}
#endif /* CONFIG_IOB_NOTIFIER */

View file

@ -1174,6 +1174,26 @@ 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 4
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

View file

@ -430,7 +430,7 @@ int nxmq_do_send(mqd_t mqdes, FAR struct mqueue_msg_s *mqmsg,
else if (event.sigev_notify == SIGEV_THREAD)
{
DEBUGVERIFY(nxsig_notification(pid, &event));
DEBUGVERIFY(nxsig_evthread(pid, &event));
}
#endif

View file

@ -49,7 +49,11 @@ CSRCS += sig_default.c
endif
ifeq ($(CONFIG_SIG_EVTHREAD),y)
CSRCS += sig_notification.c
CSRCS += sig_evthread.c
endif
ifeq ($(CONFIG_SIG_NOTIFIER),y)
CSRCS += sig_notifier.c
endif
# Include signal build support

View file

@ -1,7 +1,7 @@
/****************************************************************************
* sched/signal/sig_notification.c
* sched/signal/sig_evthread.c
*
* Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2015, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -52,6 +52,7 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Use the low-prioriry work queue is it is available */
#if defined(CONFIG_SCHED_LPWORK)
@ -68,7 +69,7 @@
/* This structure retains all that is necessary to perform the notification */
struct sig_notify_s
struct sig_evthread_s
{
struct work_s nt_work; /* Work queue structure */
union sigval nt_value; /* Data passed with notification */
@ -80,7 +81,7 @@ struct sig_notify_s
****************************************************************************/
/****************************************************************************
* Name: nxsig_notify_worker
* Name: nxsig_evthread_worker
*
* Description:
* Perform the callback from the context of the worker thread.
@ -93,9 +94,9 @@ struct sig_notify_s
*
****************************************************************************/
static void nxsig_notify_worker(FAR void *arg)
static void nxsig_evthread_worker(FAR void *arg)
{
FAR struct sig_notify_s *notify = (FAR struct sig_notify_s *)arg;
FAR struct sig_evthread_s *notify = (FAR struct sig_evthread_s *)arg;
DEBUGASSERT(notify != NULL);
@ -117,7 +118,7 @@ static void nxsig_notify_worker(FAR void *arg)
****************************************************************************/
/****************************************************************************
* Name: nxsig_notification
* Name: nxsig_evthread
*
* Description:
* Notify a client a signal event via a function call. This function is
@ -136,15 +137,15 @@ static void nxsig_notify_worker(FAR void *arg)
*
****************************************************************************/
int nxsig_notification(pid_t pid, FAR struct sigevent *event)
int nxsig_evthread(pid_t pid, FAR struct sigevent *event)
{
FAR struct sig_notify_s *notify;
FAR struct sig_evthread_s *notify;
DEBUGASSERT(event != NULL && event->sigev_notify_function != NULL);
int ret;
/* Allocate a structure to hold the notification information */
notify = kmm_zalloc(sizeof(struct sig_notify_s));
notify = kmm_zalloc(sizeof(struct sig_evthread_s));
if (notify == NULL)
{
return -ENOMEM;
@ -161,7 +162,7 @@ int nxsig_notification(pid_t pid, FAR struct sigevent *event)
/* Then queue the work */
ret = work_queue(NTWORK, &notify->nt_work, nxsig_notify_worker,
ret = work_queue(NTWORK, &notify->nt_work, nxsig_evthread_worker,
notify, 0);
if (ret < 0)
{

View file

@ -1,7 +1,8 @@
/****************************************************************************
* sched/signal/sig_initialize.c
*
* Copyright (C) 2007, 2009, 2011, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2011, 2017-2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -233,6 +234,12 @@ 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
}
/****************************************************************************

492
sched/signal/sig_notifier.c Normal file
View file

@ -0,0 +1,492 @@
/****************************************************************************
* sched/signal/sig_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 <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <sched.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/signal.h>
#include <nuttx/semaphore.h>
#include "signal/signal.h"
#ifdef CONFIG_SIG_NOTIFIER
/****************************************************************************
* Private Types
****************************************************************************/
/* This is the saved information for one notification */
struct nxsig_notifier_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 */
};
/****************************************************************************
* Private Data
****************************************************************************/
/* This is a statically allocated pool of notification structures */
static struct nxsig_notifier_s g_notifier_pool[CONFIG_SIG_NOTIFIER_NWAITERS];
/* This is a list of free notification structures */
static FAR struct nxsig_notifier_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()
* once again.
*/
static FAR struct nxsig_notifier_s *g_notifier_pending;
/* This semaphore is used as mutex to enforce mutually exclusive access to
* the notification data structures.
*/
static sem_t g_notifier_sem;
/* Used for lookup key generation */
static uint16_t g_notifier_key;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nxsig_notifier_alloc
*
* Description:
* Allocate a notification structure by removing it from the free list.
*
****************************************************************************/
static FAR struct nxsig_notifier_s *nxsig_notifier_alloc(void)
{
FAR struct nxsig_notifier_s *notifier;
notifier = g_notifier_free;
if (notifier != NULL)
{
g_notifier_free = notifier->flink;
notifier->flink = NULL;
}
return notifier;
}
/****************************************************************************
* Name: nxsig_notifier_free
*
* Description:
* Free a notification structure by returning it to the head of the free
* list.
*
****************************************************************************/
static void nxsig_notifier_free(FAR struct nxsig_notifier_s *notifier)
{
notifier->flink = g_notifier_free;
g_notifier_free = notifier;
}
/****************************************************************************
* Name: nxsig_notifier_find
*
* Description:
* Given a unique key for notification, find the corresponding notification
* structure in the pending notification list.
*
****************************************************************************/
static FAR struct nxsig_notifier_s *
nxsig_notifier_find(int16_t key, FAR struct nxsig_notifier_s **pprev)
{
FAR struct nxsig_notifier_s *notifier;
FAR struct nxsig_notifier_s *prev;
/* Find the entry matching this key in the g_notifier_pending list. */
for (prev = NULL, notifier = g_notifier_pending;
notifier != NULL;
prev = notifier, notifier = notifier->flink)
{
/* Is this the one we were looking for? */
if (notifier->key == key)
{
/* Return the previous entry if so requested */
if (pprev != NULL)
{
*pprev = prev;
}
return notifier;
}
}
return NULL;
}
/****************************************************************************
* Name: nxsig_notifier_key
*
* Description:
* Generate a unique key for this notification.
*
****************************************************************************/
static int16_t nxsig_notifier_key(void)
{
int16_t key;
/* Loop until a unique key is generated */
do
{
if (g_notifier_key >= INT16_MAX)
{
g_notifier_key = 0;
}
key = (int16_t)++g_notifier_key;
}
while (nxsig_notifier_find(key, NULL) != NULL);
return key;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nxsig_notifier_initialize
*
* Description:
* Set up the notification structure for normal operation.
*
****************************************************************************/
void nxsig_notifier_initialize(void)
{
int i;
/* Add each notification structure to the free list */
for (i = 0; i < CONFIG_SIG_NOTIFIER_NWAITERS; i++)
{
FAR struct nxsig_notifier_s *notifier = &g_notifier_pool[i];
/* Add the pre-allocated notification to the head of the free list */
notifier->flink = g_notifier_free;
g_notifier_free = notifier;
}
/* Initialize the semaphore that enforces mutually exclusive access to the
* notification data structures.
*/
nxsem_init(&g_notifier_sem, 0, 1);
}
/****************************************************************************
* 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.
*
* 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.
*
****************************************************************************/
int nxsig_notifier_setup(int pid, int signo, enum nxsig_evtype_e evtype,
FAR void *qualifier)
{
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);
if (ret < 0)
{
return ret;
}
/* Allocate a new notification */
FAR struct nxsig_notifier_s *notifier = nxsig_notifier_alloc();
if (notifier == NULL)
{
ret = -ENOSPC;
}
else
{
/* Generate a unique key for this notification */
int16_t key = nxsig_notifier_key();
/* Initialize the notification structure */
notifier->pid = pid;
notifier->signo = signo;
notifier->evtype = evtype;
notifier->key = key;
notifier->qualifier = qualifier;
/* And add it to the head of the pending list */
notifier->flink = g_notifier_pending;
g_notifier_pending = notifier;
ret = key;
}
(void)nxsem_post(&g_notifier_sem);
return ret;
}
/****************************************************************************
* 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.
*
****************************************************************************/
int nxsig_notifier_teardown(int key)
{
FAR struct nxsig_notifier_s *notifier;
FAR struct nxsig_notifier_s *prev;
int ret;
/* Get exclusive access to the notifier data structures */
ret = nxsem_wait(&g_notifier_sem);
if (ret < 0)
{
return ret;
}
/* Find the entry matching this PID in the g_notifier_pending list. We
* assume that there is only one.
*/
notifier = nxsig_notifier_find(key, &prev);
if (notifier == NULL)
{
/* There is no notification with this key in the pending list */
ret = -ENOENT;
}
else
{
/* Found it! Remove the notification from the pending list */
if (prev == NULL)
{
g_notifier_pending = notifier->flink;
}
else
{
prev->flink = notifier->flink;
}
/* And add it to the free list */
nxsig_notifier_free(notifier);
ret = OK;
}
(void)nxsem_post(&g_notifier_sem);
return ret;
}
/****************************************************************************
* 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.
*
* 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.
*
****************************************************************************/
void nxsig_notifier_signal(enum nxsig_evtype_e evtype,
FAR void *qualifier)
{
FAR struct nxsig_notifier_s *notifier;
FAR struct nxsig_notifier_s *prev;
FAR struct nxsig_notifier_s *next;
int ret;
/* Get exclusive access to the notifier data structure */
ret = nxsem_wait(&g_notifier_sem);
while (ret < 0)
{
DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
}
/* Don't let any newly started threads block this thread until all of
* the notifications and been sent.
*/
sched_lock();
/* Process the notification at the head of the pending list until the
* pending list is empty */
/* Find the entry matching this key in the g_notifier_pending list. */
for (prev = NULL, notifier = g_notifier_pending;
notifier != NULL;
notifier = next)
{
/* Set up for the next time through the loop (in case the entry is
* removed from the list).
*/
next = notifier->flink;
/* Check if this is the a notification request for the event that
* just occurred.
*/
if (notifier->evtype == evtype && notifier->qualifier == qualifier)
{
/* Yes.. Remove the notification from the pending list */
if (prev == NULL)
{
g_notifier_pending = next;
}
else
{
prev->flink = next;
}
/* Signal the waiter */
(void)nxsig_kill(notifier->pid, notifier->signo);
/* Free the notification by returning it to the free list */
nxsig_notifier_free(notifier);
}
else
{
/* The entry was not removed, the current entry will be the
* next previous entry.
*/
prev = notifier;
}
}
sched_unlock();
(void)nxsem_post(&g_notifier_sem);
}
#endif /* CONFIG_SIG_NOTIFIER */

View file

@ -68,13 +68,14 @@
* Public Type Definitions
****************************************************************************/
/* This enumeration identifies the type of signal data allocation */
enum sigalloc_e
{
SIG_ALLOC_FIXED = 0, /* pre-allocated; never freed */
SIG_ALLOC_DYN, /* dynamically allocated; free when unused */
SIG_ALLOC_IRQ /* Preallocated, reserved for interrupt handling */
};
typedef enum sigalloc_e sigalloc_t;
/* The following defines the sigaction queue entry */
@ -166,6 +167,12 @@ 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

@ -118,7 +118,7 @@ static inline void timer_signotify(FAR struct posix_timer_s *timer)
else if (timer->pt_event.sigev_notify == SIGEV_THREAD)
{
DEBUGVERIFY(nxsig_notification(timer->pt_owner, &timer->pt_event));
DEBUGVERIFY(nxsig_evthread(timer->pt_owner, &timer->pt_event));
}
#endif
}