6a3c2aded6
* Simplify EINTR/ECANCEL error handling 1. Add semaphore uninterruptible wait function 2 .Replace semaphore wait loop with a single uninterruptible wait 3. Replace all sem_xxx to nxsem_xxx * Unify the void cast usage 1. Remove void cast for function because many place ignore the returned value witout cast 2. Replace void cast for variable with UNUSED macro
383 lines
12 KiB
C
383 lines
12 KiB
C
/****************************************************************************
|
|
* sched/signal/sig_action.c
|
|
*
|
|
* Copyright (C) 2007-2009, 2013, 2016-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 <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <signal.h>
|
|
#include <queue.h>
|
|
#include <sched.h>
|
|
#include <errno.h>
|
|
|
|
#include <nuttx/irq.h>
|
|
|
|
#include "sched/sched.h"
|
|
#include "group/group.h"
|
|
#include "signal/signal.h"
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: nxsig_alloc_action
|
|
*
|
|
* Description:
|
|
* Allocate a new element for a sigaction queue
|
|
*
|
|
****************************************************************************/
|
|
|
|
static FAR sigactq_t *nxsig_alloc_action(void)
|
|
{
|
|
FAR sigactq_t *sigact;
|
|
|
|
/* Try to get the signal action structure from the free list */
|
|
|
|
sigact = (FAR sigactq_t *)sq_remfirst(&g_sigfreeaction);
|
|
|
|
/* Check if we got one. */
|
|
|
|
if (!sigact)
|
|
{
|
|
/* Add another block of signal actions to the list */
|
|
|
|
nxsig_alloc_actionblock();
|
|
|
|
/* And try again */
|
|
|
|
sigact = (FAR sigactq_t *)sq_remfirst(&g_sigfreeaction);
|
|
DEBUGASSERT(sigact);
|
|
}
|
|
|
|
return sigact;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: nxsig_action and sigaction
|
|
*
|
|
* Description:
|
|
* This function allows the calling process to examine and/or specify the
|
|
* action to be associated with a specific signal.
|
|
*
|
|
* The structure sigaction, used to describe an action to be taken, is
|
|
* defined to include the following members:
|
|
*
|
|
* - sa_u.sa_handler: Pointer to a signal-catching function
|
|
* - sa_u.sa_sigaction: Alternative form of the signal-catching function
|
|
* - sa_mask: An additional set of signals to be blocked during execution
|
|
* of a signal catching function
|
|
* - sa_flags. Special flags to affect the behavior of a signal.
|
|
*
|
|
* If the argument 'act' is not NULL, it points to a structure specifying
|
|
* the action to be associated with the specified signal. If the argument
|
|
* 'oact' is not NULL, the action previously associated with the signal
|
|
* is stored in the location pointed to by the argument 'oact.'
|
|
*
|
|
* When a signal is caught by a signal-catching function installed by
|
|
* sigaction() function, a new signal mask is calculated and installed for
|
|
* the duration of the signal-catching function. This mask is formed by
|
|
* taking the union of the current signal mask and the value of the
|
|
* sa_mask for the signal being delivered and then including the signal
|
|
* being delivered. If and when the user's signal handler returns, the
|
|
* 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().
|
|
*
|
|
* 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
|
|
* force - Force setup of the signal handler, even if it cannot normally
|
|
* be caught or ignored (nxsig_action only)
|
|
*
|
|
* Returned Value:
|
|
* 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:
|
|
*
|
|
* POSIX Compatibility:
|
|
* - If CONFIG_SIG_DEFAULT is not defined, then there are no default actions
|
|
* so the special value SIG_DFL is treated like SIG_IGN.
|
|
* - All sa_flags in struct sigaction of act input are ignored (all
|
|
* treated like SA_SIGINFO). The one exception is if CONFIG_SCHED_CHILD_STATUS
|
|
* is defined; then SA_NOCLDWAIT is supported but only for SIGCHLD
|
|
*
|
|
****************************************************************************/
|
|
|
|
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;
|
|
FAR sigactq_t *sigact;
|
|
_sa_handler_t handler;
|
|
|
|
/* Since sigactions can only be installed from the running thread of
|
|
* execution, no special precautions should be necessary.
|
|
*/
|
|
|
|
DEBUGASSERT(rtcb != NULL && rtcb->group != NULL);
|
|
group = rtcb->group;
|
|
|
|
/* Verify the signal number */
|
|
|
|
if (!GOOD_SIGNO(signo))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_SIG_DEFAULT
|
|
/* Check if the user is trying to catch or ignore a signal that cannot be
|
|
* caught or ignored.
|
|
*/
|
|
|
|
if (act != NULL && !force && act->sa_handler != SIG_DFL &&
|
|
!nxsig_iscatchable(signo))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
/* Find the signal in the signal action queue */
|
|
|
|
sigact = nxsig_find_action(group, signo);
|
|
|
|
/* Return the old sigaction value if so requested */
|
|
|
|
if (oact != NULL)
|
|
{
|
|
#ifdef CONFIG_SIG_DEFAULT
|
|
if (nxsig_isdefault(rtcb, signo))
|
|
{
|
|
/* Return SIG_DFL if the default signal is attached */
|
|
|
|
oact->sa_handler = SIG_DFL;
|
|
oact->sa_mask = NULL_SIGNAL_SET;
|
|
oact->sa_flags = SA_SIGINFO;
|
|
}
|
|
else
|
|
#endif
|
|
if (sigact)
|
|
{
|
|
/* Return the old signal action */
|
|
|
|
oact->sa_handler = sigact->act.sa_handler;
|
|
oact->sa_mask = sigact->act.sa_mask;
|
|
oact->sa_flags = sigact->act.sa_flags;
|
|
}
|
|
else
|
|
{
|
|
/* There isn't an old value */
|
|
|
|
oact->sa_handler = NULL;
|
|
oact->sa_mask = NULL_SIGNAL_SET;
|
|
oact->sa_flags = 0;
|
|
}
|
|
}
|
|
|
|
/* If the argument act is a null pointer, signal handling is unchanged;
|
|
* thus, the call can be used to inquire about the current handling of
|
|
* a given signal.
|
|
*/
|
|
|
|
if (act == NULL)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
|
|
/* Handle a special case. Retention of child status can be suppressed
|
|
* if signo == SIGCHLD and sa_flags == SA_NOCLDWAIT.
|
|
*
|
|
* POSIX.1 leaves it unspecified whether a SIGCHLD signal is generated
|
|
* when a child process terminates. In NuttX, a SIGCHLD signal is
|
|
* generated in this case; but in some other implementations, it may not
|
|
* be.
|
|
*/
|
|
|
|
if (signo == SIGCHLD && (act->sa_flags & SA_NOCLDWAIT) != 0)
|
|
{
|
|
irqstate_t flags;
|
|
|
|
/* We do require a critical section to muck with the TCB values that
|
|
* can be modified by the child thread.
|
|
*/
|
|
|
|
flags = enter_critical_section();
|
|
|
|
/* Mark that status should be not be retained */
|
|
|
|
rtcb->group->tg_flags |= GROUP_FLAG_NOCLDWAIT;
|
|
|
|
/* Free all pending exit status */
|
|
|
|
group_removechildren(rtcb->group);
|
|
leave_critical_section(flags);
|
|
}
|
|
#endif
|
|
|
|
handler = act->sa_handler;
|
|
|
|
#ifdef CONFIG_SIG_DEFAULT
|
|
/* If the caller is setting the handler to SIG_DFL, then we need to
|
|
* replace this with the correct, internal default signal action handler.
|
|
*/
|
|
|
|
if (handler == SIG_DFL)
|
|
{
|
|
/* nxsig_default() may returned SIG_IGN */
|
|
|
|
handler = nxsig_default(rtcb, signo, true);
|
|
}
|
|
else
|
|
{
|
|
/* We will be replacing the default action (or ignoring it) */
|
|
|
|
nxsig_default(rtcb, signo, false);
|
|
}
|
|
#endif
|
|
|
|
/* Handle the case where no sigaction is supplied (SIG_IGN) */
|
|
|
|
if (handler == SIG_IGN)
|
|
{
|
|
/* Do we still have a sigaction container from the previous setting? */
|
|
|
|
if (sigact)
|
|
{
|
|
/* Yes.. Remove it from signal action queue */
|
|
|
|
sq_rem((FAR sq_entry_t *)sigact, &group->tg_sigactionq);
|
|
|
|
/* And deallocate it */
|
|
|
|
nxsig_release_action(sigact);
|
|
}
|
|
}
|
|
|
|
/* A sigaction has been supplied */
|
|
|
|
else
|
|
{
|
|
/* Do we still have a sigaction container from the previous setting?
|
|
* If so, then re-use for the new signal action.
|
|
*/
|
|
|
|
if (sigact == NULL)
|
|
{
|
|
/* No.. Then we need to allocate one for the new action. */
|
|
|
|
sigact = nxsig_alloc_action();
|
|
|
|
/* An error has occurred if we could not allocate the sigaction */
|
|
|
|
if (!sigact)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Put the signal number in the queue entry */
|
|
|
|
sigact->signo = (uint8_t)signo;
|
|
|
|
/* Add the new sigaction to signal action queue */
|
|
|
|
sq_addlast((FAR sq_entry_t *)sigact, &group->tg_sigactionq);
|
|
}
|
|
|
|
/* Set the new sigaction */
|
|
|
|
sigact->act.sa_handler = handler;
|
|
sigact->act.sa_mask = act->sa_mask;
|
|
sigact->act.sa_flags = act->sa_flags;
|
|
}
|
|
|
|
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
|
|
*
|
|
* Description:
|
|
* Deallocate a sigaction Q entry
|
|
*
|
|
****************************************************************************/
|
|
|
|
void nxsig_release_action(FAR sigactq_t *sigact)
|
|
{
|
|
/* Just put it back on the free list */
|
|
|
|
sq_addlast((FAR sq_entry_t *)sigact, &g_sigfreeaction);
|
|
}
|