mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 08:36:24 +08:00
sched/semaphore: Move cancel point and errno handling to libc / user-space
This moves all the public POSIX semaphore functions into libc and with this most of the user-space logic is also moved; namely cancel point and errno handling. This also removes the need for the _SEM_XX macros used to differentiate which API is used per user-/kernel mode. Such macros are henceforth unnecessary.
This commit is contained in:
@@ -34,7 +34,6 @@
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/wdog.h>
|
||||
#include <nuttx/cancelpt.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "clock/clock.h"
|
||||
@@ -217,72 +216,3 @@ int nxsem_clockwait_uninterruptible(FAR sem_t *sem, clockid_t clockid,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sem_clockwait
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Input Parameters:
|
||||
* sem - Semaphore object
|
||||
* clockid - The timing source to use in the conversion
|
||||
* abstime - The absolute time to wait until a timeout is declared.
|
||||
*
|
||||
* Returned 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.
|
||||
* ECANCELED May be returned if the thread is canceled while waiting.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sem_clockwait(FAR sem_t *sem, clockid_t clockid,
|
||||
FAR const struct timespec *abstime)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Verify the input parameters and, in case of an error, set
|
||||
* errno appropriately.
|
||||
*/
|
||||
|
||||
if (sem == NULL || abstime == NULL)
|
||||
{
|
||||
set_errno(EINVAL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* sem_timedwait() is a cancellation point */
|
||||
|
||||
enter_cancellation_point();
|
||||
|
||||
/* Let nxsem_timedout() do the work */
|
||||
|
||||
ret = nxsem_clockwait(sem, clockid, abstime);
|
||||
if (ret < 0)
|
||||
{
|
||||
set_errno(-ret);
|
||||
ret = ERROR;
|
||||
}
|
||||
|
||||
leave_cancellation_point();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -80,49 +80,3 @@ int nxsem_destroy(FAR sem_t *sem)
|
||||
nxsem_destroyholder(sem);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sem_destroy
|
||||
*
|
||||
* Description:
|
||||
* This function is used to destroy the un-named semaphore indicated by
|
||||
* 'sem'. Only a semaphore that was created using nxsem_init() may be
|
||||
* destroyed using sem_destroy(); the effect of calling sem_destroy() with
|
||||
* a named semaphore is undefined. The effect of subsequent use of the
|
||||
* semaphore sem is undefined until sem is re-initialized by another call
|
||||
* to nxsem_init().
|
||||
*
|
||||
* The effect of destroying a semaphore upon which other processes are
|
||||
* currently blocked is undefined.
|
||||
*
|
||||
* Input Parameters:
|
||||
* sem - Semaphore to be destroyed.
|
||||
*
|
||||
* Returned Value:
|
||||
* This function is a application interface. It returns zero (OK) if
|
||||
* successful. Otherwise, -1 (ERROR) is returned and the errno value is
|
||||
* set appropriately.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sem_destroy(FAR sem_t *sem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Assure a valid semaphore is specified */
|
||||
|
||||
if (sem == NULL)
|
||||
{
|
||||
set_errno(EINVAL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = nxsem_destroy(sem);
|
||||
if (ret < 0)
|
||||
{
|
||||
set_errno(-ret);
|
||||
ret = ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -205,54 +205,3 @@ int nxsem_post(FAR sem_t *sem)
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sem_post
|
||||
*
|
||||
* Description:
|
||||
* When a task has finished with a semaphore, it will call sem_post().
|
||||
* This function unlocks the semaphore referenced by sem by performing the
|
||||
* semaphore unlock operation on that semaphore.
|
||||
*
|
||||
* If the semaphore value resulting from this operation is positive, then
|
||||
* no tasks were blocked waiting for the semaphore to become unlocked; the
|
||||
* semaphore is simply incremented.
|
||||
*
|
||||
* If the value of the semaphore resulting from this operation is zero,
|
||||
* then one of the tasks blocked waiting for the semaphore shall be
|
||||
* allowed to return successfully from its call to nxsem_wait().
|
||||
*
|
||||
* Input Parameters:
|
||||
* sem - Semaphore descriptor
|
||||
*
|
||||
* Returned Value:
|
||||
* This function is a standard, POSIX application interface. It will
|
||||
* return zero (OK) if successful. Otherwise, -1 (ERROR) is returned and
|
||||
* the errno value is set appropriately.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function may be called from an interrupt handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sem_post(FAR sem_t *sem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Make sure we were supplied with a valid semaphore. */
|
||||
|
||||
if (sem == NULL)
|
||||
{
|
||||
set_errno(EINVAL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = nxsem_post(sem);
|
||||
if (ret < 0)
|
||||
{
|
||||
set_errno(-ret);
|
||||
ret = ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -103,55 +103,4 @@ int nxsem_set_protocol(FAR sem_t *sem, int protocol)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sem_setprotocol
|
||||
*
|
||||
* Description:
|
||||
* Set semaphore protocol attribute.
|
||||
*
|
||||
* One particularly important use of this function is when a semaphore
|
||||
* is used for inter-task communication like:
|
||||
*
|
||||
* TASK A TASK B
|
||||
* sem_init(sem, 0, 0);
|
||||
* nxsem_wait(sem);
|
||||
* sem_post(sem);
|
||||
* Awakens as holder
|
||||
*
|
||||
* In this case priority inheritance can interfere with the operation of
|
||||
* the semaphore. The problem is that when TASK A is restarted it is a
|
||||
* holder of the semaphore. However, it never calls sem_post(sem) so it
|
||||
* becomes *permanently* a holder of the semaphore and may have its
|
||||
* priority boosted when any other task tries to acquire the semaphore.
|
||||
*
|
||||
* The fix is to call sem_setprotocol(SEM_PRIO_NONE) immediately after
|
||||
* the sem_init() call so that there will be no priority inheritance
|
||||
* operations on this semaphore.
|
||||
*
|
||||
* Input Parameters:
|
||||
* sem - A pointer to the semaphore whose attributes are to be
|
||||
* modified
|
||||
* protocol - The new protocol to use
|
||||
*
|
||||
* Returned Value:
|
||||
* This function is exposed as a non-standard application interface. It
|
||||
* returns zero (OK) if successful. Otherwise, -1 (ERROR) is returned and
|
||||
* the errno value is set appropriately.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sem_setprotocol(FAR sem_t *sem, int protocol)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nxsem_set_protocol(sem, protocol);
|
||||
if (ret < 0)
|
||||
{
|
||||
set_errno(-ret);
|
||||
ret = ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PRIORITY_INHERITANCE */
|
||||
|
||||
@@ -106,44 +106,3 @@ int nxsem_timedwait_uninterruptible(FAR sem_t *sem,
|
||||
{
|
||||
return nxsem_clockwait_uninterruptible(sem, CLOCK_REALTIME, abstime);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
*
|
||||
* Input Parameters:
|
||||
* sem - Semaphore object
|
||||
* abstime - The absolute time to wait until a timeout is declared.
|
||||
*
|
||||
* Returned 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.
|
||||
* ECANCELED May be returned if the thread is canceled while waiting.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime)
|
||||
{
|
||||
return sem_clockwait(sem, CLOCK_REALTIME, abstime);
|
||||
}
|
||||
|
||||
@@ -105,46 +105,3 @@ int nxsem_trywait(FAR sem_t *sem)
|
||||
leave_critical_section(flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sem_trywait
|
||||
*
|
||||
* Description:
|
||||
* This function locks the specified semaphore only if the semaphore is
|
||||
* currently not locked. In either case, the call returns without
|
||||
* blocking.
|
||||
*
|
||||
* Input Parameters:
|
||||
* sem - the semaphore descriptor
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success or -1 (ERROR) if unsuccessful. If this function
|
||||
* returns -1(ERROR), then the cause of the failure will be reported in
|
||||
* errno variable as:
|
||||
*
|
||||
* EINVAL - Invalid attempt to get the semaphore
|
||||
* EAGAIN - The semaphore is not available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sem_trywait(FAR sem_t *sem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (sem == NULL)
|
||||
{
|
||||
set_errno(EINVAL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Let nxsem_trywait do the real work */
|
||||
|
||||
ret = nxsem_trywait(sem);
|
||||
if (ret < 0)
|
||||
{
|
||||
set_errno(-ret);
|
||||
ret = ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <nuttx/init.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/cancelpt.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "semaphore/semaphore.h"
|
||||
@@ -251,67 +250,3 @@ int nxsem_wait_uninterruptible(FAR sem_t *sem)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sem_wait
|
||||
*
|
||||
* Description:
|
||||
* This function attempts to lock the semaphore referenced by 'sem'. If
|
||||
* the semaphore value is (<=) zero, then the calling task will not return
|
||||
* until it successfully acquires the lock.
|
||||
*
|
||||
* Input Parameters:
|
||||
* sem - Semaphore descriptor.
|
||||
*
|
||||
* Returned Value:
|
||||
* This function is a standard, POSIX application interface. It returns
|
||||
* zero (OK) if successful. Otherwise, -1 (ERROR) is returned and
|
||||
* the errno value is set appropriately. Possible errno values include:
|
||||
*
|
||||
* - EINVAL: Invalid attempt to get the semaphore
|
||||
* - EINTR: The wait was interrupted by the receipt of a signal.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sem_wait(FAR sem_t *sem)
|
||||
{
|
||||
int errcode;
|
||||
int ret;
|
||||
|
||||
if (sem == NULL)
|
||||
{
|
||||
set_errno(EINVAL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* sem_wait() is a cancellation point */
|
||||
|
||||
if (enter_cancellation_point())
|
||||
{
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
/* If there is a pending cancellation, then do not perform
|
||||
* the wait. Exit now with ECANCELED.
|
||||
*/
|
||||
|
||||
errcode = ECANCELED;
|
||||
goto errout_with_cancelpt;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Let nxsem_wait() do the real work */
|
||||
|
||||
ret = nxsem_wait(sem);
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = -ret;
|
||||
goto errout_with_cancelpt;
|
||||
}
|
||||
|
||||
leave_cancellation_point();
|
||||
return OK;
|
||||
|
||||
errout_with_cancelpt:
|
||||
set_errno(errcode);
|
||||
leave_cancellation_point();
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user