signals: Adds a very limited, minimal implementation for SIGEV_THREAD

This commit is contained in:
Gregory Nutt 2015-12-30 15:01:14 -06:00
parent 9852932dcc
commit c1fff4706c
7 changed files with 219 additions and 33 deletions

View file

@ -45,7 +45,7 @@
#include <sys/types.h>
#include <signal.h>
#if defined(CONFIG_SIG_EVTHREAD) && defined(__KERNEL__)
#if defined(CONFIG_SIG_EVTHREAD) && defined(CONFIG_BUILD_FLAT)
/****************************************************************************
* Public Function Prototypes
@ -72,5 +72,5 @@
int sig_notification(pid_t pid, FAR struct sigevent *event);
#endif /* CONFIG_SIG_EVTHREAD && __KERNEL__ */
#endif /* CONFIG_SIG_EVTHREAD && CONFIG_BUILD_FLAT */
#endif /* __INCLUDE_NUTTX_SIGNAL_H */

View file

@ -432,6 +432,10 @@ int pthread_sigmask(int how, FAR const sigset_t *set, FAR sigset_t *oset);
}
#endif
/********************************************************************************
* Minimal Type Definitions
********************************************************************************/
#else /* __INCLUDE_PTHREAD_H */
#include <sys/types.h>

View file

@ -210,6 +210,12 @@ union sigval
* available on a queue
*/
#ifdef CONFIG_CAN_PASS_STRUCTS
typedef CODE void (*sigev_notify_function_t)(union sigval value);
#else
typedef CODE void (*sigev_notify_function_t)(FAR void *sival_ptr);
#endif
struct sigevent
{
uint8_t sigev_notify; /* Notification method: SIGEV_SIGNAL, SIGEV_NONE, or SIGEV_THREAD */
@ -217,7 +223,7 @@ struct sigevent
union sigval sigev_value; /* Data passed with notification */
#ifdef CONFIG_SIG_EVTHREAD
CODE void (*sigev_notify_function)(union sigval); /* Notification function */
sigev_notify_function_t sigev_notify_function; /* Notification function */
FAR pthread_attr_t *sigev_notify_attributes; /* Notification attributes (not used) */
#endif
};
@ -264,10 +270,6 @@ struct sigaction
#define sa_handler sa_u._sa_handler
#define sa_sigaction sa_u._sa_sigaction
/********************************************************************************
* Public Data
********************************************************************************/
/********************************************************************************
* Public Function Prototypes
********************************************************************************/
@ -310,6 +312,10 @@ int sigqueue(int pid, int signo, FAR void *sival_ptr);
}
#endif
/********************************************************************************
* Minimal Type Definitions
********************************************************************************/
#else /* __INCLUDE_SIGNAL_H */
#include <stdint.h>

View file

@ -45,16 +45,13 @@
#include <assert.h>
#include <errno.h>
#include <nuttx/signal.h>
#include "libc.h"
#include "aio/aio.h"
#ifdef CONFIG_FS_AIO
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
@ -69,14 +66,6 @@ struct lio_sighand_s
struct sigaction oact; /* Signal handler to restore */
};
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
@ -205,11 +194,11 @@ static void lio_sighandler(int signo, siginfo_t *info, void *ucontext)
if (sighand->sig->sigev_notify == SIGEV_SIGNAL)
{
#ifdef CONFIG_CAN_PASS_STRUCTS
(void)sigqueue(sighand->pid, sighand->sig->sigev_signo,
sighand->sig->sigev_value);
DEBUGASSERT(sigqueue(sighand->pid, sighand->sig->sigev_signo,
sighand->sig->sigev_value));
#else
(void)sigqueue(sighand->pid, sighand->sig->sigev_signo,
sighand->sig->sigev_value.sival_ptr);
DEBUGASSERT(sigqueue(sighand->pid, sighand->sig->sigev_signo,
sighand->sig->sigev_value.sival_ptr));
#endif
}
@ -218,7 +207,7 @@ static void lio_sighandler(int signo, siginfo_t *info, void *ucontext)
else if (ighand->sig->sigev_notify == SIGEV_THREAD)
{
#warning Missing SIGEV_THREAD logic
DEBUGASSERT(sig_notification(sighand->pid, &sighand->sig));
}
#endif
@ -660,7 +649,7 @@ int lio_listio(int mode, FAR struct aiocb *const list[], int nent,
*/
status = lio_waitall(list, nent);
if (status < 0 && ret != OK)
if (status < 0 && ret == OK)
{
/* Something bad happened while waiting and this is the first
* error to be reported.
@ -688,7 +677,7 @@ int lio_listio(int mode, FAR struct aiocb *const list[], int nent,
/* Setup a signal handler to detect when until all I/O completes. */
status = lio_sigsetup(list, nent, sig);
if (status < 0 && ret != OK)
if (status < 0 && ret == OK)
{
/* Something bad happened while setting up the signal and this
* is the first error to be reported.
@ -707,8 +696,7 @@ int lio_listio(int mode, FAR struct aiocb *const list[], int nent,
status = sigqueue(getpid(), sig->sigev_signo,
sig->sigev_value.sival_ptr);
#endif
if (status < 0 && ret != OK)
if (status < 0 && ret == OK)
{
/* Something bad happened while signalling ourself and this is
* the first error to be reported.
@ -725,7 +713,16 @@ int lio_listio(int mode, FAR struct aiocb *const list[], int nent,
else if (sig && sig->sigev_notify == SIGEV_THREAD)
{
#warning Missing SIGEV_THREAD logic
status = sig_notification(sighand->pid, &sighand->sig);
if (status < 0 && ret == OK)
{
/* Something bad happened while performing the notification
* and this is the first error to be reported.
*/
retcode = -status;
ret = ERROR;
}
}
#endif

View file

@ -778,11 +778,14 @@ endmenu # RTOS hooks
config SIG_EVTHREAD
bool "Support SIGEV_THHREAD"
default n
depends on EXPERIMENTAL
depends on BUILD_FLAT && SCHED_WORKQUEUE
---help---
Built in support for the SIGEV_THREAD signal deliver method.
NOTE: Only partially implemented as of this writing.
NOTE: The current implementation uses a work queue to notify the
client. This, however, would only work in the FLAT build. A
different mechanism would need to be development to support this
feature on the PROTECTED or KERNEL build.
menu "Signal Numbers"
depends on !DISABLE_SIGNALS

View file

@ -44,6 +44,10 @@ CSRCS += sig_removependingsignal.c sig_releasependingsignal.c sig_lowest.c
CSRCS += sig_mqnotempty.c sig_cleanup.c sig_dispatch.c sig_deliver.c
CSRCS += sig_pause.c sig_nanosleep.c
ifeq ($(CONFIG_SIG_EVTHREAD),y)
CSRCS += sig_notification.c
endif
# Include signal build support
DEPPATH += --dep-path signal

View file

@ -0,0 +1,172 @@
/****************************************************************************
* sched/signal/sig_notification.c
*
* Copyright (C) 2015 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 <signal.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#ifdef CONFIG_SIG_EVTHREAD
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Use the low-prioriry work queue is it is available */
#if defined(CONFIG_SCHED_LPWORK)
# define NTWORK LPWORK
#elif defined(CONFIG_SCHED_HPWORK)
# define NTWORK HPWORK
#else
# error Work queue is not enabled
#endif
/****************************************************************************
* Private Type Definitions
****************************************************************************/
/* This structure retains all that is necessary to perform the notification */
struct sig_notify_s
{
struct work_s nt_work; /* Work queue structure */
union sigval nt_value; /* Data passed with notification */
sigev_notify_function_t nt_func; /* Notification function */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sig_ntworker
*
* Description:
* Perform the callback from the context of the worker thread.
*
* Input Parameters:
* arg - Work argument.
*
* Returned Value:
* None.
*
****************************************************************************/
static void sig_ntworker(FAR void *arg)
{
FAR struct sig_notify_s *notify = (FAR struct sig_notify_s *)arg;
DEBUGASSERT(notify != NULL);
/* Perform the callback */
#ifdef CONFIG_CAN_PASS_STRUCTS
notify->nt_func(notify->nt_value);
#else
notify->nt_func(notify->nt_value.sival_ptr);
#endif
/* Free the alloated notification parameters */
kmm_free(notify);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sig_notification
*
* Description:
* Notify a client a signal event via a function call. This function is
* an internal OS interface that implements the common logic for signal
* event notification for the case of SIGEV_THREAD.
*
* Input Parameters:
* pid - The task/thread ID a the client thread to be signaled.
* event - The instance of struct sigevent that describes how to signal
* the client.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* on failure.
*
****************************************************************************/
int sig_notification(pid_t pid, FAR struct sigevent *event)
{
FAR struct sig_notify_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));
if (notify == NULL)
{
return -ENOMEM;
}
/* Initialize the notification information */
#ifdef CONFIG_CAN_PASS_STRUCTS
notify->nt_value = event->sigev_value;
#else
notify->nt_value.sival_ptr = event->sigev_value.sival_ptr;
#endif
notify->nt_func = event->sigev_notify_function;
/* Then queue the work */
ret = work_queue(NTWORK, &notify->nt_work, sig_ntworker, notify, 0);
if (ret < 0)
{
kmm_free(notify);
}
return ret;
}
#endif /* CONFIG_SIG_EVTHREAD */