/****************************************************************************
 * include/nuttx/signal.h
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

#ifndef __INCLUDE_NUTTX_SIGNAL_H
#define __INCLUDE_NUTTX_SIGNAL_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdbool.h>
#include <signal.h>

#include <nuttx/wqueue.h>
#include <nuttx/sched.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#ifdef CONFIG_SIG_EVTHREAD
  #define sigwork_init(work) memset(work, 0, sizeof(*work));
#else
  #define sigwork_init(work) (void)(work)
#endif

/* Internal signal set definitions */

#define _NO_SIGNALS     ((uint32_t)0x00000000)
#define _ALL_SIGNALS    ((uint32_t)0xffffffff)
#define _SIGSET_NDX(s)  ((s) >> 5)    /* Get array index from signal number */
#define _SIGSET_BIT(s)  ((s) & 0x1f)  /* Get bit number from signal number */
#define _SIGNO2SET(s)   ((uint32_t)1 << _SIGSET_BIT(s))

/* Helper macros for printing signal sets. */

#define SIGSET_FMT     "%08" PRIx32 "%08" PRIx32
#define SIGSET_ELEM(s) (s)->_elem[1], (s)->_elem[0]

/****************************************************************************
 * Public Type Definitions
 ****************************************************************************/

struct sigwork_s
{
  struct work_s work;           /* Work queue structure */
  union sigval value;           /* Data passed with notification */
  sigev_notify_function_t func; /* Notification function */
};

#ifdef __cplusplus
extern "C"
{
#endif

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/* Most internal nxsig_* interfaces are not available in the user space in
 * PROTECTED and KERNEL builds.  In that context, the application signal
 * interfaces must be used.  The differences between the two sets of
 * interfaces are:  (1) the nxsig_* interfaces do not cause cancellation
 * points and (2) they do not modify the errno variable.
 *
 * This is only important when compiling libraries (libc or libnx) that are
 * used both by the OS (libkc.a and libknx.a) or by the applications
 * (libc.a and libnx.a).  In that case, the correct interface must be
 * used for the build context.
 *
 * REVISIT:  In the flat build, the same functions must be used both by
 * the OS and by applications.  We have to use the normal user functions
 * in this case or we will fail to set the errno or fail to create the
 * cancellation point.
 *
 * The interfaces sigtimedwait(), sigwait(), sigwaitinfo(), sleep(),
 * nanosleep(), and usleep()  are cancellation points.
 *
 * REVISIT:  The fact that these interfaces are cancellation points is an
 * issue and may cause violations:  It use of these internally will cause
 * the calling function to become a cancellation points!
 */

#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__)
#  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_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

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

struct timespec;  /* Forward reference */

/****************************************************************************
 * Name: nxsig_ismember
 *
 * Description:
 *   This function tests whether the signal specified by signo is a member
 *   of the set specified by set.
 *
 * Input Parameters:
 *   set - Signal set to test
 *   signo - Signal to test for
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   On success, it returns 0 if the signal is not a member, 1 if the signal
 *   is a member of the set.
 *   A negated errno value is returned on failure.
 *
 *    EINVAL - The signo argument is invalid.
 *
 * Assumptions:
 *
 ****************************************************************************/

int nxsig_ismember(FAR const sigset_t *set, int signo);

/****************************************************************************
 * Name: nxsig_addset
 *
 * Description:
 *   This function adds the signal specified by signo to the signal set
 *   specified by set.
 *
 * Input Parameters:
 *   set - Signal set to add signal to
 *   signo - Signal to add
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 *    EINVAL - The signo argument is invalid.
 *
 * Assumptions:
 *
 ****************************************************************************/

int nxsig_addset(FAR sigset_t *set, int signo);

/****************************************************************************
 * Name: nxsig_delset
 *
 * Description:
 *   This function deletes the signal specified by signo from the signal
 *   set specified by the 'set' argument.
 *
 * Input Parameters:
 *   set   - Signal set to delete the signal from
 *   signo - Signal to delete
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 *    EINVAL - The signo argument is invalid.
 *
 * Assumptions:
 *
 ****************************************************************************/

int nxsig_delset(FAR sigset_t *set, int signo);

/****************************************************************************
 * Name: nxsig_nandset
 *
 * Description:
 *   This function returns the intersection of the left set and the
 *   complement of the right set in dest.
 *
 * Input Parameters:
 *   dest  - The location to store the result
 *   left  - The uncomplemented set used in the intersection
 *   right - The set that will be complemented and used in the intersection
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 * Assumptions:
 *
 ****************************************************************************/

int nxsig_nandset(FAR sigset_t *dest, FAR const sigset_t *left,
                  FAR const sigset_t *right);

/****************************************************************************
 * Name: nxsig_xorset
 *
 * Description:
 *   This function returns the xor of right and left in dest.
 *
 * Input Parameters:
 *   dest        - Location to return the union
 *   left, right - The two sets to use in the union
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 *     0 on success or -1 on failure
 *
 * Assumptions:
 *
 ****************************************************************************/

int nxsig_xorset(FAR sigset_t *dest, FAR const sigset_t *left,
                 FAR const sigset_t *right);

/****************************************************************************
 * Name: nxsig_pendingset
 *
 * Description:
 *   Convert the list of pending signals into a signal set
 *
 * Input Parameters:
 *   stcb - The specific tcb of return pending set.
 *
 * Returned Value:
 *   Return the pending signal set.
 *
 * Assumptions:
 *
 ****************************************************************************/

sigset_t nxsig_pendingset(FAR struct tcb_s *stcb);

/****************************************************************************
 * Name: nxsig_procmask
 *
 * Description:
 *   This function allows the calling process to examine and/or change its
 *   signal mask.  If the 'set' is not NULL, then it points to a set of
 *   signals to be used to change the currently blocked set.  The value of
 *   'how' indicates the manner in which the set is changed.
 *
 *   If there any pending unblocked signals after the call to
 *   nxsig_procmask(), those signals will be delivered before
 *    nxsig_procmask() returns.
 *
 *   If nxsig_procmask() fails, the signal mask of the process is not changed
 *   by this function call.
 *
 *   This is an internal OS interface.  It is functionally equivalent to
 *   sigprocmask() except that it does not modify the errno value.
 *
 * Input Parameters:
 *   how - How the signal mask will be changed:
 *         SIG_BLOCK   - The resulting set is the union of the current set
 *                       and the signal set pointed to by 'set'.
 *         SIG_UNBLOCK - The resulting set is the intersection of the current
 *                       set and the complement of the signal set pointed to
 *                       by 'set'.
 *         SIG_SETMASK - The resulting set is the signal set pointed to by
 *                       'set'.
 *   set  - Location of the new signal mask
 *   oset - Location to store the old signal mask
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 *    EINVAL - The 'how' argument is invalid.
 *
 ****************************************************************************/

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
 *
 * Description:
 *   This function sends the signal specified by signo with the signal
 *   parameter value to the process specified by pid.
 *
 *   If the receiving process has the signal blocked via the sigprocmask,
 *   the signal will pend until it is unmasked. Only one pending signal (per
 *   signo) is retained.  This is consistent with POSIX which states, "If
 *   a subsequent occurrence of a pending signal is generated, it is
 *   implementation defined as to whether the signal is delivered more than
 *   once.
 *
 *   This is an internal OS interface.  It is functionally equivalent to
 *   sigqueue() except that it does not modify the errno value.
 *
 * Input Parameters:
 *   pid   - Process ID of task to receive signal
 *   signo - Signal number
 *   value - Value to pass to task with signal
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 *    EGAIN  - The limit of signals which may be queued has been reached.
 *    EINVAL - sig was invalid.
 *    EPERM  - The  process  does  not  have  permission to send the
 *             signal to the receiving process.
 *    ESRCH  - No process has a PID matching pid.
 *
 ****************************************************************************/

int nxsig_queue(int pid, int signo, union sigval value);

/****************************************************************************
 * Name: nxsig_kill
 *
 * Description:
 *   The nxsig_kill() system call can be used to send any signal to any task.
 *
 *   This is an internal OS interface.  It is functionally equivalent to
 *   the POSIX standard kill() function but does not modify the application
 *   errno variable.
 *
 *   Limitation: Sending of signals to 'process groups' is not
 *   supported in NuttX
 *
 * Input Parameters:
 *   pid - The id of the task to receive the signal.  The POSIX nxsig_kill
 *     specification encodes process group information as zero and
 *     negative pid values.  Only positive, non-zero values of pid are
 *     supported by this implementation.
 *   signo - The signal number to send.  If signo is zero, no signal is
 *     sent, but all error checking is performed.
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 *    EINVAL An invalid signal was specified.
 *    EPERM  The process does not have permission to send the
 *           signal to any of the target processes.
 *    ESRCH  The pid or process group does not exist.
 *    ENOSYS Do not support sending signals to process groups.
 *
 ****************************************************************************/

int nxsig_kill(pid_t pid, int signo);

/****************************************************************************
 * Name: nxsig_tgkill
 *
 * Description:
 *   The tgkill() system call can be used to send any signal to a thread.
 *   See kill() for further information as this is just a simple wrapper
 *   around the kill() function.
 *
 * Input Parameters:
 *   gid   - The id of the task to receive the signal.
 *   tid   - The id of the thread to receive the signal. Only positive,
 *           non-zero values of 'tid' are supported.
 *   signo - The signal number to send.  If 'signo' is zero, no signal is
 *           sent, but all error checking is performed.
 *
 * Returned Value:
 *    On success the signal was send and zero is returned. On error -1 is
 *    returned, and errno is set one of the following error numbers:
 *
 *    EINVAL An invalid signal was specified.
 *    EPERM  The thread does not have permission to send the
 *           signal to the target thread.
 *    ESRCH  No thread could be found corresponding to that
 *           specified by the given thread ID
 *    ENOSYS Do not support sending signals to process groups.
 *
 ****************************************************************************/

int nxsig_tgkill(pid_t pid, pid_t tid, int signo);

/****************************************************************************
 * Name: nxsig_clockwait
 *
 * Description:
 *   This function selects the pending signal set specified by the argument
 *   set.  If multiple signals are pending in set, it will remove and return
 *   the lowest numbered one.  If no signals in set are pending at the time
 *   of the call, the calling process will be suspended until one of the
 *   signals in set becomes pending, OR until the process is interrupted by
 *   an unblocked signal, OR until the time interval specified by timeout
 *   (if any), has expired. If timeout is NULL, then the timeout interval
 *   is forever.
 *
 *   If the info argument is non-NULL, the selected signal number is stored
 *   in the si_signo member and the cause of the signal is stored in the
 *   si_code member.  The content of si_value is only meaningful if the
 *   signal was generated by sigqueue() (or nxsig_queue).
 *
 *   This is an internal OS interface.  It is functionally equivalent to
 *   sigtimedwait() except that:
 *
 *   - It is not a cancellation point, and
 *   - It does not modify the errno value.
 *
 * Input Parameters:
 *   clockid - The ID of the clock to be used to measure the timeout.
 *   flags   - Open flags.  TIMER_ABSTIME  is the only supported flag.
 *   rqtp - The amount of time to be suspended from execution.
 *   rmtp - If the rmtp argument is non-NULL, the timespec structure
 *          referenced by it is updated to contain the amount of time
 *          remaining in the interval (the requested time minus the time
 *          actually slept)
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   A negated errno value is returned on failure.
 *
 *   EAGAIN - wait time is zero.
 *   EINTR  - The wait was interrupted by an unblocked, caught signal.
 *
 * Notes:
 *  This function should be called with critical section set.
 *
 ****************************************************************************/

int nxsig_clockwait(int clockid, int flags,
                    FAR const struct timespec *rqtp,
                    FAR struct timespec *rmtp);

/****************************************************************************
 * Name: nxsig_timedwait
 *
 * Description:
 *   This function selects the pending signal set specified by the argument
 *   set.  If multiple signals are pending in set, it will remove and return
 *   the lowest numbered one.  If no signals in set are pending at the time
 *   of the call, the calling process will be suspended until one of the
 *   signals in set becomes pending, OR until the process is interrupted by
 *   an unblocked signal, OR until the time interval specified by timeout
 *   (if any), has expired. If timeout is NULL, then the timeout interval
 *   is forever.
 *
 *   If the info argument is non-NULL, the selected signal number is stored
 *   in the si_signo member and the cause of the signal is stored in the
 *   si_code member.  The content of si_value is only meaningful if the
 *   signal was generated by sigqueue().
 *
 *   This is an internal OS interface.  It is functionally equivalent to
 *   sigtimedwait() except that:
 *
 *   - It is not a cancellation point, and
 *   - It does not modify the errno value.
 *
 * Input Parameters:
 *   set     - The pending signal set.
 *   info    - The returned value (may be NULL).
 *   timeout - The amount of time to wait (may be NULL)
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 *   EAGAIN - No signal specified by set was generated within the specified
 *            timeout period.
 *   EINTR  - The wait was interrupted by an unblocked, caught signal.
 *
 ****************************************************************************/

int nxsig_timedwait(FAR const sigset_t *set, FAR struct siginfo *info,
                    FAR const struct timespec *timeout);

/****************************************************************************
 * Name: nxsig_nanosleep
 *
 * Description:
 *   The nxsig_nanosleep() function causes the current thread to be
 *   suspended from execution until either the time interval specified by
 *   the rqtp argument has elapsed or a signal is delivered to the calling
 *   thread and its action is to invoke a signal-catching function or to
 *   terminate the process. The suspension time may be longer than requested
 *   because the argument value is rounded up to an integer multiple of the
 *   sleep resolution or because of the scheduling of other activity by the
 *   system. But, except for the case of being interrupted by a signal, the
 *   suspension time will not be less than the time specified by rqtp, as
 *   measured by the system clock, CLOCK_REALTIME.
 *
 *   The use of the nxsig_nanosleep() function has no effect on the action
 *   or blockage of any signal.
 *
 * Input Parameters:
 *   rqtp - The amount of time to be suspended from execution.
 *   rmtp - If the rmtp argument is non-NULL, the timespec structure
 *          referenced by it is updated to contain the amount of time
 *          remaining in the interval (the requested time minus the time
 *          actually slept)
 *
 * Returned Value:
 *   If the nxsig_nanosleep() function returns because the requested time
 *   has elapsed, its return value is zero.
 *
 *   If the nxsig_nanosleep() function returns because it has been
 *   interrupted by a signal, the function returns a negated errno value
 *   indicate the interruption. If the rmtp argument is non-NULL, the
 *   timespec structure referenced by it is updated to contain the amount
 *   of time remaining in the interval (the requested time minus the time
 *   actually slept). If the rmtp argument is NULL, the remaining time is
 *   not returned.
 *
 *   If nxsig_nanosleep() fails, it returns a negated errno indicating the
 *   cause of the failure. The nxsig_nanosleep() function will fail if:
 *
 *     EINTR - The nxsig_nanosleep() function was interrupted by a signal.
 *     EINVAL - The rqtp argument specified a nanosecond value less than
 *       zero or greater than or equal to 1000 million.
 *     ENOSYS - The nxsig_nanosleep() function is not supported by this
 *       implementation.
 *
 ****************************************************************************/

int nxsig_nanosleep(FAR const struct timespec *rqtp,
                    FAR struct timespec *rmtp);

/****************************************************************************
 * Name: nxsig_sleep
 *
 * Description:
 *   The nxsig_sleep() function will cause the calling thread to be
 *   suspended from execution until either the number of real-time seconds
 *   specified by the argument 'seconds' has elapsed or a signal is
 *   delivered to the calling thread.
 *
 *   This is an internal OS interface.  It is functionally equivalent to
 *   the standard sleep() application interface except that:
 *
 *   - It is not a cancellation point, and
 *   - There is no check that the action of the signal is to invoke a
 *     signal-catching function or to terminate the process.
 *
 *   See the description of sleep() for additional information that is not
 *   duplicated here.
 *
 * Input Parameters:
 *   seconds - The number of seconds to sleep
 *
 * Returned Value:
 *   If nxsig_sleep() returns because the requested time has elapsed, the
 *   value returned will be zero (OK). If nxsig_sleep() returns because of
 *   premature arousal due to delivery of a signal, the return value will
 *   be the "unslept" amount (the requested time minus the time actually
 *   slept) in seconds.
 *
 ****************************************************************************/

unsigned int nxsig_sleep(unsigned int seconds);

/****************************************************************************
 * Name: nxsig_usleep
 *
 * Description:
 *   The nxsig_usleep() function will cause the calling thread to be
 *   suspended from execution until either the number of real-time
 *   microseconds specified by the argument 'usec' has elapsed or a signal
 *   is delivered to the calling thread. The suspension time may be longer
 *   than requested due to the scheduling of other activity by the system.
 *
 *   This is an internal OS interface.  It is functionally equivalent to
 *   the standard nxsig_usleep() application interface except that:
 *
 *   - It is not a cancellation point, and
 *   - It does not modify the errno value.
 *
 *   See the description of usleep() for additional information that is not
 *   duplicated here.
 *
 * Input Parameters:
 *   usec - the number of microseconds to wait.
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 ****************************************************************************/

int nxsig_usleep(useconds_t usec);

/****************************************************************************
 * Name: nxsig_notification
 *
 * Description:
 *   Notify a client an event via either a signal or a function call
 *   base on the sigev_notify field.
 *
 * Input Parameters:
 *   pid   - The task/thread ID a the client thread to be signaled.
 *   event - The instance of struct sigevent that describes how to signal
 *           the client.
 *   code  - Source: SI_USER, SI_QUEUE, SI_TIMER, SI_ASYNCIO, or SI_MESGQ
 *   work  - The work structure to queue.  Must be non-NULL if
 *           event->sigev_notify == SIGEV_THREAD.  Ignored if
 *           CONFIG_SIG_EVTHREAD is not defined.
 *
 * Returned Value:
 *   This is an internal OS interface and should not be used by applications.
 *   It follows the NuttX internal error return policy:  Zero (OK) is
 *   returned on success.  A negated errno value is returned on failure.
 *
 ****************************************************************************/

int nxsig_notification(pid_t pid, FAR struct sigevent *event,
                       int code, FAR struct sigwork_s *work);

/****************************************************************************
 * Name: nxsig_cancel_notification
 *
 * Description:
 *   Cancel the notification if it doesn't send yet.
 *
 * Input Parameters:
 *   work  - The work structure to cancel
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

#ifdef CONFIG_SIG_EVTHREAD
void nxsig_cancel_notification(FAR struct sigwork_s *work);
#else
#  define nxsig_cancel_notification(work)
#endif

#ifdef __cplusplus
}
#endif

#endif /* __INCLUDE_NUTTX_SIGNAL_H */
