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
This commit is contained in:
patacongo 2012-05-30 15:36:46 +00:00
parent e48bc996c4
commit 81c4bcb9b5
6 changed files with 254 additions and 37 deletions

View File

@ -2833,5 +2833,20 @@
* stmpe11*: Fix a massive naming problem. All references to STMPE11 should be
STMPE812.
* arch/arm/src/stm32/stm32_otgfsdev.c: Need to enabled USB reset interrupt
(contricuted by Erik Van Der Zalm).
(contributed by Erik Van Der Zalm).
* sched/sleep.c: Fix the return value from sleep(). The correct behavior is
to return the number of unwaited seconds; the implementation was always
returning zero.
* sched/usleep.c and include/unistd.h: Was a void function, but should return
0 on success. usleep() needs to check the return value from sigtimedwait().
sigtimewait() returns the signal number that awakened it and an error (EAGAIN)
if the timeout expired (normal case).
* sched/sig_timedwait.c: Fix sigtimedwait() return value. On a timeout, it was
setting the 8-bit si_signo field to -1 and eded up reported successfully awakened
by signal 255! Now detects the timeout and errors -1 with errno == EGAIN. If
sigtimedwait() is awakened by an unblocked signal, but it is not one of the
signals in the waited-for set, it will return -1 with errno == EINTR.
* arch/arm/src/stm32_i2c.c: Fix STM32 F2 I2C. It is apparently bug-for-bug
compatible with the F4 and needs the same work-around for the missing BTF
signal that was needed for the F4.

View File

@ -1125,11 +1125,11 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
}
#endif
/* Was last byte received or sent? Hmmm... the F4 seems to differ from
/* Was last byte received or sent? Hmmm... the F2 and F4 seems to differ from
* the F1 in that BTF is not set after data is received (only RXNE).
*/
#ifdef CONFIG_STM32_STM32F40XX
#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
if (priv->dcnt <= 0 && (status & (I2C_SR1_BTF|I2C_SR1_RXNE)) != 0)
#else
if (priv->dcnt <= 0 && (status & I2C_SR1_BTF) != 0)

View File

@ -132,7 +132,7 @@ EXTERN int optopt; /* unrecognized option character */
EXTERN pid_t getpid(void);
EXTERN void _exit(int status) noreturn_function;
EXTERN unsigned int sleep(unsigned int seconds);
EXTERN void usleep(useconds_t usec);
EXTERN int usleep(useconds_t usec);
/* File descriptor operations */

View File

@ -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 (GOOD_SIGNO(rtcb->sigunbinfo.si_signo))
{
/* 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.
*/
ret = rtcb->sigunbinfo.si_signo;
}
else
{
/* No... then set EINTR and report an error */
set_errno(EINTR);
ret = ERROR;
}
}
else
{
/* Otherwise, we must have been awakened by the timeout. Set EGAIN
* and return an error.
*/
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));
/* The return value is the number of the signal that awakened us */
ret = info->si_signo;
}
else
{
/* We don't know which signal awakened us. This is probably a bug. */
ret = 0;
}
irqrestore(saved_state);
}

View File

@ -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;
}

View File

@ -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;
}