aboutsummaryrefslogtreecommitdiff
path: root/nuttx/sched
diff options
context:
space:
mode:
authorpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-05-30 15:36:46 +0000
committerpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-05-30 15:36:46 +0000
commit81c4bcb9b5b6d40a0d7aebf6c82e7497057fdfba (patch)
tree23c40db9c1c2047b74bd10c336a243270af01ffa /nuttx/sched
parente48bc996c40507d87bda9eb3426b68882d7985b8 (diff)
downloadpx4-firmware-81c4bcb9b5b6d40a0d7aebf6c82e7497057fdfba.tar.gz
px4-firmware-81c4bcb9b5b6d40a0d7aebf6c82e7497057fdfba.tar.bz2
px4-firmware-81c4bcb9b5b6d40a0d7aebf6c82e7497057fdfba.zip
Fix return values from sleep(), usleep(), and sigtimedwait(). Fix STM32 F2 I2C bug-for-bug compatibility
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4786 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx/sched')
-rw-r--r--nuttx/sched/sig_timedwait.c64
-rw-r--r--nuttx/sched/sleep.c110
-rw-r--r--nuttx/sched/usleep.c86
3 files changed, 231 insertions, 29 deletions
diff --git a/nuttx/sched/sig_timedwait.c b/nuttx/sched/sig_timedwait.c
index 2d9afaab1..c0b4d802a 100644
--- a/nuttx/sched/sig_timedwait.c
+++ b/nuttx/sched/sig_timedwait.c
@@ -1,8 +1,8 @@
/****************************************************************************
* sched/sig_timedwait.c
*
- * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ * Copyright (C) 2007-2009, 2012 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
@@ -47,15 +47,24 @@
#include <assert.h>
#include <debug.h>
#include <sched.h>
+#include <errno.h>
+
#include <nuttx/arch.h>
+
#include "os_internal.h"
#include "sig_internal.h"
#include "clock_internal.h"
/****************************************************************************
- * Definitions
+ * Pre-processor Definitions
****************************************************************************/
+/* This is a special value of si_signo that means that it was the timeout
+ * that awakened the wait... not the receipt of a signal.
+ */
+
+#define SIG_WAIT_TIMEOUT 0xff
+
/****************************************************************************
* Private Type Declarations
****************************************************************************/
@@ -107,7 +116,7 @@ static void sig_timeout(int argc, uint32_t itcb)
if (u.wtcb->task_state == TSTATE_WAIT_SIG)
{
- u.wtcb->sigunbinfo.si_signo = ERROR;
+ u.wtcb->sigunbinfo.si_signo = SIG_WAIT_TIMEOUT;
u.wtcb->sigunbinfo.si_code = SI_TIMER;
u.wtcb->sigunbinfo.si_value.sival_int = 0;
up_unblock_task(u.wtcb);
@@ -151,7 +160,11 @@ static void sig_timeout(int argc, uint32_t itcb)
*
* Return Value:
* Signal number that cause the wait to be terminated, otherwise -1 (ERROR)
- * is returned.
+ * is returned with errno set to either:
+ *
+ * EAGAIN - No signal specified by set was generated within the specified
+ * timeout period.
+ * EINTR - The wait was interrupted by an unblocked, caught signal.
*
* Assumptions:
*
@@ -270,23 +283,48 @@ int sigtimedwait(FAR const sigset_t *set, FAR struct siginfo *info,
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
+ /* When we awaken, the cause will be in the TCB. Get the signal number
+ * or timeout) that awakened us.
*/
- if (info)
+ if (GOOD_SIGNO(rtcb->sigunbinfo.si_signo))
{
- memcpy(info, &rtcb->sigunbinfo, sizeof(struct siginfo));
+ /* We were awakened by a signal... but is it one of the signals that
+ * we were waiting for?
+ */
+
+ if (sigismember(set, rtcb->sigunbinfo.si_signo))
+ {
+ /* Yes.. the return value is the number of the signal that
+ * awakened us.
+ */
- /* The return value is the number of the signal that awakened us */
+ ret = rtcb->sigunbinfo.si_signo;
+ }
+ else
+ {
+ /* No... then set EINTR and report an error */
- ret = info->si_signo;
+ set_errno(EINTR);
+ ret = ERROR;
+ }
}
else
{
- /* We don't know which signal awakened us. This is probably a bug. */
+ /* Otherwise, we must have been awakened by the timeout. Set EGAIN
+ * and return an error.
+ */
- ret = 0;
+ DEBUGASSERT(rtcb->sigunbinfo.si_signo == SIG_WAIT_TIMEOUT);
+ set_errno(EAGAIN);
+ ret = ERROR;
+ }
+
+ /* Return the signal info to the caller if so requested */
+
+ if (info)
+ {
+ memcpy(info, &rtcb->sigunbinfo, sizeof(struct siginfo));
}
irqrestore(saved_state);
}
diff --git a/nuttx/sched/sleep.c b/nuttx/sched/sleep.c
index bf586acd9..7df922c61 100644
--- a/nuttx/sched/sleep.c
+++ b/nuttx/sched/sleep.c
@@ -1,8 +1,8 @@
/****************************************************************************
* sched/sleep.c
*
- * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ * Copyright (C) 2007, 2009, 2012 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
@@ -42,6 +42,9 @@
#include <unistd.h>
#include <signal.h>
+#include <nuttx/clock.h>
+#include <arch/irq.h>
+
/****************************************************************************
* Preprocessor Definitions
****************************************************************************/
@@ -70,15 +73,54 @@
* Function: sleep
*
* Description:
- * As typically declared in unistd.h. sleep() is a simple application of
- * sigtimedwait.
+ * The 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 and its action is to invoke a signal-catching function or to
+ * terminate the process. The suspension time may be longer than requested
+ * due to the scheduling of other activity by the system.
+ *
+ * If a SIGALRM signal is generated for the calling process during
+ * execution of sleep() and if the SIGALRM signal is being ignored or
+ * blocked from delivery, it is unspecified whether sleep() returns
+ * when the SIGALRM signal is scheduled. If the signal is being blocked, it
+ * is also unspecified whether it remains pending after sleep() returns or
+ * it is discarded.
+ *
+ * If a SIGALRM signal is generated for the calling process during
+ * execution of sleep(), except as a result of a prior call to alarm(),
+ * and if the SIGALRM signal is not being ignored or blocked from delivery,
+ * it is unspecified whether that signal has any effect other than causing
+ * sleep() to return.
+ *
+ * If a signal-catching function interrupts sleep() and examines or changes
+ * either the time a SIGALRM is scheduled to be generated, the action
+ * associated with the SIGALRM signal, or whether the SIGALRM signal is
+ * blocked from delivery, the results are unspecified.
+ *
+ * If a signal-catching function interrupts sleep() and calls siglongjmp()
+ * or longjmp() to restore an environment saved prior to the sleep() call,
+ * the action associated with the SIGALRM signal and the time at which a
+ * SIGALRM signal is scheduled to be generated are unspecified. It is also
+ * unspecified whether the SIGALRM signal is blocked, unless the process'
+ * signal mask is restored as part of the environment.
+ *
+ * Implementations may place limitations on the granularity of timer values.
+ * For each interval timer, if the requested timer value requires a finer
+ * granularity than the implementation supports, the actual timer value will
+ * be rounded up to the next supported value.
+ *
+ * Interactions between sleep() and any of setitimer(), ualarm() or sleep()
+ * are unspecified.
*
* Parameters:
* seconds
*
* Returned Value:
- * Zero if the requested time has elapsed, or the number of seconds left
- * to sleep.
+ * If sleep() returns because the requested time has elapsed, the value
+ * returned will be 0. If 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.
*
* Assumptions:
*
@@ -89,14 +131,66 @@ unsigned int sleep(unsigned int seconds)
sigset_t set;
struct timespec ts;
struct siginfo value;
+ irqstate_t flags;
+ uint32_t start;
+ int32_t elapsed;
+ int32_t remaining = 0;
+
+ /* Don't sleep if seconds == 0 */
if (seconds)
{
+ /* Set up for the sleep. Using the empty set means that we are not
+ * waiting for any particualar signal. However, any unmasked signal
+ * can still awaken sigtimedwait().
+ */
+
(void)sigemptyset(&set);
- ts.tv_sec = seconds;
+ ts.tv_sec = seconds;
ts.tv_nsec = 0;
+
+ /* Interrupts are disabled around the following so that it is atomic */
+
+ flags = irqsave();
+
+ /* Get the current time then sleep for the requested time.
+ * sigtimedwait() cannot succeed. It should always return error with
+ * either (1) EAGAIN meaning that the timeout occurred, or (2) EINTR
+ * meaning that some other unblocked signal was caught.
+ */
+
+ start = clock_systimer();
(void)sigtimedwait(&set, &value, &ts);
+
+ /* Calculate the elapsed time (in clock ticks) when we wake up from the sleep.
+ * This is really only necessary if we were awakened from the sleep early
+ * due to the receipt of a signal.
+ */
+
+ elapsed = clock_systimer() - start;
+ irqrestore(flags);
+
+ /* Get the remaining, un-waited seconds. Note that this calculation
+ * truncates the elapsed seconds in the division. We may have slept some
+ * fraction of a second longer than this! But if the calculation is less
+ * than the 'seconds', we certainly did not sleep for the complete
+ * requested interval.
+ */
+
+ remaining = (int32_t)seconds - elapsed / TICK_PER_SEC;
+
+ /* Make sure that the elapsed time is non-negative (this should always
+ * be the case unless something exceptional happened while were we
+ * sleeping -- like the clock was reset or we went into a low power mode,
+ * OR if we had to wait a long time to run again after calling
+ * sigtimedwait() making 'elapsed' bigger than it should have been).
+ */
+
+ if (remaining < 0)
+ {
+ remaining = 0;
+ }
}
- return 0;
+ return (unsigned int)remaining;
}
diff --git a/nuttx/sched/usleep.c b/nuttx/sched/usleep.c
index 2751628eb..ba2c072c4 100644
--- a/nuttx/sched/usleep.c
+++ b/nuttx/sched/usleep.c
@@ -1,8 +1,8 @@
/****************************************************************************
* sched/usleep.c
*
- * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ * Copyright (C) 2007, 2009, 2012 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
@@ -40,6 +40,8 @@
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
+#include <assert.h>
+#include <errno.h>
/****************************************************************************
* Definitions
@@ -69,30 +71,98 @@
* Function: usleep
*
* Description:
- * BSD version as typically declared in unistd.h. usleep() is a simple
- * application of sigtimedwait.
+ * The 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.
*
+ * The 'usec' argument must be less than 1,000,000. If the value of
+ * 'usec' is 0, then the call has no effect.
+ *
+ * If a SIGALRM signal is generated for the calling process during
+ * execution of usleep() and if the SIGALRM signal is being ignored or
+ * blocked from delivery, it is unspecified whether usleep() returns
+ * when the SIGALRM signal is scheduled. If the signal is being blocked, it
+ * is also unspecified whether it remains pending after usleep() returns or
+ * it is discarded.
+ *
+ * If a SIGALRM signal is generated for the calling process during
+ * execution of usleep(), except as a result of a prior call to alarm(),
+ * and if the SIGALRM signal is not being ignored or blocked from delivery,
+ * it is unspecified whether that signal has any effect other than causing
+ * usleep() to return.
+ *
+ * If a signal-catching function interrupts usleep() and examines or changes
+ * either the time a SIGALRM is scheduled to be generated, the action
+ * associated with the SIGALRM signal, or whether the SIGALRM signal is
+ * blocked from delivery, the results are unspecified.
+ *
+ * If a signal-catching function interrupts usleep() and calls siglongjmp()
+ * or longjmp() to restore an environment saved prior to the usleep() call,
+ * the action associated with the SIGALRM signal and the time at which a
+ * SIGALRM signal is scheduled to be generated are unspecified. It is also
+ * unspecified whether the SIGALRM signal is blocked, unless the process'
+ * signal mask is restored as part of the environment.
+ *
+ * Implementations may place limitations on the granularity of timer values.
+ * For each interval timer, if the requested timer value requires a finer
+ * granularity than the implementation supports, the actual timer value will
+ * be rounded up to the next supported value.
+ *
+ * Interactions between usleep() and any of the following are unspecified:
+ *
+ * nanosleep(), setitimer(), timer_create(), timer_delete(), timer_getoverrun(),
+ * timer_gettime(), timer_settime(), ualarm(), sleep()
+
* Parameters:
- * seconds
+ * usec - the number of microseconds to wait.
*
* Returned Value:
- * None
+ * On successful completion, usleep() returns 0. Otherwise, it returns -1
+ * and sets errno to indicate the error.
*
* Assumptions:
*
****************************************************************************/
-void usleep(useconds_t usec)
+int usleep(useconds_t usec)
{
sigset_t set;
struct timespec ts;
struct siginfo value;
+ int errval;
+ int ret = 0;
if (usec)
{
+ /* Set up for the sleep. Using the empty set means that we are not
+ * waiting for any particualar signal. However, any unmasked signal
+ * can still awaken sigtimedwait().
+ */
+
(void)sigemptyset(&set);
ts.tv_sec = usec / 1000000;
ts.tv_nsec = (usec % 1000000) * 1000;
- (void)sigtimedwait(&set, &value, &ts);
+
+ /* usleep is a simple application of sigtimedwait. */
+
+ ret = sigtimedwait(&set, &value, &ts);
+
+ /* sigtimedwait() cannot succeed. It should always return error with
+ * either (1) EAGAIN meaning that the timeout occurred, or (2) EINTR
+ * meaning that some other unblocked signal was caught.
+ */
+
+ errval = errno;
+ DEBUGASSERT(ret < 0 && (errval == EAGAIN || errval == EINTR));
+ if (errval == EAGAIN)
+ {
+ /* The timeout "error" is the normal, successful result */
+
+ ret = 0;
+ }
}
+
+ return ret;
}