summaryrefslogtreecommitdiffstats
path: root/nuttx/sched/sig_timedwait.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/sched/sig_timedwait.c')
-rw-r--r--nuttx/sched/sig_timedwait.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/nuttx/sched/sig_timedwait.c b/nuttx/sched/sig_timedwait.c
new file mode 100644
index 0000000000..842f68c2fb
--- /dev/null
+++ b/nuttx/sched/sig_timedwait.c
@@ -0,0 +1,267 @@
+/************************************************************
+ * sig_timedwait.c
+ *
+ * Copyright (C) 2007 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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 Gregory Nutt 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 <sys/types.h>
+#include <signal.h>
+#include <time.h>
+#include <wdog.h>
+#include <assert.h>
+#include <debug.h>
+#include <sched.h>
+#include <nuttx/arch.h>
+#include "os_internal.h"
+#include "sig_internal.h"
+#include "clock_internal.h"
+
+/************************************************************
+ * Definitions
+ ************************************************************/
+
+/************************************************************
+ * Private Type Declarations
+ ************************************************************/
+
+/************************************************************
+ * Global Variables
+ ************************************************************/
+
+/************************************************************
+ * Private Variables
+ ************************************************************/
+
+/************************************************************
+ * Private Functionss
+ ************************************************************/
+
+/************************************************************
+ * Function: sig_timeout
+ *
+ * Description:
+ * A timeout elapsed while waiting for signals to be queued.
+ ************************************************************/
+
+static void sig_timeout(int itcb, int parm2, int parm3, int parm4)
+{
+ _TCB *wtcb = (_TCB*)itcb;
+
+ if (!wtcb)
+ {
+ PANIC(OSERR_TIMEOUTNOTCB);
+ }
+
+ /* There may be a race condition -- make sure the task is
+ * still waiting for a signal
+ */
+
+ if (wtcb->task_state == TSTATE_WAIT_SIG)
+ {
+ wtcb->sigunbinfo.si_signo = ERROR;
+ wtcb->sigunbinfo.si_code = SI_TIMEOUT;
+ wtcb->sigunbinfo.si_value.sival_int = 0;
+ up_unblock_task(wtcb);
+ }
+}
+
+/************************************************************
+ * Public Functions
+ ************************************************************/
+
+/************************************************************
+ * Function: sigtimedwait
+ *
+ * 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 store in the si_code emember. The
+ * content of si_value is only meaningful if the signal was
+ * generated by sigqueue().
+ *
+ * The following values for si_code are defined in signal.h:
+ * SI_QUEUE - Signal sent from sigqueue
+ * SI_MESGQ - Signal generated by arrival of a message on an
+ * empty message queue
+ * SI_NOWAIT - Signal already pending -- don't know how sent
+ * SI_TIMEOUT - No Signal, restarted by timeout
+ *
+ * Parameters:
+ * set - The pending signal set.
+ * info - The returned value
+ * timeout - The amount of time to wait
+ *
+ * Return Value:
+ * Signal number that cause the wait to be terminated, otherwise
+ * -1 (ERROR) is returned.
+ *
+ * Assumptions:
+ *
+ ************************************************************/
+
+int sigtimedwait(const sigset_t *set, struct siginfo *info,
+ const struct timespec *timeout)
+{
+ _TCB *rtcb = (_TCB*)g_readytorun.head;
+ sigset_t intersection;
+ sigpendq_t *sigpend;
+ WDOG_ID wdog;
+ uint32 saved_state;
+ sint32 waitticks;
+ int ret = ERROR;
+
+ sched_lock(); /* Not necessary */
+
+ /* Several operations must be performed below: We must determine if any
+ * signal is pending and, if not, wait for the signal. Since signals can
+ * be posted from the interrupt level, there is a race condition that
+ * can only be eliminated by disabling interrupts!
+ */
+
+ saved_state = irqsave();
+
+ /* Check if there is a pending signal corresponding to one of the
+ * signals in the pending signal set argument.
+ */
+
+ intersection = *set & sig_pendingset(rtcb);
+ if (intersection != NULL_SIGNAL_SET)
+ {
+ /* One or more of the signals in intersections is sufficient to cause
+ * us to not wait. Pick the lowest numbered signal and mark it not
+ * pending.
+ */
+
+ sigpend = sig_removependingsignal(rtcb, sig_lowest(&intersection));
+ if (!sigpend)
+ {
+ PANIC(OSERR_NOPENDINGSIGNAL);
+ }
+
+ /* Return the signal info to the caller if so requested */
+
+ if (info) *info = sigpend->info;
+
+ /* Then dispose of the pending signal structure properly */
+
+ sig_releasependingsignal(sigpend);
+ irqrestore(saved_state);
+
+ /* The return value is the number of the signal that awakened us */
+
+ ret = info->si_signo;
+ }
+
+ /* We will have to wait for a signal to be posted to this task. */
+
+ else
+ {
+ /* Save the set of pending signals to wait for */
+
+ rtcb->sigwaitmask = *set;
+
+ /* Check if we should wait for the timeout */
+
+ if (timeout)
+ {
+ /* Convert the timespec to milliseconds */
+
+ waitticks = MSEC2TICK(timeout->tv_sec * MSEC_PER_SEC
+ + timeout->tv_nsec / NSEC_PER_MSEC);
+
+ /* Create a watchdog */
+
+ wdog = wd_create();
+ if (wdog)
+ {
+ /* Start the watchdog */
+
+ wd_start(wdog, waitticks, (wdentry_t)sig_timeout,
+ (int)rtcb, 0, 0, 0);
+
+ /* Now wait for either the signal or the watchdog */
+
+ up_block_task(rtcb, TSTATE_WAIT_SIG);
+
+ /* We no longer need the watchdog */
+
+ wd_delete(wdog);
+ }
+ }
+
+ /* No timeout, just wait */
+
+ else
+ {
+ /* And wait until one of the unblocked signals is posted */
+
+ up_block_task(rtcb, TSTATE_WAIT_SIG);
+ }
+
+ /* We are running again, clear the sigwaitmask */
+
+ rtcb->sigwaitmask = NULL_SIGNAL_SET;
+
+ /* When we awaken, the cause will be in the TCB. Return the signal
+ * info to the caller if so requested
+ */
+
+ if (info)
+ {
+ *info = rtcb->sigunbinfo;
+ }
+ irqrestore(saved_state);
+
+ /* The return value is the number of the signal that awakened us */
+
+ ret = info->si_signo;
+ }
+ sched_unlock();
+
+ return ret;
+}
+