From c1fff4706c640b0959bf2d4b9c3ea98abeb7a015 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 30 Dec 2015 15:01:14 -0600 Subject: [PATCH] signals: Adds a very limited, minimal implementation for SIGEV_THREAD --- include/nuttx/signal.h | 4 +- include/pthread.h | 4 + include/signal.h | 18 ++-- libc/aio/lio_listio.c | 43 ++++---- sched/Kconfig | 7 +- sched/signal/Make.defs | 4 + sched/signal/sig_notification.c | 172 ++++++++++++++++++++++++++++++++ 7 files changed, 219 insertions(+), 33 deletions(-) create mode 100644 sched/signal/sig_notification.c diff --git a/include/nuttx/signal.h b/include/nuttx/signal.h index 56c708ec86..3f4adb5021 100644 --- a/include/nuttx/signal.h +++ b/include/nuttx/signal.h @@ -45,7 +45,7 @@ #include #include -#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 */ diff --git a/include/pthread.h b/include/pthread.h index 5a380bafbc..9cc2b44a41 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -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 diff --git a/include/signal.h b/include/signal.h index 50d6ea9f01..742720cf6b 100644 --- a/include/signal.h +++ b/include/signal.h @@ -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,8 +223,8 @@ struct sigevent union sigval sigev_value; /* Data passed with notification */ #ifdef CONFIG_SIG_EVTHREAD - CODE void (*sigev_notify_function)(union sigval); /* Notification function */ - FAR pthread_attr_t *sigev_notify_attributes; /* Notification attributes (not used) */ + 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 diff --git a/libc/aio/lio_listio.c b/libc/aio/lio_listio.c index 38efad0019..b123a4e735 100644 --- a/libc/aio/lio_listio.c +++ b/libc/aio/lio_listio.c @@ -45,16 +45,13 @@ #include #include +#include + #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 diff --git a/sched/Kconfig b/sched/Kconfig index 301558ec8d..d1e72a30e8 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -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 diff --git a/sched/signal/Make.defs b/sched/signal/Make.defs index 8521b644aa..9d6ddda3a6 100644 --- a/sched/signal/Make.defs +++ b/sched/signal/Make.defs @@ -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 diff --git a/sched/signal/sig_notification.c b/sched/signal/sig_notification.c new file mode 100644 index 0000000000..f9a0710fbe --- /dev/null +++ b/sched/signal/sig_notification.c @@ -0,0 +1,172 @@ +/**************************************************************************** + * sched/signal/sig_notification.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include +#include +#include + +#include +#include + +#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, ¬ify->nt_work, sig_ntworker, notify, 0); + if (ret < 0) + { + kmm_free(notify); + } + + return ret; +} + +#endif /* CONFIG_SIG_EVTHREAD */