This commit adds support for default signal actions for SIGSTOP, SIGSTP, and SIGCONT.

Squashed commit of the following:

    Add procfs support to show stopped tasks.  Add nxsig_action() to solve a chicken and egg problem:  We needed to use sigaction to set default actions, but sigaction() would refuse to set actions if the default actions could not be caught or ignored.

    sched/signal:  Add configuration option to selectively enabled/disable default signal actions for SIGSTOP/SIGSTP/SIGCONT and SIGKILL/SIGINT.  Fix some compilation issues.

    sched/sched:  Okay.. I figured out a way to handle state changes that may occur while they were stopped. If a task/thread was already blocked when SIGSTOP/SIGSTP was received, it will restart in the running state.  I will appear that to the task/thread that the blocked condition was interrupt by a signal and returns the EINTR error.

    sched/group and sched/sched:  Finish framework for continue/resume logic.

    sched/signal:  Roughing out basic structure to support task suspend/resume
This commit is contained in:
Gregory Nutt 2018-08-30 10:27:18 -06:00
parent 20fc3ebcdd
commit a7265d71c6
22 changed files with 815 additions and 75 deletions

View File

@ -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.
</p>
<p>
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 <i>real time</i> signals.
In this sense, all NuttX are <i>real time</i> signals by default.
If the configuration option <code>CONFIG_SIG_DEFAULT=y</code> is included, some signals will perform their default actions dependent upon addition configuration settings as summarized in the following table:
</p>
<p><ul><table>
<tr>
<th>Signal</th>
<th>Action</th>
<th>Additional Configuration</th>
</tr>
<tr>
<td><code>SIGUSR1</code></td>
<td>Abnormal Termination</td>
<td><code>CONFIG_SIG_SIGUSR1_ACTION</code></td>
</tr>
<tr>
<td><code>SIGUSR2</code></td>
<td>Abnormal Termination</td>
<td><code>CONFIG_SIG_SIGUSR2_ACTION</code></td>
</tr>
<tr>
<td><code>SIGALRM</code></td>
<td>Abnormal Termination</td>
<td><code>CONFIG_SIG_SIGALRM_ACTION</code></td>
</tr>
<tr>
<td><code>SIGPOLL</code></td>
<td>Abnormal Termination</td>
<td><code>CONFIG_SIG_SIGPOLL_ACTION</code></td>
</tr>
<tr>
<td><code>SIGSTOP</code></td>
<td>Suspend task</td>
<td><code>CONFIG_SIG_SIGSTOP_ACTION</code></td>
</tr>
<tr>
<td><code>SIGSTP</code></td>
<td>Suspend task</td>
<td><code>CONFIG_SIG_SIGSTOP_ACTION</code></td>
</tr>
<tr>
<td><code>SIGCONT</code></td>
<td>Resume task</td>
<td><code>CONFIG_SIG_SIGSTOP_ACTION</code></td>
</tr>
<tr>
<td><code>SIGINT</code></td>
<td>Abnormal Termination</td>
<td><code>CONFIG_SIG_SIGKILL_ACTION</code></td>
</tr>
<tr>
<td><code>SIGKILL</code></td>
<td>Abnormal Termination</td>
<td><code>CONFIG_SIG_SIGKILL_ACTION</code></td>
</tr>
</table></ul></p>
<p>
Tasks may also suspend themselves and wait until a signal is received.
</p>

22
TODO
View File

@ -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.

View File

@ -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

View File

@ -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
};

View File

@ -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;

View File

@ -43,6 +43,7 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdbool.h>
#include <signal.h>
/****************************************************************************
@ -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
*

View File

@ -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 <task>' */
# 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 */

View File

@ -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"

View File

@ -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 <gnutt@nuttx.org>
#
# 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

View File

@ -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 <gnutt@nuttx.org>
*
* 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

View File

@ -0,0 +1,128 @@
/****************************************************************************
* sched/group/group_continue.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <sched.h>
#include <pthread.h>
#include <nuttx/sched.h>
#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 */

View File

@ -0,0 +1,135 @@
/****************************************************************************
* sched/group/group_suspendchildren.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <sched.h>
#include <pthread.h>
#include <nuttx/sched.h>
#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 */

View File

@ -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)) && \

View File

@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -0,0 +1,81 @@
/****************************************************************************
* sched/sched/sched_continue.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sched.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/sched.h>
#include <nuttx/arch.h>
#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);
}

104
sched/sched/sched_suspend.c Normal file
View File

@ -0,0 +1,104 @@
/****************************************************************************
* sched/sched/sched_suspend.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sched.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/sched.h>
#include <nuttx/arch.h>
#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);
}

View File

@ -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 <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without

View File

@ -41,6 +41,7 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <signal.h>
#include <queue.h>
#include <sched.h>
@ -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
*

View File

@ -48,6 +48,7 @@
#include <nuttx/sched.h>
#include <nuttx/irq.h>
#include <nuttx/signal.h>
#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 */

View File

@ -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;