From 9835eeb181ebc9b2c9119803b3263191ab08c165 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 30 Dec 2015 13:20:31 -0600 Subject: [PATCH] signals: Basic framework to support SIGEV_THREAD --- TODO | 7 +-- arch | 2 +- configs | 2 +- fs/aio/aio_signal.c | 34 ++++++------- include/nuttx/mqueue.h | 5 +- include/pthread.h | 93 ++++++++++++++++++++++++++++++++++- include/signal.h | 38 ++++++++++++-- libc/aio/lio_listio.c | 18 +++++++ sched/Kconfig | 9 ++++ sched/mqueue/mq_desclose.c | 4 +- sched/mqueue/mq_notify.c | 19 +++---- sched/mqueue/mq_sndinternal.c | 44 +++++++++++------ sched/timer/timer.h | 5 +- sched/timer/timer_create.c | 10 +--- sched/timer/timer_settime.c | 46 +++++++++++------ 15 files changed, 252 insertions(+), 84 deletions(-) diff --git a/TODO b/TODO index 3e11ed34b2..43e5bef9e7 100644 --- a/TODO +++ b/TODO @@ -340,9 +340,10 @@ o Signals (sched/signal, arch/) embedded system. Title: SIGEV_THREAD - Description: sig_notify() logic does not support SIGEV_THREAD; structure - struct sigevent does not provide required members sigev_notify_function - or sigev_notify_attributes. + Description: Implementation of support for support for SIGEV_THREAD is incomplete; + The internal OS functin sig_notification has not been implemented (and + will be tricky!). There are also some unimplemented function call logic + in libc/aio Status: Low, there are alternative designs. However, these features are required by the POSIX standard. Priority: Low for now diff --git a/arch b/arch index 4e962ff8a0..08f9810f59 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 4e962ff8a0a2f15247232d7e9aef89032c9b2898 +Subproject commit 08f9810f5922c627fd378ea3727faa0ba4eb0d74 diff --git a/configs b/configs index bf83eb388a..d4540c0f83 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit bf83eb388aea59fb76651ba22c86f22a0da5d6dc +Subproject commit d4540c0f83378a6680ffd792ff1e4a8ca0ddd8b8 diff --git a/fs/aio/aio_signal.c b/fs/aio/aio_signal.c index 9545a86227..57e37dfe71 100644 --- a/fs/aio/aio_signal.c +++ b/fs/aio/aio_signal.c @@ -51,29 +51,10 @@ #ifdef CONFIG_FS_AIO -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Name: aio_signal * @@ -126,6 +107,19 @@ int aio_signal(pid_t pid, FAR struct aiocb *aiocbp) } } +#ifdef CONFIG_SIG_EVTHREAD + /* Notify the client via a function call */ + + else if (aiocbp->aio_sigevent.sigev_notify == SIGEV_THREAD) + { + ret = sig_notification(pid, &aiocbp->aio_sigevent); + if (ret < 0) + { + fdbg("ERROR: sig_notification failed: %d\n", ret); + } + } +#endif + /* Send the poll signal in any event in case the caller is waiting * on sig_suspend(); */ diff --git a/include/nuttx/mqueue.h b/include/nuttx/mqueue.h index 68f7b1b2bf..53fa3af9f8 100644 --- a/include/nuttx/mqueue.h +++ b/include/nuttx/mqueue.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/mqueue.h * - * Copyright (C) 2007, 2009, 2011, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2011, 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -80,8 +80,7 @@ struct mqueue_inode_s #ifndef CONFIG_DISABLE_SIGNALS FAR struct mq_des *ntmqdes; /* Notification: Owning mqdes (NULL if none) */ pid_t ntpid; /* Notification: Receiving Task's PID */ - int ntsigno; /* Notification: Signal number */ - union sigval ntvalue; /* Notification: Signal value */ + struct sigevent ntevent; /* Notification description */ #endif }; diff --git a/include/pthread.h b/include/pthread.h index 4de07d62a2..5a380bafbc 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -158,8 +158,11 @@ extern "C" /* pthread-specific types */ -typedef int pthread_key_t; -typedef FAR void *pthread_addr_t; +typedef int pthread_key_t; +#define __PTHREAD_KEY_T_DEFINED 1 + +typedef FAR void *pthread_addr_t; +#define __PTHREAD_ADDR_T_DEFINED 1 typedef pthread_addr_t (*pthread_startroutine_t)(pthread_addr_t); typedef pthread_startroutine_t pthread_func_t; @@ -182,17 +185,24 @@ struct pthread_attr_s struct timespec budget; /* Initial budget */ #endif }; + typedef struct pthread_attr_s pthread_attr_t; +#define __PTHREAD_ATTR_T_DEFINED 1 typedef pid_t pthread_t; +#define __PTHREAD_T_DEFINED 1 typedef int pthread_condattr_t; +#define __PTHREAD_CONDATTR_T_DEFINED 1 struct pthread_cond_s { sem_t sem; }; + typedef struct pthread_cond_s pthread_cond_t; +#define __PTHREAD_COND_T_DEFINED 1 + #define PTHREAD_COND_INITIALIZER {SEM_INITIALIZER(0)} struct pthread_mutexattr_s @@ -202,7 +212,9 @@ struct pthread_mutexattr_s uint8_t type; /* Type of the mutex. See PTHREAD_MUTEX_* definitions */ #endif }; + typedef struct pthread_mutexattr_s pthread_mutexattr_t; +#define __PTHREAD_MUTEXATTR_T_DEFINED 1 struct pthread_mutex_s { @@ -213,7 +225,9 @@ struct pthread_mutex_s int nlocks; /* The number of recursive locks held */ #endif }; + typedef struct pthread_mutex_s pthread_mutex_t; +#define __PTHREAD_MUTEX_T_DEFINED 1 #ifdef CONFIG_MUTEX_TYPES # define PTHREAD_MUTEX_INITIALIZER {-1, SEM_INITIALIZER(1), PTHREAD_MUTEX_DEFAULT, 0} @@ -225,16 +239,21 @@ struct pthread_barrierattr_s { int pshared; }; + typedef struct pthread_barrierattr_s pthread_barrierattr_t; +#define __PTHREAD_BARRIERATTR_T_DEFINED 1 struct pthread_barrier_s { sem_t sem; unsigned int count; }; + typedef struct pthread_barrier_s pthread_barrier_t; +#define __PTHREAD_BARRIER_T_DEFINED 1 typedef bool pthread_once_t; +#define __PTHREAD_ONCE_T_DEFINED 1 /* Forware references */ @@ -413,4 +432,74 @@ int pthread_sigmask(int how, FAR const sigset_t *set, FAR sigset_t *oset); } #endif +#else /* __INCLUDE_PTHREAD_H */ + +#include +#include + +/* Avoid a circular dependencies by assuring that simple type definitions + * are avaiable in any inclusion ordering. + */ + +#ifndef __PTHREAD_KEY_T_DEFINED +typedef int pthread_key_t; +# define __PTHREAD_KEY_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_ADDR_T_DEFINED +typedef FAR void *pthread_addr_t; +# define __PTHREAD_ADDR_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_ATTR_T_DEFINED +struct pthread_attr_s; +typedef struct pthread_attr_s pthread_attr_t; +# define __PTHREAD_ATTR_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_T_DEFINED +typedef pid_t pthread_t; +# define __PTHREAD_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_CONDATTR_T_DEFINED +typedef int pthread_condattr_t; +# define __PTHREAD_CONDATTR_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_COND_T_DEFINED +struct pthread_cond_s; +typedef struct pthread_cond_s pthread_cond_t; +# define __PTHREAD_COND_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_MUTEXATTR_T_DEFINED +struct pthread_mutexattr_s; +typedef struct pthread_mutexattr_s pthread_mutexattr_t; +# define __PTHREAD_MUTEXATTR_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_MUTEX_T_DEFINED +struct pthread_mutex_s; +typedef struct pthread_mutex_s pthread_mutex_t; +# define __PTHREAD_MUTEX_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_BARRIERATTR_T_DEFINED +struct pthread_barrierattr_s; +typedef struct pthread_barrierattr_s pthread_barrierattr_t; +# define __PTHREAD_BARRIERATTR_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_BARRIER_T_DEFINED +struct pthread_barrier_s; +typedef struct pthread_barrier_s pthread_barrier_t; +# define __PTHREAD_BARRIER_T_DEFINED 1 +#endif + +#ifndef __PTHREAD_ONCE_T_DEFINED +typedef bool pthread_once_t; +# define __PTHREAD_ONCE_T_DEFINED 1 +#endif + #endif /* __INCLUDE_PTHREAD_H */ diff --git a/include/signal.h b/include/signal.h index 18ab6b85c1..50d6ea9f01 100644 --- a/include/signal.h +++ b/include/signal.h @@ -45,6 +45,9 @@ #include #include +#ifdef CONFIG_SIG_EVTHREAD +# include /* Needed for pthread_attr_t */ +#endif /******************************************************************************** * Pre-processor Definitions @@ -162,8 +165,11 @@ /* Values for the sigev_notify field of struct sigevent */ -#define SIGEV_NONE 0 /* No notification desired */ -#define SIGEV_SIGNAL 1 /* Notify via signal */ +#define SIGEV_NONE 0 /* No asynchronous notification is delivered */ +#define SIGEV_SIGNAL 1 /* Notify via signal,with an application-defined value */ +#ifdef CONFIG_SIG_EVTHREAD +# define SIGEV_THREAD 3 /* A notification function is called */ +#endif /* Special values of of sa_handler used by sigaction and sigset. They are all * treated like NULL for now. This is okay for SIG_DFL and SIG_IGN because @@ -189,6 +195,7 @@ /* This defines a set of 32 signals (numbered 0 through 31). */ typedef uint32_t sigset_t; /* Bit set of 32 signals */ +#define __SIGSET_T_DEFINED 1 /* This defines the type of the siginfo si_value field */ @@ -205,9 +212,14 @@ union sigval struct sigevent { - uint8_t sigev_notify; /* Notification method: SIGEV_SIGNAL or SIGEV_NONE */ + uint8_t sigev_notify; /* Notification method: SIGEV_SIGNAL, SIGEV_NONE, or SIGEV_THREAD */ uint8_t sigev_signo; /* Notification signal */ 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) */ +#endif }; /* The following types is used to pass parameters to/from signal handlers */ @@ -225,6 +237,7 @@ struct siginfo }; typedef struct siginfo siginfo_t; +#define __SIGINFO_T_DEFINED 1 /* Non-standard convenience definition of signal handling function types. * These should be used only internally within the NuttX signal logic. @@ -297,4 +310,23 @@ int sigqueue(int pid, int signo, FAR void *sival_ptr); } #endif +#else /* __INCLUDE_SIGNAL_H */ + +#include + +/* Avoid a circular dependencies by assuring that simple type definitions + * are avaiable in any inclusion ordering. + */ + +#ifndef __SIGSET_T_DEFINED +typedef uint32_t sigset_t; +# define __SIGSET_T_DEFINED 1 +#endif + +#ifndef __SIGINFO_T_DEFINED +struct siginfo; +typedef struct siginfo siginfo_t; +# define __SIGINFO_T_DEFINED 1 +#endif + #endif /* __INCLUDE_SIGNAL_H */ diff --git a/libc/aio/lio_listio.c b/libc/aio/lio_listio.c index b552817e09..38efad0019 100644 --- a/libc/aio/lio_listio.c +++ b/libc/aio/lio_listio.c @@ -213,6 +213,15 @@ static void lio_sighandler(int signo, siginfo_t *info, void *ucontext) #endif } +#ifdef CONFIG_SIG_EVTHREAD + /* Notify the client via a function call */ + + else if (ighand->sig->sigev_notify == SIGEV_THREAD) + { +#warning Missing SIGEV_THREAD logic + } +#endif + /* And free the container */ lib_free(sighand); @@ -711,6 +720,15 @@ int lio_listio(int mode, FAR struct aiocb *const list[], int nent, } } +#ifdef CONFIG_SIG_EVTHREAD + /* Notify the client via a function call */ + + else if (sig && sig->sigev_notify == SIGEV_THREAD) + { +#warning Missing SIGEV_THREAD logic + } +#endif + /* Case 3: mode == LIO_NOWAIT and sig == NULL * * Just return now. diff --git a/sched/Kconfig b/sched/Kconfig index 5aefa848c0..301558ec8d 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -775,6 +775,15 @@ config SCHED_ONEXIT_MAX endmenu # RTOS hooks +config SIG_EVTHREAD + bool "Support SIGEV_THHREAD" + default n + depends on EXPERIMENTAL + ---help--- + Built in support for the SIGEV_THREAD signal deliver method. + + NOTE: Only partially implemented as of this writing. + menu "Signal Numbers" depends on !DISABLE_SIGNALS diff --git a/sched/mqueue/mq_desclose.c b/sched/mqueue/mq_desclose.c index ca7bfc5b8a..881ce5499a 100644 --- a/sched/mqueue/mq_desclose.c +++ b/sched/mqueue/mq_desclose.c @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -128,9 +129,8 @@ void mq_desclose(mqd_t mqdes) #ifndef CONFIG_DISABLE_SIGNALS if (msgq->ntmqdes == mqdes) { + memset(&msgq->ntevent, 0, sizeof(struct sigevent)); msgq->ntpid = INVALID_PROCESS_ID; - msgq->ntsigno = 0; - msgq->ntvalue.sival_int = 0; msgq->ntmqdes = NULL; } #endif diff --git a/sched/mqueue/mq_notify.c b/sched/mqueue/mq_notify.c index c9836715fe..d87c413b3e 100644 --- a/sched/mqueue/mq_notify.c +++ b/sched/mqueue/mq_notify.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -93,7 +94,7 @@ * Parameters: * mqdes - Message queue descriptor * notification - Real-time signal structure containing: - * sigev_notify - Should be SIGEV_SIGNAL (but actually ignored) + * sigev_notify - Should be SIGEV_SIGNAL or SIGEV_THREAD * sigev_signo - The signo to use for the notification * sigev_value - Value associated with the signal * @@ -171,10 +172,11 @@ int mq_notify(mqd_t mqdes, const struct sigevent *notification) /* Yes... Assign it to the current task. */ - msgq->ntvalue.sival_ptr = notification->sigev_value.sival_ptr; - msgq->ntsigno = notification->sigev_signo; - msgq->ntpid = rtcb->pid; - msgq->ntmqdes = mqdes; + memcpy(&msgq->ntevent, ¬ification->sigev_value, + sizeof(struct sigevent)); + + msgq->ntpid = rtcb->pid; + msgq->ntmqdes = mqdes; } } @@ -197,10 +199,9 @@ int mq_notify(mqd_t mqdes, const struct sigevent *notification) * thread to detach the notification. */ - msgq->ntpid = INVALID_PROCESS_ID; - msgq->ntsigno = 0; - msgq->ntvalue.sival_ptr = NULL; - msgq->ntmqdes = NULL; + memset(&msgq->ntevent, 0, sizeof(struct sigevent)); + msgq->ntpid = INVALID_PROCESS_ID; + msgq->ntmqdes = NULL; } sched_unlock(); diff --git a/sched/mqueue/mq_sndinternal.c b/sched/mqueue/mq_sndinternal.c index f2a312f8ef..43abe64e1f 100644 --- a/sched/mqueue/mq_sndinternal.c +++ b/sched/mqueue/mq_sndinternal.c @@ -51,6 +51,8 @@ #include #include #include +#include + #include "sched/sched.h" #ifndef CONFIG_DISABLE_SIGNALS # include "signal/signal.h" @@ -384,30 +386,44 @@ int mq_dosend(mqd_t mqdes, FAR struct mqueue_msg_s *mqmsg, FAR const char *msg, #ifndef CONFIG_DISABLE_SIGNALS if (msgq->ntmqdes) { + struct sigevent event; + pid_t pid; + /* Remove the message notification data from the message queue. */ -#ifdef CONFIG_CAN_PASS_STRUCTS - union sigval value = msgq->ntvalue; -#else - void *sival_ptr = msgq->ntvalue.sival_ptr; -#endif - int signo = msgq->ntsigno; - int pid = msgq->ntpid; + memcpy(&event, &msgq->ntevent, sizeof(struct sigevent)); + pid = msgq->ntpid; /* Detach the notification */ - msgq->ntpid = INVALID_PROCESS_ID; - msgq->ntsigno = 0; - msgq->ntvalue.sival_int = 0; - msgq->ntmqdes = NULL; + memset(&msgq->ntevent, 0, sizeof(struct sigevent)); + msgq->ntpid = INVALID_PROCESS_ID; + msgq->ntmqdes = NULL; - /* Queue the signal -- What if this returns an error? */ + /* Notification the client via signal? */ + + if (event.sigev_notify == SIGEV_SIGNAL) + { + /* Yes... Queue the signal -- What if this returns an error? */ #ifdef CONFIG_CAN_PASS_STRUCTS - sig_mqnotempty(pid, signo, value); + DEBUGVERIFY(sig_mqnotempty(pid, event.sigev_signo, + event.sigev_value)); #else - sig_mqnotempty(pid, signo, sival_ptr); + DEBUGVERIFY(sig_mqnotempty(pid, event.sigev_signo, + event.sigev_value.sival_ptr)); #endif + } + +#ifdef CONFIG_SIG_EVTHREAD + /* Notify the client via a function call */ + + else if (event.sigev_notify == SIGEV_THREAD) + { + DEBUGVERIFY(sig_notification(pid, &event)); + } +#endif + } #endif diff --git a/sched/timer/timer.h b/sched/timer/timer.h index 1f139a1f42..6165d9e847 100644 --- a/sched/timer/timer.h +++ b/sched/timer/timer.h @@ -1,7 +1,7 @@ /******************************************************************************** * sched/timer/timer.h * - * Copyright (C) 2007-2009, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -67,12 +67,11 @@ struct posix_timer_s uint8_t pt_flags; /* See PT_FLAGS_* definitions */ uint8_t pt_crefs; /* Reference count */ - uint8_t pt_signo; /* Notification signal */ pid_t pt_owner; /* Creator of timer */ int pt_delay; /* If non-zero, used to reset repetitive timers */ int pt_last; /* Last value used to set watchdog */ WDOG_ID pt_wdog; /* The watchdog that provides the timing */ - union sigval pt_value; /* Data passed with notification */ + struct sigevent pt_event; /* Notification information */ }; /******************************************************************************** diff --git a/sched/timer/timer_create.c b/sched/timer/timer_create.c index bf6429e3bc..27b2b0fe2b 100644 --- a/sched/timer/timer_create.c +++ b/sched/timer/timer_create.c @@ -215,17 +215,11 @@ int timer_create(clockid_t clockid, FAR struct sigevent *evp, FAR timer_t *timer if (evp) { - ret->pt_signo = evp->sigev_signo; -#ifdef CONFIG_CAN_PASS_STRUCTS - ret->pt_value = evp->sigev_value; -#else - ret->pt_value.sival_ptr = evp->sigev_value.sival_ptr; -#endif + memcpy(&ret->pt_event, evp, sizeof(struct sigevent)); } else { - ret->pt_signo = SIGALRM; - ret->pt_value.sival_ptr = ret; + memset(&ret->pt_event, 0, sizeof(struct sigevent)); } /* Return the timer */ diff --git a/sched/timer/timer_settime.c b/sched/timer/timer_settime.c index 4df42217ee..de8eda47e8 100644 --- a/sched/timer/timer_settime.c +++ b/sched/timer/timer_settime.c @@ -44,6 +44,8 @@ #include #include +#include + #include "clock/clock.h" #include "signal/signal.h" #include "timer/timer.h" @@ -66,7 +68,7 @@ * Private Function Prototypes ********************************************************************************/ -static inline void timer_sigqueue(FAR struct posix_timer_s *timer); +static inline void timer_signotify(FAR struct posix_timer_s *timer); static inline void timer_restart(FAR struct posix_timer_s *timer, wdparm_t itimer); static void timer_timeout(int argc, wdparm_t itimer); @@ -75,7 +77,7 @@ static void timer_timeout(int argc, wdparm_t itimer); ********************************************************************************/ /******************************************************************************** - * Name: timer_sigqueue + * Name: timer_signotify * * Description: * This function basically reimplements sigqueue() so that the si_code can @@ -92,28 +94,42 @@ static void timer_timeout(int argc, wdparm_t itimer); * ********************************************************************************/ -static inline void timer_sigqueue(FAR struct posix_timer_s *timer) +static inline void timer_signotify(FAR struct posix_timer_s *timer) { siginfo_t info; - /* Create the siginfo structure */ + /* Notify client via a signal? */ - info.si_signo = timer->pt_signo; - info.si_code = SI_TIMER; - info.si_errno = OK; + if (timer->pt_event.sigev_notify == SIGEV_SIGNAL) + { + /* Yes.. Create the siginfo structure */ + + info.si_signo = timer->pt_event.sigev_signo; + info.si_code = SI_TIMER; + info.si_errno = OK; #ifdef CONFIG_CAN_PASS_STRUCTS - info.si_value = timer->pt_value; + info.si_value = timer->pt_event.sigev_value; #else - info.si_value.sival_ptr = timer->pt_value.sival_ptr; + info.si_value.sival_ptr = timer->pt_event.sigev_value.sival_ptr; #endif #ifdef CONFIG_SCHED_HAVE_PARENT - info.si_pid = 0; /* Not applicable */ - info.si_status = OK; + info.si_pid = 0; /* Not applicable */ + info.si_status = OK; #endif - /* Send the signal */ + /* Send the signal */ - (void)sig_dispatch(timer->pt_owner, &info); + DEBUGVERIFY(sig_dispatch(timer->pt_owner, &info)); + } + +#ifdef CONFIG_SIG_EVTHREAD + /* Notify the client via a function call */ + + else if (timer->pt_event.sigev_notify == SIGEV_THREAD) + { + DEBUGVERIFY(sig_notification(timer->pt_owner, &timer->pt_event)); + } +#endif } /******************************************************************************** @@ -187,7 +203,7 @@ static void timer_timeout(int argc, wdparm_t itimer) */ u.timer->pt_crefs++; - timer_sigqueue(u.timer); + timer_signotify(u.timer); /* Release the reference. timer_release will return nonzero if the timer * was not deleted. @@ -208,7 +224,7 @@ static void timer_timeout(int argc, wdparm_t itimer) */ timer->pt_crefs++; - timer_sigqueue(timer); + timer_signotify(timer); /* Release the reference. timer_release will return nonzero if the timer * was not deleted.