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:
parent
0eb1beee63
commit
fc127fd297
19 changed files with 820 additions and 466 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
19
mm/iob/iob.h
19
mm/iob/iob.h
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
151
mm/iob/iob_notifier.c
Normal 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 */
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, ¬ify->nt_work, nxsig_notify_worker,
|
||||
ret = work_queue(NTWORK, ¬ify->nt_work, nxsig_evthread_worker,
|
||||
notify, 0);
|
||||
if (ret < 0)
|
||||
{
|
|
@ -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
492
sched/signal/sig_notifier.c
Normal 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 */
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue