From e3940eb2080711edac189cca3f642ee89dc215f2 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 17 Feb 2007 23:21:28 +0000 Subject: NuttX RTOS git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/sched/sig_timedwait.c | 267 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 nuttx/sched/sig_timedwait.c (limited to 'nuttx/sched/sig_timedwait.c') diff --git a/nuttx/sched/sig_timedwait.c b/nuttx/sched/sig_timedwait.c new file mode 100644 index 000000000..842f68c2f --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#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; +} + -- cgit v1.2.3