diff --git a/Documentation/NuttxUserGuide.html b/Documentation/NuttxUserGuide.html index a3fd8e55a7..b2328be4fa 100644 --- a/Documentation/NuttxUserGuide.html +++ b/Documentation/NuttxUserGuide.html @@ -4874,10 +4874,63 @@ interface of the same name. The signal handler is a user-supplied function that is bound to a specific signal and performs whatever actions are necessary whenever the signal is received.

- There are no predefined actions for any signal. + By default, here are no predefined actions for any signal. The default action for all signals (i.e., when no signal handler has been supplied by the user) is to ignore the signal. - In this sense, all NuttX are real time signals. + In this sense, all NuttX are real time signals by default. + If the configuration option CONFIG_SIG_DEFAULT=y is included, some signals will perform their default actions dependent upon addition configuration settings as summarized in the following table:

+

Tasks may also suspend themselves and wait until a signal is received.

diff --git a/TODO b/TODO index 0c2487d00c..1373cc1a3a 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -NuttX TODO List (Last updated August 26, 2018) +NuttX TODO List (Last updated August 30, 2018) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with @@ -579,10 +579,24 @@ o Signals (sched/signal, arch/) ^^^^^^^^^^^^^^^^^^^^^^^ Title: STANDARD SIGNALS - Description: 'Standard' signals and signal actions are not supported. - (e.g., SIGINT, SIGSEGV, etc). Default is only SIG_IGN. + Description: 'Standard' signals and signal actions are not fully + supported. The SIGCHLD signal is supported and, if the + option CONFIG_SIG_DEFAULT=y is included, some signals will + perform their default actions (dependent upon addition + configuration settings): + + Signal Action Additional Configuration + ------- -------------------- ------------------------- + SIGUSR1 Abnormal Termination CONFIG_SIG_SIGUSR1_ACTION + SIGUSR2 Abnormal Termination CONFIG_SIG_SIGUSR2_ACTION + SIGALRM Abnormal Termination CONFIG_SIG_SIGALRM_ACTION + SIGPOLL Abnormal Termination CONFIG_SIG_SIGPOLL_ACTION + SIGSTOP Suspend task CONFIG_SIG_SIGSTOP_ACTION + SIGSTP Suspend task CONFIG_SIG_SIGSTOP_ACTION + SIGCONT Resume task CONFIG_SIG_SIGSTOP_ACTION + SIGINT Abnormal Termination CONFIG_SIG_SIGKILL_ACTION + SIGKILL Abnormal Termination CONFIG_SIG_SIGKILL_ACTION - Update: SIGCHLD is supported if so configured. Status: Open. No further changes are planned. Priority: Low, required by standards but not so critical for an embedded system. diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 16aa27087f..052dd6bc52 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -134,7 +134,7 @@ config SERIAL_TERMIOS config TTY_SIGINT bool "Support SIGINT" default n - select SIG_DEFAULT + select SIG_SIGKILL_ACTION depends on !DISABLE_SIGNALS && SERIAL_TERMIOS ---help--- Whether support Ctrl-c/x event. Enabled automatically for console diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c index 09d76b925c..2387f82f55 100644 --- a/fs/procfs/fs_procfsproc.c +++ b/fs/procfs/fs_procfsproc.c @@ -359,13 +359,16 @@ static FAR const char *g_statenames[] = #endif "Running", "Inactive", - "Waiting,Semaphore", + "Waiting,Semaphore" #ifndef CONFIG_DISABLE_SIGNALS - "Waiting,Signal", + , "Waiting,Signal" #endif #ifndef CONFIG_DISABLE_MQUEUE - "Waiting,MQ empty", - "Waiting,MQ full" + , "Waiting,MQ empty" + , "Waiting,MQ full" +#endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION + , "Stopped" #endif }; diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 45ea27c39e..828d5f453f 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -245,6 +245,10 @@ enum tstate_e #ifdef CONFIG_PAGING TSTATE_WAIT_PAGEFILL, /* BLOCKED - Waiting for page fill */ #endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION + TSTATE_TASK_STOPPED, /* BLOCKED - Waiting for SIGCONT */ +#endif + NUM_TASK_STATES /* Must be last */ }; typedef enum tstate_e tstate_t; diff --git a/include/nuttx/signal.h b/include/nuttx/signal.h index a2b65e99b5..903b4a9dfd 100644 --- a/include/nuttx/signal.h +++ b/include/nuttx/signal.h @@ -43,6 +43,7 @@ #include #include +#include #include /**************************************************************************** @@ -69,25 +70,27 @@ */ #if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__) -# define _SIG_PROCMASK(h,s,o) nxsig_procmask(h,s,o) -# define _SIG_QUEUE(p,s,v) nxsig_queue(p,s,v) -# define _SIG_KILL(p,s) nxsig_kill(p,s); -# define _SIG_WAITINFO(s,i) nxsig_timedwait(s,i,NULL) -# define _SIG_NANOSLEEP(r,a) nxsig_nanosleep(r,a) -# define _SIG_SLEEP(s) nxsig_sleep(s) -# define _SIG_USLEEP(u) nxsig_usleep(u) -# define _SIG_ERRNO(r) (-(r)) -# define _SIG_ERRVAL(r) (r) +# define _SIG_PROCMASK(h,s,o) nxsig_procmask(h,s,o) +# define _SIG_SIGACTION(s,a,o) nxsig_action(s,a,o,false) +# define _SIG_QUEUE(p,s,v) nxsig_queue(p,s,v) +# define _SIG_KILL(p,s) nxsig_kill(p,s); +# define _SIG_WAITINFO(s,i) nxsig_timedwait(s,i,NULL) +# define _SIG_NANOSLEEP(r,a) nxsig_nanosleep(r,a) +# define _SIG_SLEEP(s) nxsig_sleep(s) +# define _SIG_USLEEP(u) nxsig_usleep(u) +# define _SIG_ERRNO(r) (-(r)) +# define _SIG_ERRVAL(r) (r) #else -# define _SIG_PROCMASK(h,s,o) sigprocmask(h,s,o) -# define _SIG_QUEUE(p,s,v) sigqueue(p,s,v) -# define _SIG_KILL(p,s) kill(p,s); -# define _SIG_WAITINFO(s,i) sigwaitinfo(s,i) -# define _SIG_NANOSLEEP(r,a) nanosleep(r,a) -# define _SIG_SLEEP(s) sleep(s) -# define _SIG_USLEEP(u) usleep(u) -# define _SIG_ERRNO(r) errno -# define _SIG_ERRVAL(r) (-errno) +# define _SIG_PROCMASK(h,s,o) sigprocmask(h,s,o) +# define _SIG_SIGACTION(s,a,o) sigaction(s,a,o) +# define _SIG_QUEUE(p,s,v) sigqueue(p,s,v) +# define _SIG_KILL(p,s) kill(p,s); +# define _SIG_WAITINFO(s,i) sigwaitinfo(s,i) +# define _SIG_NANOSLEEP(r,a) nanosleep(r,a) +# define _SIG_SLEEP(s) sleep(s) +# define _SIG_USLEEP(u) usleep(u) +# define _SIG_ERRNO(r) errno +# define _SIG_ERRVAL(r) (-errno) #endif /**************************************************************************** @@ -138,6 +141,32 @@ struct timespec; /* Forward reference */ int nxsig_procmask(int how, FAR const sigset_t *set, FAR sigset_t *oset); +/**************************************************************************** + * Name: nxsig_action + * + * Description: + * This function allows the calling process to examine and/or specify the + * action to be associated with a specific signal. This is a non-standard, + * OS internal version of the standard sigaction() function. nxsig_action() + * adds an additional parameter, force, that is used to set default signal + * actions (which may not normally be settable). nxsig_action() does not + * alter the errno variable. + * + * Input Parameters: + * sig - Signal of interest + * act - Location of new handler + * oact - Location to store only handler + * force - Force setup of the signal handler + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int nxsig_action(int signo, FAR const struct sigaction *act, + FAR struct sigaction *oact, bool force); + /**************************************************************************** * Name: nxsig_queue * diff --git a/include/signal.h b/include/signal.h index d6edd2a0f8..ea76843961 100644 --- a/include/signal.h +++ b/include/signal.h @@ -169,17 +169,15 @@ # endif #endif -#ifdef CONFIG_SIG_DEFAULT -# ifndef CONFIG_SIG_INT -# define SIGINT 6 /* Sent when ctrl-c event */ -# else -# define SIGINT CONFIG_SIG_INT -# endif -# ifndef CONFIG_SIG_KILL -# define SIGKILL 9 /* Sent from shell as 'kill -9 ' */ -# else -# define SIGKILL CONFIG_SIG_KILL -# endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION +# define SIGSTOP CONFIG_SIG_STOP +# define SIGSTP CONFIG_SIG_STP +# define SIGCONT CONFIG_SIG_CONT +#endif + +#ifdef CONFIG_SIG_SIGKILL_ACTION +# define SIGKILL CONFIG_SIG_KILL +# define SIGINT CONFIG_SIG_INT #endif /* The following are non-standard signal definitions */ diff --git a/sched/Kconfig b/sched/Kconfig index 4e12237b28..7290fbbf15 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -1201,30 +1201,52 @@ config SIG_SIGUSR1_ACTION bool "SIGUSR1" default n ---help--- - Enable the default action for SIGUSR1 (terminate the process) + Enable the default action for SIGUSR1 (terminate the task) Make sure that your applications are expecting this POSIX behavior. + Backward compatible behavior would require that the application use + sigaction() to ignore SIGUSR1. config SIG_SIGUSR2_ACTION bool "SIGUSR2" default n ---help--- - Enable the default action for SIGUSR2 (terminate the process) + Enable the default action for SIGUSR2 (terminate the task) Make sure that your applications are expecting this POSIX behavior. + Backward compatible behavior would require that the application use + sigaction() to ignore SIGUSR2. config SIG_SIGALRM_ACTION bool "SIGALRM" default n ---help--- - Enable the default action for SIGALRM (terminate the process) + Enable the default action for SIGALRM (terminate the task) Make sure that your applications are expecting this POSIX behavior. + Backward compatible behavior would require that the application use + sigaction() to ignore SIGALRM. config SIG_SIGPOLL_ACTION bool "SIGPOLL" default n depends on FS_AIO ---help--- - Enable the default action for SIGPOLL (terminate the process) + Enable the default action for SIGPOLL (terminate the task) Make sure that your applications are expecting this POSIX behavior. + Backward compatible behavior would require that the application use + sigaction() to ignore SIGPOLL. + +config SIG_SIGSTOP_ACTION + bool "SIGSTOP SIGSTP, and SIGCONT" + default y + ---help--- + Enable the default action for SIGSTOP and SIGSTP (suspend the + task) and SIGCONT (resume the task). + +config SIG_SIGKILL_ACTION + bool "SIGINT and SIGKILL" + default y + ---help--- + Enable the default action for SIGINT and SIGKILL (terminate the + task). endif # SIG_DEFAULT @@ -1269,22 +1291,49 @@ config SIG_POLL The SIGPOLL signal is sent to a process when an asynchronous I/O event occurs (meaning it has been polled). Default: 5 -config SIG_INT - int "SIGINT" +if SIG_DEFAULT + +config SIG_STOP + int "SIGSTOP" default 6 - depends on SIG_DEFAULT + depends on SIG_SIGSTOP_ACTION ---help--- - The SIGINT signal is sent to cause a task termination event (only - if CONFIG_SIG_DEFAULT=y). SIGINT may be ignored or caught by the - receiving task. + Suspend/pause a task. SIGSTOP may not be caught or ignored. + +config SIG_STP + int "SIGSTP" + default 7 + depends on SIG_SIGSTOP_ACTION + ---help--- + Suspend/pause a task. Unlike SIGSTOP, this signal can be caught or + ignored. + +config SIG_CONT + int "SIGCONT" + default 8 + depends on SIG_SIGSTOP_ACTION + ---help--- + Resume a suspended/paused task. SIGSTOP only has an action when + send to a stopped task. SIGCONT is ignored by other task. SIGCONT + may not be caught or ignored by a stopped task. config SIG_KILL int "SIGKILL" default 9 - depends on SIG_DEFAULT + depends on SIG_SIGKILL_ACTION ---help--- - The SIGKILL signal is sent to cause a task termination event (only - if CONFIG_SIG_DEFAULT=y). SIGKILL may not be caught or ignored. + The SIGKILL signal is sent to cause a task termination event. + SIGKILL may not be caught or ignored. + +config SIG_INT + int "SIGINT" + default 10 + depends on SIG_SIGKILL_ACTION + ---help--- + The SIGINT signal is sent to cause a task termination event. + SIGINT may be ignored or caught by the receiving task. + +endif # SIG_DEFAULT comment "Non-standard Signal Numbers" diff --git a/sched/group/Make.defs b/sched/group/Make.defs index 5cf67634c2..2eb414c331 100644 --- a/sched/group/Make.defs +++ b/sched/group/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # sched/group/Make.defs # -# Copyright (C) 2014 Gregory Nutt. All rights reserved. +# Copyright (C) 2014, 2018 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -52,6 +52,10 @@ ifeq ($(CONFIG_ARCH_ADDRENV),y) CSRCS += group_addrenv.c endif +ifeq ($(CONFIG_SIG_SIGSTOP_ACTION),y) +CSRCS += group_suspendchildren.c group_continue.c +endif + ifeq ($(CONFIG_BINFMT_LOADABLE),y) CSRCS += group_exitinfo.c endif diff --git a/sched/group/group.h b/sched/group/group.h index a508d5d462..1448e5b5ef 100644 --- a/sched/group/group.h +++ b/sched/group/group.h @@ -1,7 +1,7 @@ /**************************************************************************** * sched/group/group.h * - * Copyright (C) 2007-2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2013, 2015, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -116,6 +116,10 @@ FAR struct task_group_s *group_findbypid(pid_t pid); int group_foreachchild(FAR struct task_group_s *group, foreachchild_t handler, FAR void *arg); int group_killchildren(FAR struct task_tcb_s *tcb); +#ifdef CONFIG_SIG_SIGSTOP_ACTION +int group_suspendchildren(FAR struct task_tcb_s *tcb); +int group_continue(FAR struct task_tcb_s *tcb); +#endif #endif #ifdef CONFIG_ARCH_ADDRENV diff --git a/sched/group/group_continue.c b/sched/group/group_continue.c new file mode 100644 index 0000000000..624480e089 --- /dev/null +++ b/sched/group/group_continue.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * sched/group/group_continue.c + * + * Copyright (C) 2018 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 "sched/sched.h" +#include "group/group.h" + +#ifdef HAVE_GROUP_MEMBERS + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: group_continue_handler + * + * Description: + * Callback from group_foreachchild that handles one member of the group. + * + * Input Parameters: + * pid - The ID of the group member that may be resumed. + * arg - Unused + * + * Returned Value: + * 0 (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int group_continue_handler(pid_t pid, FAR void *arg) +{ + FAR struct tcb_s *rtcb; + int ret; + + /* Resume all threads */ + + rtcb = sched_gettcb(pid); + if (rtc != NULL) + { + ret = sched_resume(rtcb); + if (ret < 0) + { + serr("ERROR: Failed to resume %d: %d\n", ret, pid); + } + } + + /* Always return zero. We need to visit each member of the group*/ + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: group_continue + * + * Description: + * Resume all members of the task group. This is SIGCONT default signal + * action logic. + * + * Input Parameters: + * tcb - TCB of the task to be retained. + * + * Returned Value: + * None + * + ****************************************************************************/ + +int group_continue(FAR struct task_tcb_s *tcb) +{ + int ret; + + /* Lock the scheduler so that there this thread will not lose priority + * until all of its children are suspended. + */ + + sched_lock(); + ret = group_foreachchild(tcb->cmn.group, group_continue_handler, NULL); + sched_unlock(); + return ret; +} + +#endif /* HAVE_GROUP_MEMBERS */ diff --git a/sched/group/group_suspendchildren.c b/sched/group/group_suspendchildren.c new file mode 100644 index 0000000000..27761e9414 --- /dev/null +++ b/sched/group/group_suspendchildren.c @@ -0,0 +1,135 @@ +/**************************************************************************** + * sched/group/group_suspendchildren.c + * + * Copyright (C) 2018 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 "sched/sched.h" +#include "group/group.h" + +#ifdef HAVE_GROUP_MEMBERS + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: group_suspendchildren_handler + * + * Description: + * Callback from group_foreachchild that handles one member of the group. + * + * Input Parameters: + * pid - The ID of the group member that may be suspended. + * arg - The PID of the thread to be retained. + * + * Returned Value: + * 0 (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int group_suspendchildren_handler(pid_t pid, FAR void *arg) +{ + FAR struct tcb_s *rtcb; + int ret; + + /* Suspend all threads except for the one specified by the argument */ + + if (pid != (pid_t)((uintptr_t)arg)) + { + /* Suspend this thread if it is still alive. */ + + rtcb = sched_gettcb(pid); + if (rtcb != NULL) + { + ret = sched_suspend(rtcb); + if (ret < 0) + { + serr("ERROR: Failed to suspend %d: %d\n", ret, pid); + } + } + } + + /* Always return zero. We need to visit each member of the group*/ + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: group_suspendchildren + * + * Description: + * Suspend all children of a task except for the specified task. This is + * SIGSTP/SIGSTOP default signal action logic. When the main task is + * suspended, all of its child pthreads must also be suspended. + * + * Input Parameters: + * tcb - TCB of the task to be retained. + * + * Returned Value: + * None + * + ****************************************************************************/ + +int group_suspendchildren(FAR struct task_tcb_s *tcb) +{ + int ret; + + /* Lock the scheduler so that there this thread will not lose priority + * until all of its children are suspended. + */ + + sched_lock(); + ret = group_foreachchild(tcb->cmn.group, group_suspendchildren_handler, + (FAR void *)((uintptr_t)tcb->cmn.pid)); + sched_unlock(); + return ret; +} + +#endif /* HAVE_GROUP_MEMBERS */ diff --git a/sched/init/os_start.c b/sched/init/os_start.c index 689abaf6b6..0b80dea7d0 100644 --- a/sched/init/os_start.c +++ b/sched/init/os_start.c @@ -182,6 +182,12 @@ volatile dq_queue_t g_waitingformqnotfull; volatile dq_queue_t g_waitingforfill; #endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION +/* This is the list of all tasks that have been stopped via SIGSTOP or SIGSTP */ + +volatile dq_queue_t g_stoppedtasks; +#endif + /* This the list of all tasks that have been initialized, but not yet * activated. NOTE: This is the only list that is not prioritized. */ @@ -300,6 +306,13 @@ const struct tasklist_s g_tasklisttable[NUM_TASK_STATES] = TLIST_ATTR_PRIORITIZED } #endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION + , + { /* TSTATE_TASK_STOPPED */ + &g_stoppedtasks, + 0 /* See tcb->prev_state */ + }, +#endif }; /* This is the current initialization state. The level of initialization @@ -397,6 +410,9 @@ void os_start(void) #endif #ifdef CONFIG_PAGING dq_init(&g_waitingforfill); +#endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION + dq_init(&g_stoppedtasks); #endif dq_init(&g_inactivetasks); #if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \ diff --git a/sched/irq/irq_dispatch.c b/sched/irq/irq_dispatch.c index ee80e9269b..afb19fac2c 100644 --- a/sched/irq/irq_dispatch.c +++ b/sched/irq/irq_dispatch.c @@ -158,4 +158,5 @@ void irq_dispatch(int irq, FAR void *context) /* Then dispatch to the interrupt handler */ CALL_VECTOR(ndx, vector, irq, context, arg); + UNUSED(ndx); } diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index 333dc0a23b..fd0bc78b7d 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -54,6 +54,10 @@ CSRCS += sched_cpuselect.c sched_cpupause.c CSRCS += sched_getaffinity.c sched_setaffinity.c endif +ifeq ($(CONFIG_SIG_SIGSTOP_ACTION),y) +CSRCS += sched_suspend.c sched_continue.c +endif + ifeq ($(CONFIG_SCHED_WAITPID),y) CSRCS += sched_waitpid.c ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) diff --git a/sched/sched/sched.h b/sched/sched/sched.h index dca36d1f6c..038398472a 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -440,6 +440,11 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks, void sched_sporadic_lowpriority(FAR struct tcb_s *tcb); #endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION +void sched_suspend(FAR struct tcb_s *tcb); +void sched_continue(FAR struct tcb_s *tcb); +#endif + #ifdef CONFIG_SMP #if defined(CONFIG_ARCH_GLOBAL_IRQDISABLE) || defined(CONFIG_ARCH_HAVE_FETCHADD) FAR struct tcb_s *this_task(void); diff --git a/sched/sched/sched_continue.c b/sched/sched/sched_continue.c new file mode 100644 index 0000000000..495b0e671c --- /dev/null +++ b/sched/sched/sched_continue.c @@ -0,0 +1,81 @@ +/**************************************************************************** + * sched/sched/sched_continue.c + * + * Copyright (C) 2018 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 + +#include "sched/sched.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sched_continue + * + * Description: + * Resume the specified thread. This is normally calling indirectly + * via group_continue(); + * + ****************************************************************************/ + +void sched_continue(FAR struct tcb_s *tcb) +{ + irqstate_t flags; + + DEBUGASSERT(tcb != NULL && tcb->task_state == TSTATE_TASK_STOPPED); + + flags = enter_critical_section(); + + /* Simply restart the thread. If is was blocked before, it will awaken + * with pterrno = EINTR and will appears as if it were awakened by a + * signal. If pre-emption is not disabled this action could block this + * task here! + */ + + up_unblock_task(tcb); + leave_critical_section(flags); +} diff --git a/sched/sched/sched_suspend.c b/sched/sched/sched_suspend.c new file mode 100644 index 0000000000..eb9c580f58 --- /dev/null +++ b/sched/sched/sched_suspend.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * sched/sched/sched_suspend.c + * + * Copyright (C) 2018 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 + +#include "sched/sched.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sched_suspend + * + * Description: + * Suspend/pause the specified thread. This is normally calling indirectly + * via group_suspendchildren(); + * + ****************************************************************************/ + +void sched_suspend(FAR struct tcb_s *tcb) +{ + irqstate_t flags; + + DEBUGASSERT(tcb != NULL); + + flags = enter_critical_section(); + + /* Check the current state of the task */ + + if (tcb->task_state >= FIRST_BLOCKED_STATE && + tcb->task_state <= LAST_BLOCKED_STATE) + { + /* Remove the TCB from the the blocked task list. */ + + sched_removeblocked(tcb); + + /* Set the errno value to EINTR. The task will be restarted in the + * running or runnable state and will appear to have awakened from + * the block state by a signal. + */ + + tcb->pterrno = EINTR; + + /* Move the TCB to the g_stoppedtasks list. */ + + sched_addblocked(tcb, TSTATE_TASK_STOPPED); + } + else + { + /* The task was running or runnable before being stopped. Simply + * block it in the stopped state. If tcb refers to this task, then + * this action will block this task. + */ + + up_block_task(tcb, TSTATE_TASK_STOPPED); + } + + leave_critical_section(flags); +} diff --git a/sched/signal/Make.defs b/sched/signal/Make.defs index 984016b24e..cf907c277b 100644 --- a/sched/signal/Make.defs +++ b/sched/signal/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # sched/signal/Make.defs # -# Copyright (C) 2014 Gregory Nutt. All rights reserved. +# Copyright (C) 2014, 2018 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without diff --git a/sched/signal/sig_action.c b/sched/signal/sig_action.c index 5f8a20dd47..d904525531 100644 --- a/sched/signal/sig_action.c +++ b/sched/signal/sig_action.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -94,7 +95,7 @@ static FAR sigactq_t *nxsig_alloc_action(void) ****************************************************************************/ /**************************************************************************** - * Name: sigaction + * Name: nxsig_action and sigaction * * Description: * This function allows the calling process to examine and/or specify the @@ -123,16 +124,28 @@ static FAR sigactq_t *nxsig_alloc_action(void) * original signal mask is restored. * * Once an action is installed for a specific signal, it remains installed - * until another action is explicitly requested by another call to sigaction(). + * until another action is explicitly requested by another call to + * sigaction(). + * + * nxsig_action() is an internal version of sigaction that adds an + * additional parameter, force, that is used to set default signal actions + * (which may not normally be settable). nxsig_action() does not alter the + * errno variable. * * Input Parameters: - * sig - Signal of interest - * act - Location of new handler - * oact - Location to store only handler + * sig - Signal of interest + * act - Location of new handler + * oact - Location to store only handler + * force - Force setup of the signal handler, even if it cannot normally + * be caught or ignored (nxsig_action only) * * Returned Value: - * 0 (OK), or -1 (ERROR) if the signal number is invalid. - * (errno is not set) + * nxsig_action: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure + * sigaction: + * Zero (OK) is returned on success; -1 (ERROR) is returned on any + * failure if the signal number is invalid with the errno set appropriately * * Assumptions: * @@ -145,8 +158,8 @@ static FAR sigactq_t *nxsig_alloc_action(void) * ****************************************************************************/ -int sigaction(int signo, FAR const struct sigaction *act, - FAR struct sigaction *oact) +int nxsig_action(int signo, FAR const struct sigaction *act, + FAR struct sigaction *oact, bool force) { FAR struct tcb_s *rtcb = this_task(); FAR struct task_group_s *group; @@ -164,8 +177,7 @@ int sigaction(int signo, FAR const struct sigaction *act, if (!GOOD_SIGNO(signo)) { - set_errno(EINVAL); - return ERROR; + return -EINVAL; } #ifdef CONFIG_SIG_DEFAULT @@ -173,11 +185,10 @@ int sigaction(int signo, FAR const struct sigaction *act, * caught or ignored. */ - if (act != NULL && - (act->sa_handler != SIG_DFL && !nxsig_iscatchable(signo))) + if (act != NULL && !force && act->sa_handler != SIG_DFL && + !nxsig_iscatchable(signo)) { - set_errno(EINVAL); - return ERROR; + return -EINVAL; } #endif @@ -316,8 +327,7 @@ int sigaction(int signo, FAR const struct sigaction *act, if (!sigact) { - set_errno(ENOMEM); - return ERROR; + return -ENOMEM; } /* Put the signal number in the queue entry */ @@ -339,6 +349,23 @@ int sigaction(int signo, FAR const struct sigaction *act, return OK; } +int sigaction(int signo, FAR const struct sigaction *act, + FAR struct sigaction *oact) +{ + int ret; + + /* nxsig_action() does all of the work */ + + ret = nxsig_action(signo, act, oact, false); + if (ret < 0) + { + set_errno(-ret); + return ERROR; + } + + return OK; +} + /**************************************************************************** * Name: nxsig_release_action * diff --git a/sched/signal/sig_default.c b/sched/signal/sig_default.c index 59bfb60cc9..3e510cdb7e 100644 --- a/sched/signal/sig_default.c +++ b/sched/signal/sig_default.c @@ -48,6 +48,7 @@ #include #include +#include #include "group/group.h" #include "sched/sched.h" @@ -80,7 +81,9 @@ struct nxsig_defaction_s /* Default actions */ +static void nxsig_null_action(int signo); static void nxsig_abnormal_termination(int signo); +static void nxsig_stop_task(int signo); /* Helpers */ @@ -116,8 +119,15 @@ static const struct nxsig_defaction_s g_defactions[] = #ifdef CONFIG_SIG_SIGPOLL_ACTION { SIGPOLL, 0, nxsig_abnormal_termination }, #endif +#ifdef CONFIG_SIG_SIGSTOP_ACTION + { SIGSTOP, SIG_FLAG_NOCATCH, nxsig_stop_task }, + { SIGSTP, 0, nxsig_stop_task }, + { SIGCONT, SIG_FLAG_NOCATCH, nxsig_null_action }, +#endif +#ifdef CONFIG_SIG_SIGKILL_ACTION { SIGINT, 0, nxsig_abnormal_termination }, { SIGKILL, SIG_FLAG_NOCATCH, nxsig_abnormal_termination } +#endif }; #define NACTIONS (sizeof(g_defactions) / sizeof(struct nxsig_defaction_s)) @@ -142,6 +152,24 @@ static const struct nxsig_defaction_s g_defactions[] = * - Continue the process, if it is stopped; otherwise, ignore the signal. */ +/**************************************************************************** + * Name: nxsig_null_action + * + * Description: + * The do-nothing default signal actin handler. + * + * Input Parameters: + * Standard signal handler parameters + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void nxsig_null_action(int signo) +{ +} + /**************************************************************************** * Name: nxsig_abnormal_termination * @@ -195,6 +223,42 @@ static void nxsig_abnormal_termination(int signo) } } +/**************************************************************************** + * Name: nxsig_stop_task + * + * Description: + * This is the handler for the abnormal termination default action. + * + * Input Parameters: + * Standard signal handler parameters + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void nxsig_stop_task(int signo) +{ + FAR struct tcb_s *rtcb = (FAR struct tcb_s *)this_task(); + + /* Careful: In the multi-threaded task, the signal may be handled on a + * child pthread. + */ + +#ifdef HAVE_GROUP_MEMBERS + /* Suspend of of the children of the task. This will not suspend the + * currently running task/pthread (this_task). It will suspend the + * main thread of the task group if the this_task is a pthread. + */ + + group_suspendchildren((FAR struct task_tcb_s *)rtcb); +#endif + + /* Then, finally, suspend this thread */ + + sched_suspend(rtcb); +} + /**************************************************************************** * Name: nxsig_default_action * @@ -260,13 +324,14 @@ static void nxsig_setup_default_action(FAR struct task_group_s *group, /* Attach the signal handler. * - * NOTE: sigaction will call nxsig_default(tcb, action, false) + * NOTE: nxsig_action will call nxsig_default(tcb, action, false). + * Don't be surprised. */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = info->action; sa.sa_flags = SA_SIGINFO; - (void)sigaction(info->signo, &sa, NULL); + (void)nxsig_action(info->signo, &sa, NULL, true); /* Indicate that the default signal handler has been attached */ diff --git a/sched/signal/sig_dispatch.c b/sched/signal/sig_dispatch.c index 1085b168b6..977de7cdfe 100644 --- a/sched/signal/sig_dispatch.c +++ b/sched/signal/sig_dispatch.c @@ -402,6 +402,22 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info) nxmq_wait_irq(stcb, EINTR); } #endif + +#ifdef CONFIG_SIG_SIGSTOP_ACTION + /* If the task was stopped by SIGSTOP or SIGSTP, then unblock the task + * if SIGCONT is received. + */ + + if (stcb->task_state == TSTATE_TASK_STOPPED && + info->si_signo == SIGCONT) + { +#ifdef HAVE_GROUP_MEMBERS + group_continue(stcb); +#else + sched_continue(stcb); +#endif + } +#endif } return ret;