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:
Ville Juven
2023-11-16 16:27:06 +02:00
committed by Xiang Xiao
parent 34afef5cfb
commit c9bdadd541
20 changed files with 552 additions and 411 deletions
-70
View File
@@ -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;
}
-46
View File
@@ -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;
}
-51
View File
@@ -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;
}
-51
View File
@@ -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 */
-41
View File
@@ -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);
}
-43
View File
@@ -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;
}
-65
View File
@@ -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;
}