LCOV - code coverage report
Current view: top level - zephyr/sys - sem.h Coverage Total Hit
Test: new.info Lines: 81.8 % 11 9
Test Date: 2025-03-11 06:50:38

            Line data    Source code
       1            1 : /*
       2              :  * Copyright (c) 2019 Intel Corporation
       3              :  *
       4              :  * SPDX-License-Identifier: Apache-2.0
       5              :  */
       6              : 
       7              : /**
       8              :  * @file
       9              :  *
      10              :  * @brief public sys_sem APIs.
      11              :  */
      12              : 
      13              : #ifndef ZEPHYR_INCLUDE_SYS_SEM_H_
      14              : #define ZEPHYR_INCLUDE_SYS_SEM_H_
      15              : 
      16              : /*
      17              :  * sys_sem exists in user memory working as counter semaphore for
      18              :  * user mode thread when user mode enabled. When user mode isn't
      19              :  * enabled, sys_sem behaves like k_sem.
      20              :  */
      21              : 
      22              : #include <zephyr/kernel.h>
      23              : #include <zephyr/sys/atomic.h>
      24              : #include <zephyr/types.h>
      25              : #include <zephyr/sys/iterable_sections.h>
      26              : #include <zephyr/sys/__assert.h>
      27              : 
      28              : #ifdef __cplusplus
      29              : extern "C" {
      30              : #endif
      31              : 
      32              : /**
      33              :  * sys_sem structure
      34              :  */
      35            1 : struct sys_sem {
      36              : #ifdef CONFIG_USERSPACE
      37            0 :         struct k_futex futex;
      38            0 :         int limit;
      39              : #else
      40              :         struct k_sem kernel_sem;
      41              : #endif
      42              : };
      43              : 
      44              : /**
      45              :  * @defgroup user_semaphore_apis User mode semaphore APIs
      46              :  * @ingroup kernel_apis
      47              :  * @{
      48              :  */
      49              : 
      50              : /**
      51              :  * @brief Statically define and initialize a sys_sem
      52              :  *
      53              :  * The semaphore can be accessed outside the module where it is defined using:
      54              :  *
      55              :  * @code extern struct sys_sem <name>; @endcode
      56              :  *
      57              :  * Route this to memory domains using K_APP_DMEM().
      58              :  *
      59              :  * @param _name Name of the semaphore.
      60              :  * @param _initial_count Initial semaphore count.
      61              :  * @param _count_limit Maximum permitted semaphore count.
      62              :  */
      63              : #ifdef CONFIG_USERSPACE
      64            1 : #define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
      65              :         struct sys_sem _name = { \
      66              :                 .futex = { _initial_count }, \
      67              :                 .limit = _count_limit \
      68              :         }; \
      69              :         BUILD_ASSERT(((_count_limit) != 0) && \
      70              :                      ((_initial_count) <= (_count_limit)))
      71              : #else
      72              : /* Stuff this in the section with the rest of the k_sem objects, since they
      73              :  * are identical and can be treated as a k_sem in the boot initialization code
      74              :  */
      75              : #define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
      76              :         STRUCT_SECTION_ITERABLE_ALTERNATE(k_sem, sys_sem, _name) = { \
      77              :                 .kernel_sem = Z_SEM_INITIALIZER(_name.kernel_sem, \
      78              :                                                 _initial_count, _count_limit) \
      79              :         }; \
      80              :         BUILD_ASSERT(((_count_limit) != 0) && \
      81              :                      ((_initial_count) <= (_count_limit)))
      82              : #endif
      83              : 
      84              : /**
      85              :  * @brief Initialize a semaphore.
      86              :  *
      87              :  * This routine initializes a semaphore instance, prior to its first use.
      88              :  *
      89              :  * @param sem Address of the semaphore.
      90              :  * @param initial_count Initial semaphore count.
      91              :  * @param limit Maximum permitted semaphore count.
      92              :  *
      93              :  * @retval 0 Initial success.
      94              :  * @retval -EINVAL Bad parameters, the value of limit should be located in
      95              :  *         (0, INT_MAX] and initial_count shouldn't be greater than limit.
      96              :  */
      97            1 : int sys_sem_init(struct sys_sem *sem, unsigned int initial_count,
      98              :                 unsigned int limit);
      99              : 
     100              : /**
     101              :  * @brief Give a semaphore.
     102              :  *
     103              :  * This routine gives @a sem, unless the semaphore is already at its
     104              :  * maximum permitted count.
     105              :  *
     106              :  * @param sem Address of the semaphore.
     107              :  *
     108              :  * @retval 0 Semaphore given.
     109              :  * @retval -EINVAL Parameter address not recognized.
     110              :  * @retval -EACCES Caller does not have enough access.
     111              :  * @retval -EAGAIN Count reached Maximum permitted count and try again.
     112              :  */
     113            1 : int sys_sem_give(struct sys_sem *sem);
     114              : 
     115              : /**
     116              :  * @brief Take a sys_sem.
     117              :  *
     118              :  * This routine takes @a sem.
     119              :  *
     120              :  * @param sem Address of the sys_sem.
     121              :  * @param timeout Waiting period to take the sys_sem,
     122              :  *                or one of the special values K_NO_WAIT and K_FOREVER.
     123              :  *
     124              :  * @retval 0 sys_sem taken.
     125              :  * @retval -EINVAL Parameter address not recognized.
     126              :  * @retval -ETIMEDOUT Waiting period timed out.
     127              :  * @retval -EACCES Caller does not have enough access.
     128              :  */
     129            1 : int sys_sem_take(struct sys_sem *sem, k_timeout_t timeout);
     130              : 
     131              : /**
     132              :  * @brief Get sys_sem's value
     133              :  *
     134              :  * This routine returns the current value of @a sem.
     135              :  *
     136              :  * @param sem Address of the sys_sem.
     137              :  *
     138              :  * @return Current value of sys_sem.
     139              :  */
     140            1 : unsigned int sys_sem_count_get(struct sys_sem *sem);
     141              : 
     142              : /**
     143              :  * @cond INTERNAL_HIDDEN
     144              :  */
     145              : 
     146              : #if defined(__GNUC__)
     147              : static ALWAYS_INLINE void z_sys_sem_lock_onexit(__maybe_unused int *rc)
     148              : {
     149              :         __ASSERT(*rc == 1, "SYS_SEM_LOCK exited with goto, break or return, "
     150              :                            "use SYS_SEM_LOCK_BREAK instead.");
     151              : }
     152              : #define SYS_SEM_LOCK_ONEXIT __attribute__((__cleanup__(z_sys_sem_lock_onexit)))
     153              : #else
     154              : #define SYS_SEM_LOCK_ONEXIT
     155              : #endif
     156              : 
     157              : /**
     158              :  * INTERNAL_HIDDEN @endcond
     159              :  */
     160              : 
     161              : /**
     162              :  * @brief Leaves a code block guarded with @ref SYS_SEM_LOCK after releasing the
     163              :  * lock.
     164              :  *
     165              :  * See @ref SYS_SEM_LOCK for details.
     166              :  */
     167            1 : #define SYS_SEM_LOCK_BREAK continue
     168              : 
     169              : /**
     170              :  * @brief Guards a code block with the given sys_sem, automatically acquiring
     171              :  * the semaphore before executing the code block. The semaphore will be
     172              :  * released either when reaching the end of the code block or when leaving the
     173              :  * block with @ref SYS_SEM_LOCK_BREAK.
     174              :  *
     175              :  * @details Example usage:
     176              :  *
     177              :  * @code{.c}
     178              :  * SYS_SEM_LOCK(&sem) {
     179              :  *
     180              :  *   ...execute statements with the semaphore held...
     181              :  *
     182              :  *   if (some_condition) {
     183              :  *     ...release the lock and leave the guarded section prematurely:
     184              :  *     SYS_SEM_LOCK_BREAK;
     185              :  *   }
     186              :  *
     187              :  *   ...execute statements with the lock held...
     188              :  *
     189              :  * }
     190              :  * @endcode
     191              :  *
     192              :  * Behind the scenes this pattern expands to a for-loop whose body is executed
     193              :  * exactly once:
     194              :  *
     195              :  * @code{.c}
     196              :  * for (sys_sem_take(&sem, K_FOREVER); ...; sys_sem_give(&sem)) {
     197              :  *     ...
     198              :  * }
     199              :  * @endcode
     200              :  *
     201              :  * @warning The code block must execute to its end or be left by calling
     202              :  * @ref SYS_SEM_LOCK_BREAK. Otherwise, e.g. if exiting the block with a break,
     203              :  * goto or return statement, the semaphore will not be released on exit.
     204              :  *
     205              :  * @param sem Semaphore (@ref sys_sem) used to guard the enclosed code block.
     206              :  */
     207            1 : #define SYS_SEM_LOCK(sem)                                                                          \
     208              :         for (int __rc SYS_SEM_LOCK_ONEXIT = sys_sem_take((sem), K_FOREVER); ({                     \
     209              :                      __ASSERT(__rc >= 0, "Failed to take sem: %d", __rc);                          \
     210              :                      __rc == 0;                                                                    \
     211              :              });                                                                                   \
     212              :              ({                                                                                    \
     213              :                      __rc = sys_sem_give((sem));                                                   \
     214              :                      __ASSERT(__rc == 0, "Failed to give sem: %d", __rc);                          \
     215              :              }),                                                                                   \
     216              :                       __rc = 1)
     217              : 
     218              : /**
     219              :  * @}
     220              :  */
     221              : 
     222              : #ifdef __cplusplus
     223              : }
     224              : #endif
     225              : 
     226              : #endif
        

Generated by: LCOV version 2.0-1