Move usermode mutex/semaphore under the usermode group. Signed-off-by: Anas Nashif <anas.nashif@intel.com>
227 lines
6.1 KiB
C
227 lines
6.1 KiB
C
/*
|
|
* Copyright (c) 2019 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* @brief public sys_sem APIs.
|
|
*/
|
|
|
|
#ifndef ZEPHYR_INCLUDE_SYS_SEM_H_
|
|
#define ZEPHYR_INCLUDE_SYS_SEM_H_
|
|
|
|
/*
|
|
* sys_sem exists in user memory working as counter semaphore for
|
|
* user mode thread when user mode enabled. When user mode isn't
|
|
* enabled, sys_sem behaves like k_sem.
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/sys/atomic.h>
|
|
#include <zephyr/types.h>
|
|
#include <zephyr/sys/iterable_sections.h>
|
|
#include <zephyr/sys/__assert.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* sys_sem structure
|
|
*/
|
|
struct sys_sem {
|
|
#ifdef CONFIG_USERSPACE
|
|
struct k_futex futex;
|
|
int limit;
|
|
#else
|
|
struct k_sem kernel_sem;
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* @defgroup user_semaphore_apis User mode semaphore APIs
|
|
* @ingroup usermode_apis
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Statically define and initialize a sys_sem
|
|
*
|
|
* The semaphore can be accessed outside the module where it is defined using:
|
|
*
|
|
* @code extern struct sys_sem <name>; @endcode
|
|
*
|
|
* Route this to memory domains using K_APP_DMEM().
|
|
*
|
|
* @param _name Name of the semaphore.
|
|
* @param _initial_count Initial semaphore count.
|
|
* @param _count_limit Maximum permitted semaphore count.
|
|
*/
|
|
#ifdef CONFIG_USERSPACE
|
|
#define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
|
|
struct sys_sem _name = { \
|
|
.futex = { _initial_count }, \
|
|
.limit = _count_limit \
|
|
}; \
|
|
BUILD_ASSERT(((_count_limit) != 0) && \
|
|
((_initial_count) <= (_count_limit)))
|
|
#else
|
|
/* Stuff this in the section with the rest of the k_sem objects, since they
|
|
* are identical and can be treated as a k_sem in the boot initialization code
|
|
*/
|
|
#define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
|
|
STRUCT_SECTION_ITERABLE_ALTERNATE(k_sem, sys_sem, _name) = { \
|
|
.kernel_sem = Z_SEM_INITIALIZER(_name.kernel_sem, \
|
|
_initial_count, _count_limit) \
|
|
}; \
|
|
BUILD_ASSERT(((_count_limit) != 0) && \
|
|
((_initial_count) <= (_count_limit)))
|
|
#endif
|
|
|
|
/**
|
|
* @brief Initialize a semaphore.
|
|
*
|
|
* This routine initializes a semaphore instance, prior to its first use.
|
|
*
|
|
* @param sem Address of the semaphore.
|
|
* @param initial_count Initial semaphore count.
|
|
* @param limit Maximum permitted semaphore count.
|
|
*
|
|
* @retval 0 Initial success.
|
|
* @retval -EINVAL Bad parameters, the value of limit should be located in
|
|
* (0, INT_MAX] and initial_count shouldn't be greater than limit.
|
|
*/
|
|
int sys_sem_init(struct sys_sem *sem, unsigned int initial_count,
|
|
unsigned int limit);
|
|
|
|
/**
|
|
* @brief Give a semaphore.
|
|
*
|
|
* This routine gives @a sem, unless the semaphore is already at its
|
|
* maximum permitted count.
|
|
*
|
|
* @param sem Address of the semaphore.
|
|
*
|
|
* @retval 0 Semaphore given.
|
|
* @retval -EINVAL Parameter address not recognized.
|
|
* @retval -EACCES Caller does not have enough access.
|
|
* @retval -EAGAIN Count reached Maximum permitted count and try again.
|
|
*/
|
|
int sys_sem_give(struct sys_sem *sem);
|
|
|
|
/**
|
|
* @brief Take a sys_sem.
|
|
*
|
|
* This routine takes @a sem.
|
|
*
|
|
* @param sem Address of the sys_sem.
|
|
* @param timeout Waiting period to take the sys_sem,
|
|
* or one of the special values K_NO_WAIT and K_FOREVER.
|
|
*
|
|
* @retval 0 sys_sem taken.
|
|
* @retval -EINVAL Parameter address not recognized.
|
|
* @retval -ETIMEDOUT Waiting period timed out.
|
|
* @retval -EACCES Caller does not have enough access.
|
|
*/
|
|
int sys_sem_take(struct sys_sem *sem, k_timeout_t timeout);
|
|
|
|
/**
|
|
* @brief Get sys_sem's value
|
|
*
|
|
* This routine returns the current value of @a sem.
|
|
*
|
|
* @param sem Address of the sys_sem.
|
|
*
|
|
* @return Current value of sys_sem.
|
|
*/
|
|
unsigned int sys_sem_count_get(struct sys_sem *sem);
|
|
|
|
/**
|
|
* @cond INTERNAL_HIDDEN
|
|
*/
|
|
|
|
#if defined(__GNUC__)
|
|
static ALWAYS_INLINE void z_sys_sem_lock_onexit(__maybe_unused int *rc)
|
|
{
|
|
__ASSERT(*rc == 1, "SYS_SEM_LOCK exited with goto, break or return, "
|
|
"use SYS_SEM_LOCK_BREAK instead.");
|
|
}
|
|
#define SYS_SEM_LOCK_ONEXIT __attribute__((__cleanup__(z_sys_sem_lock_onexit)))
|
|
#else
|
|
#define SYS_SEM_LOCK_ONEXIT
|
|
#endif
|
|
|
|
/**
|
|
* INTERNAL_HIDDEN @endcond
|
|
*/
|
|
|
|
/**
|
|
* @brief Leaves a code block guarded with @ref SYS_SEM_LOCK after releasing the
|
|
* lock.
|
|
*
|
|
* See @ref SYS_SEM_LOCK for details.
|
|
*/
|
|
#define SYS_SEM_LOCK_BREAK continue
|
|
|
|
/**
|
|
* @brief Guards a code block with the given sys_sem, automatically acquiring
|
|
* the semaphore before executing the code block. The semaphore will be
|
|
* released either when reaching the end of the code block or when leaving the
|
|
* block with @ref SYS_SEM_LOCK_BREAK.
|
|
*
|
|
* @details Example usage:
|
|
*
|
|
* @code{.c}
|
|
* SYS_SEM_LOCK(&sem) {
|
|
*
|
|
* ...execute statements with the semaphore held...
|
|
*
|
|
* if (some_condition) {
|
|
* ...release the lock and leave the guarded section prematurely:
|
|
* SYS_SEM_LOCK_BREAK;
|
|
* }
|
|
*
|
|
* ...execute statements with the lock held...
|
|
*
|
|
* }
|
|
* @endcode
|
|
*
|
|
* Behind the scenes this pattern expands to a for-loop whose body is executed
|
|
* exactly once:
|
|
*
|
|
* @code{.c}
|
|
* for (sys_sem_take(&sem, K_FOREVER); ...; sys_sem_give(&sem)) {
|
|
* ...
|
|
* }
|
|
* @endcode
|
|
*
|
|
* @warning The code block must execute to its end or be left by calling
|
|
* @ref SYS_SEM_LOCK_BREAK. Otherwise, e.g. if exiting the block with a break,
|
|
* goto or return statement, the semaphore will not be released on exit.
|
|
*
|
|
* @param sem Semaphore (@ref sys_sem) used to guard the enclosed code block.
|
|
*/
|
|
#define SYS_SEM_LOCK(sem) \
|
|
for (int __rc SYS_SEM_LOCK_ONEXIT = sys_sem_take((sem), K_FOREVER); ({ \
|
|
__ASSERT(__rc >= 0, "Failed to take sem: %d", __rc); \
|
|
__rc == 0; \
|
|
}); \
|
|
({ \
|
|
__rc = sys_sem_give((sem)); \
|
|
__ASSERT(__rc == 0, "Failed to give sem: %d", __rc); \
|
|
}), \
|
|
__rc = 1)
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|