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:
+
+
+ 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 |
+
+
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;