1
0
Fork 0
forked from nuttx/nuttx-update

sched/semaphore: sem_timedwait() is a cancellation point and, hence, cannot be called from within the OS. Created nxsem_timedwait() that is equivalent but does not modify the errno and does not cause cancellation. All calls to sem_timedwait() change to calls to nxsem_timedwait() in the OS.

This commit is contained in:
Gregory Nutt 2017-10-05 07:24:54 -06:00
parent 9568600ab1
commit 29b5b3667f
20 changed files with 207 additions and 122 deletions

View file

@ -578,16 +578,16 @@ static inline int efm32_i2c_sem_waitdone(FAR struct efm32_i2c_priv_s *priv)
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
/* Disable I2C interrupts */
efm32_i2c_putreg(priv, EFM32_I2C_IEN_OFFSET, 0);
if (ret != OK && errno != EINTR)
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would include
* timeouts and mystery errors reported by sem_timedwait. NOTE that
* timeouts and mystery errors reported by nxsem_timedwait. NOTE that
* we try again if we are awakened by a signal (EINTR).
*/
@ -624,7 +624,7 @@ static inline int efm32_i2c_sem_waitdone(FAR struct efm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts are
* currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
start = clock_systimer();

View file

@ -54,9 +54,10 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/kmalloc.h>
#include <nuttx/clock.h>
#include <nuttx/semaphore.h>
#include <nuttx/i2c/i2c_master.h>
#include <arch/board/board.h>
@ -308,11 +309,7 @@ static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv
{
/* Get the current time */
#ifdef CONFIG_CLOCK_MONOTONIC
(void)clock_gettime(CLOCK_MONOTONIC, &abstime);
#else
(void)clock_gettime(CLOCK_REALTIME, &abstime);
#endif
/* Calculate a time in the future */
@ -331,16 +328,12 @@ static inline int lc823450_i2c_sem_waitdone(FAR struct lc823450_i2c_priv_s *priv
/* Wait until either the transfer is complete or the timeout expires */
#ifdef CONFIG_CLOCK_MONOTONIC
ret = sem_timedwait_monotonic(&priv->sem_isr, &abstime);
#else
ret = sem_timedwait(&priv->sem_isr, &abstime);
#endif
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && errno != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
break;

View file

@ -61,6 +61,7 @@
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/semaphore.h>
#include <nuttx/i2c/i2c_master.h>
#include <arch/board/board.h>
@ -624,15 +625,16 @@ static inline void i2c_putrel(struct sam_i2c_dev_s *priv, unsigned int offset,
static int i2c_wait_for_bus(struct sam_i2c_dev_s *priv, unsigned int size)
{
struct timespec ts;
int ret;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_nsec += 200e3;
if (sem_timedwait(&priv->waitsem, (const struct timespec *)&ts) != OK)
ret = nxsem_timedwait(&priv->waitsem, (const struct timespec *)&ts);
if (ret < 0)
{
int errcode = errno;
i2cinfo("timedwait error %d\n", errcode);
return -errcode;
i2cinfo("timedwait error %d\n", ret);
return ret;
}
return priv->result;

View file

@ -814,11 +814,11 @@ static int stm32_1wire_process(struct stm32_1wire_priv_s *priv,
stm32_1wire_send(priv, RESET_TX);
leave_critical_section(irqs);
/* Wait */
/* Wait. Break on timeout if TX line closed to GND */
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += BUS_TIMEOUT;
sem_timedwait(&priv->sem_isr, &abstime); /* break on timeout if TX line closed to GND */
(void)nxsem_timedwait(&priv->sem_isr, &abstime);
break;
case ONEWIRETASK_WRITE:
@ -836,11 +836,11 @@ static int stm32_1wire_process(struct stm32_1wire_priv_s *priv,
stm32_1wire_send(priv, (*priv->byte & (1 << priv->bit)) ? WRITE_TX1 : WRITE_TX0);
leave_critical_section(irqs);
/* Wait */
/* Wait. Break on timeout if TX line closed to GND */
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += BUS_TIMEOUT;
sem_timedwait(&priv->sem_isr, &abstime); /* break on timeout if TX line closed to GND */
(void)nxsem_timedwait(&priv->sem_isr, &abstime);
break;
case ONEWIRETASK_READ:
@ -858,11 +858,11 @@ static int stm32_1wire_process(struct stm32_1wire_priv_s *priv,
stm32_1wire_send(priv, READ_TX);
leave_critical_section(irqs);
/* Wait */
/* Wait. Break on timeout if TX line closed to GND */
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += BUS_TIMEOUT;
sem_timedwait(&priv->sem_isr, &abstime); /* break on timeout if TX line closed to GND */
(void)nxsem_timedwait(&priv->sem_isr, &abstime);
break;
}

View file

@ -577,7 +577,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
@ -614,11 +614,11 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -661,7 +661,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;

View file

@ -585,7 +585,7 @@ static int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
@ -622,11 +622,11 @@ static int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -669,7 +669,7 @@ static int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;

View file

@ -614,7 +614,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
@ -650,11 +650,11 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
#endif
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -695,7 +695,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;

View file

@ -633,7 +633,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
@ -670,11 +670,11 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -717,7 +717,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;

View file

@ -556,7 +556,7 @@ static inline int stm32f0_i2c_sem_waitdone(FAR struct stm32f0_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
@ -592,11 +592,11 @@ static inline int stm32f0_i2c_sem_waitdone(FAR struct stm32f0_i2c_priv_s *priv)
#endif
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -637,7 +637,7 @@ static inline int stm32f0_i2c_sem_waitdone(FAR struct stm32f0_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;

View file

@ -839,11 +839,11 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
#endif
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -884,7 +884,7 @@ static inline int stm32_i2c_sem_waitdone(FAR struct stm32_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;

View file

@ -588,7 +588,7 @@ static inline int stm32l4_i2c_sem_waitdone(FAR struct stm32l4_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;
@ -624,11 +624,11 @@ static inline int stm32l4_i2c_sem_waitdone(FAR struct stm32l4_i2c_priv_s *priv)
#endif
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->sem_isr, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->sem_isr, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -669,7 +669,7 @@ static inline int stm32l4_i2c_sem_waitdone(FAR struct stm32l4_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
priv->intstate = INTSTATE_WAITING;

View file

@ -718,7 +718,7 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
do
@ -754,11 +754,11 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
/* Wait until either the transfer is complete or the timeout expires */
ret = sem_timedwait(&priv->waitsem, &abstime);
if (ret != OK && errno != EINTR)
ret = nxsem_timedwait(&priv->waitsem, &abstime);
if (ret < 0 && ret != -EINTR)
{
/* Break out of the loop on irrecoverable errors. This would
* include timeouts and mystery errors reported by sem_timedwait.
* include timeouts and mystery errors reported by nxsem_timedwait.
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
@ -802,7 +802,7 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps.
* nxsem_timedwait() sleeps.
*/
start = clock_systimer();

View file

@ -327,7 +327,7 @@ static int pn532_wait_rx_ready(struct pn532_dev_s *dev, int timeout)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 1;
sem_timedwait(dev->sem_rx, &ts);
(void)nxsem_timedwait(dev->sem_rx, &ts);
#endif
/* TODO: Handle Exception bits 2, 3 */

View file

@ -570,14 +570,13 @@ static int lps25h_one_shot(FAR struct lps25h_dev_s *dev)
abstime.tv_nsec -= 1000 * 1000 * 1000;
}
while ((ret = sem_timedwait(&dev->waitsem, &abstime)) != 0)
while ((ret = nxsem_timedwait(&dev->waitsem, &abstime)) < 0)
{
int err = errno;
if (err == EINTR)
if (ret == -EINTR)
{
continue;
}
else if (err == ETIMEDOUT)
else if (ret == -ETIMEDOUT)
{
uint8_t reg = LPS25H_CTRL_REG2;
uint8_t value;
@ -609,7 +608,7 @@ static int lps25h_one_shot(FAR struct lps25h_dev_s *dev)
/* Some unknown mystery error */
DEBUGASSERT(false);
return -err;
return ret;
}
}

View file

@ -227,7 +227,7 @@ int bcmf_cdc_control_request_unsafe(FAR struct bcmf_dev_s *priv,
}
ret = bcmf_sem_wait(&priv->control_timeout, BCMF_CONTROL_TIMEOUT_MS);
if (ret != OK)
if (ret < 0)
{
wlerr("Error while waiting for control response %d\n", ret);
return ret;

View file

@ -1188,10 +1188,10 @@ int bcmf_wl_set_ssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
wlinfo("semwait done ! %d\n", ret);
if (ret)
if (ret < 0)
{
wlerr("Associate request timeout\n");
return -EINVAL;
return ret;
}
switch (priv->auth_status)
@ -1204,5 +1204,6 @@ int bcmf_wl_set_ssid(FAR struct bcmf_dev_s *priv, struct iwreq *iwr)
wlerr("AP join failed %d\n", priv->auth_status);
return -EINVAL;
}
return OK;
}

View file

@ -45,6 +45,8 @@
#include <stdio.h>
#include <queue.h>
#include <nuttx/semaphore.h>
#include "bcmf_utils.h"
/****************************************************************************
@ -117,7 +119,7 @@ int bcmf_sem_wait(sem_t *sem, unsigned int timeout_ms)
abstime.tv_nsec -= 1000 * 1000 * 1000;
}
return sem_timedwait(sem, &abstime);
return nxsem_timedwait(sem, &abstime);
}
void bcmf_dqueue_push(dq_queue_t *queue, dq_entry_t *entry)

View file

@ -180,6 +180,52 @@ int nxsem_destroy (FAR sem_t *sem);
int nxsem_wait(FAR sem_t *sem);
/****************************************************************************
* Name: nxsem_timedwait
*
* Description:
* This function will lock the semaphore referenced by sem as in the
* sem_wait() function. However, if the semaphore cannot be locked without
* waiting for another process or thread to unlock the semaphore by
* performing a sem_post() function, this wait will be terminated when the
* specified timeout expires.
*
* The timeout will expire when the absolute time specified by abstime
* passes, as measured by the clock on which timeouts are based (that is,
* when the value of that clock equals or exceeds abstime), or if the
* absolute time specified by abstime has already been passed at the
* time of the call.
*
* This is an internal OS interface. It is functionally equivalent to
* sem_wait except that:
*
* - It is not a cancellaction point, and
* - It does not modify the errno value.
*
* Parameters:
* sem - Semaphore object
* abstime - The absolute time to wait until a timeout is declared.
*
* Return 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.
* That may be one of:
*
* EINVAL The sem argument does not refer to a valid semaphore. Or the
* thread would have blocked, and the abstime parameter specified
* a nanoseconds field value less than zero or greater than or
* equal to 1000 million.
* ETIMEDOUT The semaphore could not be locked before the specified timeout
* expired.
* EDEADLK A deadlock condition was detected.
* EINTR A signal interrupted this function.
*
****************************************************************************/
struct timespec; /* Forward reference */
int nxsem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime);
/****************************************************************************
* Name: nxsem_tickwait
*

View file

@ -47,6 +47,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include "utils/utils.h"
@ -226,11 +227,11 @@ int net_timedwait(sem_t *sem, FAR const struct timespec *abstime)
/* Now take the semaphore, waiting if so requested. */
if (abstime)
if (abstime != NULL)
{
/* Wait until we get the lock or until the timeout expires */
ret = sem_timedwait(sem, abstime);
ret = nxsem_timedwait(sem, abstime);
}
else
{
@ -250,7 +251,6 @@ int net_timedwait(sem_t *sem, FAR const struct timespec *abstime)
ret = nxsem_wait(sem);
}
sched_unlock();
leave_critical_section(flags);
return ret;

View file

@ -60,7 +60,7 @@
****************************************************************************/
/****************************************************************************
* Name: sem_timedwait
* Name: nxsem_timedwait
*
* Description:
* This function will lock the semaphore referenced by sem as in the
@ -75,13 +75,21 @@
* absolute time specified by abstime has already been passed at the
* time of the call.
*
* This is an internal OS interface. It is functionally equivalent to
* sem_wait except that:
*
* - It is not a cancellaction point, and
* - It does not modify the errno value.
*
* Parameters:
* sem - Semaphore object
* sem - Semaphore object
* abstime - The absolute time to wait until a timeout is declared.
*
* Return Value:
* Zero (OK) is returned on success. On failure, -1 (ERROR) is returned
* and the errno is set appropriately:
* 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.
* That may be one of:
*
* EINVAL The sem argument does not refer to a valid semaphore. Or the
* thread would have blocked, and the abstime parameter specified
@ -94,20 +102,16 @@
*
****************************************************************************/
int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
int nxsem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
{
FAR struct tcb_s *rtcb = this_task();
irqstate_t flags;
ssystime_t ticks;
int errcode;
int ret = ERROR;
int status;
int ret = ERROR;
DEBUGASSERT(up_interrupt_context() == false && rtcb->waitdog == NULL);
/* sem_timedwait() is a cancellation point */
(void)enter_cancellation_point();
/* Verify the input parameters and, in case of an error, set
* errno appropriately.
*/
@ -115,8 +119,7 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
#ifdef CONFIG_DEBUG_FEATURES
if (!abstime || !sem)
{
errcode = EINVAL;
goto errout;
return -EINVAL;
}
#endif
@ -128,8 +131,7 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
rtcb->waitdog = wd_create();
if (!rtcb->waitdog)
{
errcode = ENOMEM;
goto errout;
return -ENOMEM;
}
/* We will disable interrupts until we have completed the semaphore
@ -158,28 +160,32 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
{
errcode = EINVAL;
ret = -EINVAL;
goto errout_with_irqdisabled;
}
/* Convert the timespec to clock ticks. We must have interrupts
* disabled here so that this time stays valid until the wait begins.
*
* clock_abstime2ticks() returns zero on success or a POSITIVE errno
* value on failure.
*/
errcode = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks);
status = clock_abstime2ticks(CLOCK_REALTIME, abstime, &ticks);
/* If the time has already expired return immediately. */
if (errcode == OK && ticks <= 0)
if (status == OK && ticks <= 0)
{
errcode = ETIMEDOUT;
ret = -ETIMEDOUT;
goto errout_with_irqdisabled;
}
/* Handle any time-related errors */
if (errcode != OK)
if (status != OK)
{
ret = -status;
goto errout_with_irqdisabled;
}
@ -188,7 +194,9 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
(void)wd_start(rtcb->waitdog, ticks, (wdentry_t)nxsem_timeout,
1, getpid());
/* Now perform the blocking wait */
/* Now perform the blocking wait. If nxsem_wait() fails, the
* negated errno value will be returned below.
*/
ret = nxsem_wait(sem);
@ -196,34 +204,68 @@ int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
wd_cancel(rtcb->waitdog);
if (ret < 0)
{
/* nxsem_wait() failed. Save the errno value */
errcode = -ret;
goto errout_with_irqdisabled;
}
/* We can now restore interrupts and delete the watchdog */
/* Success exits */
success_with_irqdisabled:
leave_critical_section(flags);
wd_delete(rtcb->waitdog);
rtcb->waitdog = NULL;
leave_cancellation_point();
return OK;
/* Error exits */
errout_with_irqdisabled:
leave_critical_section(flags);
wd_delete(rtcb->waitdog);
rtcb->waitdog = NULL;
errout:
set_errno(errcode);
leave_cancellation_point();
return ERROR;
return ret;
}
/****************************************************************************
* Name: sem_timedwait
*
* Description:
* This function will lock the semaphore referenced by sem as in the
* sem_wait() function. However, if the semaphore cannot be locked without
* waiting for another process or thread to unlock the semaphore by
* performing a sem_post() function, this wait will be terminated when the
* specified timeout expires.
*
* The timeout will expire when the absolute time specified by abstime
* passes, as measured by the clock on which timeouts are based (that is,
* when the value of that clock equals or exceeds abstime), or if the
* absolute time specified by abstime has already been passed at the
* time of the call.
*
* Parameters:
* sem - Semaphore object
* abstime - The absolute time to wait until a timeout is declared.
*
* Return Value:
* Zero (OK) is returned on success. On failure, -1 (ERROR) is returned
* and the errno is set appropriately:
*
* EINVAL The sem argument does not refer to a valid semaphore. Or the
* thread would have blocked, and the abstime parameter specified
* a nanoseconds field value less than zero or greater than or
* equal to 1000 million.
* ETIMEDOUT The semaphore could not be locked before the specified timeout
* expired.
* EDEADLK A deadlock condition was detected.
* EINTR A signal interrupted this function.
*
****************************************************************************/
int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
{
int ret;
/* sem_timedwait() is a cancellation point */
(void)enter_cancellation_point();
/* Let nxsem_timedout() do the work */
ret = nxsem_timedwait(sem, abstime);
if (ret < 0)
{
set_errno(-ret);
ret = ERROR;
}
leave_cancellation_point();
return ret;
}