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 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 
31 /**
32  * sys_sem structure
33  */
34 struct sys_sem {
35 #ifdef CONFIG_USERSPACE
36 	struct k_futex futex;
37 	int limit;
38 #else
39 	struct k_sem kernel_sem;
40 #endif
41 };
42 
43 /**
44  * @defgroup user_semaphore_apis User mode semaphore APIs
45  * @ingroup kernel_apis
46  * @{
47  */
48 
49 /**
50  * @brief Statically define and initialize a sys_sem
51  *
52  * The semaphore can be accessed outside the module where it is defined using:
53  *
54  * @code extern struct sys_sem <name>; @endcode
55  *
56  * Route this to memory domains using K_APP_DMEM().
57  *
58  * @param _name Name of the semaphore.
59  * @param _initial_count Initial semaphore count.
60  * @param _count_limit Maximum permitted semaphore count.
61  */
62 #ifdef CONFIG_USERSPACE
63 #define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
64 	struct sys_sem _name = { \
65 		.futex = { _initial_count }, \
66 		.limit = _count_limit \
67 	}; \
68 	BUILD_ASSERT(((_count_limit) != 0) && \
69 		     ((_initial_count) <= (_count_limit)))
70 #else
71 /* Stuff this in the section with the rest of the k_sem objects, since they
72  * are identical and can be treated as a k_sem in the boot initialization code
73  */
74 #define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
75 	STRUCT_SECTION_ITERABLE_ALTERNATE(k_sem, sys_sem, _name) = { \
76 		.kernel_sem = Z_SEM_INITIALIZER(_name.kernel_sem, \
77 						_initial_count, _count_limit) \
78 	}; \
79 	BUILD_ASSERT(((_count_limit) != 0) && \
80 		     ((_initial_count) <= (_count_limit)))
81 #endif
82 
83 /**
84  * @brief Initialize a semaphore.
85  *
86  * This routine initializes a semaphore instance, prior to its first use.
87  *
88  * @param sem Address of the semaphore.
89  * @param initial_count Initial semaphore count.
90  * @param limit Maximum permitted semaphore count.
91  *
92  * @retval 0 Initial success.
93  * @retval -EINVAL Bad parameters, the value of limit should be located in
94  *         (0, INT_MAX] and initial_count shouldn't be greater than limit.
95  */
96 int sys_sem_init(struct sys_sem *sem, unsigned int initial_count,
97 		unsigned int limit);
98 
99 /**
100  * @brief Give a semaphore.
101  *
102  * This routine gives @a sem, unless the semaphore is already at its
103  * maximum permitted count.
104  *
105  * @param sem Address of the semaphore.
106  *
107  * @retval 0 Semaphore given.
108  * @retval -EINVAL Parameter address not recognized.
109  * @retval -EACCES Caller does not have enough access.
110  * @retval -EAGAIN Count reached Maximum permitted count and try again.
111  */
112 int sys_sem_give(struct sys_sem *sem);
113 
114 /**
115  * @brief Take a sys_sem.
116  *
117  * This routine takes @a sem.
118  *
119  * @param sem Address of the sys_sem.
120  * @param timeout Waiting period to take the sys_sem,
121  *                or one of the special values K_NO_WAIT and K_FOREVER.
122  *
123  * @retval 0 sys_sem taken.
124  * @retval -EINVAL Parameter address not recognized.
125  * @retval -ETIMEDOUT Waiting period timed out.
126  * @retval -EACCES Caller does not have enough access.
127  */
128 int sys_sem_take(struct sys_sem *sem, k_timeout_t timeout);
129 
130 /**
131  * @brief Get sys_sem's value
132  *
133  * This routine returns the current value of @a sem.
134  *
135  * @param sem Address of the sys_sem.
136  *
137  * @return Current value of sys_sem.
138  */
139 unsigned int sys_sem_count_get(struct sys_sem *sem);
140 
141 /**
142  * @}
143  */
144 
145 #ifdef __cplusplus
146 }
147 #endif
148 
149 #endif
150