Line data Source code
1 0 : /*
2 : * Copyright (c) 2019 Peter Bigot Consulting, LLC
3 : * Copyright (c) 2020 Nordic Semiconductor ASA
4 : *
5 : * SPDX-License-Identifier: Apache-2.0
6 : */
7 :
8 : #ifndef ZEPHYR_INCLUDE_SYS_NOTIFY_H_
9 : #define ZEPHYR_INCLUDE_SYS_NOTIFY_H_
10 :
11 : #include <zephyr/kernel.h>
12 : #include <zephyr/types.h>
13 :
14 : #ifdef __cplusplus
15 : extern "C" {
16 : #endif
17 :
18 : struct sys_notify;
19 :
20 : /*
21 : * Flag value that overwrites the method field when the operation has
22 : * completed.
23 : */
24 0 : #define SYS_NOTIFY_METHOD_COMPLETED 0
25 :
26 : /*
27 : * Indicates that no notification will be provided.
28 : *
29 : * Callers must check for completions using
30 : * sys_notify_fetch_result().
31 : *
32 : * See sys_notify_init_spinwait().
33 : */
34 0 : #define SYS_NOTIFY_METHOD_SPINWAIT 1
35 :
36 : /*
37 : * Select notification through @ref k_poll signal
38 : *
39 : * See sys_notify_init_signal().
40 : */
41 0 : #define SYS_NOTIFY_METHOD_SIGNAL 2
42 :
43 : /*
44 : * Select notification through a user-provided callback.
45 : *
46 : * See sys_notify_init_callback().
47 : */
48 0 : #define SYS_NOTIFY_METHOD_CALLBACK 3
49 :
50 0 : #define SYS_NOTIFY_METHOD_MASK 0x03U
51 0 : #define SYS_NOTIFY_METHOD_POS 0
52 :
53 : /**
54 : * @brief Identify the region of sys_notify flags available for
55 : * containing services.
56 : *
57 : * Bits of the flags field of the sys_notify structure at and above
58 : * this position may be used by extensions to the sys_notify
59 : * structure.
60 : *
61 : * These bits are intended for use by containing service
62 : * implementations to record client-specific information. The bits
63 : * are cleared by sys_notify_validate(). Use of these does not
64 : * imply that the flags field becomes public API.
65 : */
66 1 : #define SYS_NOTIFY_EXTENSION_POS 2
67 :
68 : /*
69 : * Mask isolating the bits of sys_notify::flags that are available
70 : * for extension.
71 : */
72 0 : #define SYS_NOTIFY_EXTENSION_MASK (~BIT_MASK(SYS_NOTIFY_EXTENSION_POS))
73 :
74 : /**
75 : * @defgroup sys_notify_apis Asynchronous Notification APIs
76 : * @ingroup os_services
77 : * @{
78 : */
79 :
80 : /**
81 : * @brief Generic signature used to notify of result completion by
82 : * callback.
83 : *
84 : * Functions with this role may be invoked from any context including
85 : * pre-kernel, ISR, or cooperative or pre-emptible threads.
86 : * Compatible functions must be isr-ok and not sleep.
87 : *
88 : * Parameters that should generally be passed to such functions include:
89 : *
90 : * * a pointer to a specific client request structure, i.e. the one
91 : * that contains the sys_notify structure.
92 : * * the result of the operation, either as passed to
93 : * sys_notify_finalize() or extracted afterwards using
94 : * sys_notify_fetch_result(). Expected values are
95 : * service-specific, but the value shall be non-negative if the
96 : * operation succeeded, and negative if the operation failed.
97 : */
98 1 : typedef void (*sys_notify_generic_callback)();
99 :
100 : /**
101 : * @brief State associated with notification for an asynchronous
102 : * operation.
103 : *
104 : * Objects of this type are allocated by a client, which must use an
105 : * initialization function (e.g. sys_notify_init_signal()) to
106 : * configure them. Generally the structure is a member of a
107 : * service-specific client structure, such as onoff_client.
108 : *
109 : * Control of the containing object transfers to the service provider
110 : * when a pointer to the object is passed to a service function that
111 : * is documented to take control of the object, such as
112 : * onoff_service_request(). While the service provider controls the
113 : * object the client must not change any object fields. Control
114 : * reverts to the client:
115 : * * if the call to the service API returns an error;
116 : * * when operation completion is posted. This may occur before the
117 : * call to the service API returns.
118 : *
119 : * Operation completion is technically posted when the flags field is
120 : * updated so that sys_notify_fetch_result() returns success. This
121 : * will happen before the signal is posted or callback is invoked.
122 : * Note that although the manager will no longer reference the
123 : * sys_notify object past this point, the containing object may have
124 : * state that will be referenced within the callback. Where callbacks
125 : * are used control of the containing object does not revert to the
126 : * client until the callback has been invoked. (Re-use within the
127 : * callback is explicitly permitted.)
128 : *
129 : * After control has reverted to the client the notify object must be
130 : * reinitialized for the next operation.
131 : *
132 : * The content of this structure is not public API to clients: all
133 : * configuration and inspection should be done with functions like
134 : * sys_notify_init_callback() and sys_notify_fetch_result().
135 : * However, services that use this structure may access certain
136 : * fields directly.
137 : */
138 1 : struct sys_notify {
139 0 : union method {
140 : /* Pointer to signal used to notify client.
141 : *
142 : * The signal value corresponds to the res parameter
143 : * of sys_notify_callback.
144 : */
145 0 : struct k_poll_signal *signal;
146 :
147 : /* Generic callback function for callback notification. */
148 0 : sys_notify_generic_callback callback;
149 0 : } method;
150 :
151 : /*
152 : * Flags recording information about the operation.
153 : *
154 : * Bits below SYS_NOTIFY_EXTENSION_POS are initialized by
155 : * async notify API init functions like
156 : * sys_notify_init_callback(), and must not by modified by
157 : * extensions or client code.
158 : *
159 : * Bits at and above SYS_NOTIFY_EXTENSION_POS are available
160 : * for use by service extensions while the containing object
161 : * is managed by the service. They are not for client use,
162 : * are zeroed by the async notify API init functions, and will
163 : * be zeroed by sys_notify_finalize().
164 : */
165 0 : uint32_t volatile flags;
166 :
167 : /*
168 : * The result of the operation.
169 : *
170 : * This is the value that was (or would be) passed to the
171 : * async infrastructure. This field is the sole record of
172 : * success or failure for spin-wait synchronous operations.
173 : */
174 0 : int volatile result;
175 : };
176 :
177 : /** @internal */
178 0 : static inline uint32_t sys_notify_get_method(const struct sys_notify *notify)
179 : {
180 : uint32_t method = notify->flags >> SYS_NOTIFY_METHOD_POS;
181 :
182 : return method & SYS_NOTIFY_METHOD_MASK;
183 : }
184 :
185 : /**
186 : * @brief Validate and initialize the notify structure.
187 : *
188 : * This should be invoked at the start of any service-specific
189 : * configuration validation. It ensures that the basic asynchronous
190 : * notification configuration is consistent, and clears the result.
191 : *
192 : * Note that this function does not validate extension bits (zeroed by
193 : * async notify API init functions like sys_notify_init_callback()).
194 : * It may fail to recognize that an uninitialized structure has been
195 : * passed because only method bits of flags are tested against method
196 : * settings. To reduce the chance of accepting an uninitialized
197 : * operation service validation of structures that contain an
198 : * sys_notify instance should confirm that the extension bits are
199 : * set or cleared as expected.
200 : *
201 : * @retval 0 on successful validation and reinitialization
202 : * @retval -EINVAL if the configuration is not valid.
203 : */
204 1 : int sys_notify_validate(struct sys_notify *notify);
205 :
206 : /**
207 : * @brief Record and signal the operation completion.
208 : *
209 : * @param notify pointer to the notification state structure.
210 : *
211 : * @param res the result of the operation. Expected values are
212 : * service-specific, but the value shall be non-negative if the
213 : * operation succeeded, and negative if the operation failed.
214 : *
215 : * @return If the notification is to be done by callback this returns
216 : * the generic version of the function to be invoked. The caller must
217 : * immediately invoke that function with whatever arguments are
218 : * expected by the callback. If notification is by spin-wait or
219 : * signal, the notification has been completed by the point this
220 : * function returns, and a null pointer is returned.
221 : */
222 1 : sys_notify_generic_callback sys_notify_finalize(struct sys_notify *notify,
223 : int res);
224 :
225 : /**
226 : * @brief Check for and read the result of an asynchronous operation.
227 : *
228 : * @param notify pointer to the object used to specify asynchronous
229 : * function behavior and store completion information.
230 : *
231 : * @param result pointer to storage for the result of the operation.
232 : * The result is stored only if the operation has completed.
233 : *
234 : * @retval 0 if the operation has completed.
235 : * @retval -EAGAIN if the operation has not completed.
236 : */
237 1 : static inline int sys_notify_fetch_result(const struct sys_notify *notify,
238 : int *result)
239 : {
240 : __ASSERT_NO_MSG(notify != NULL);
241 : __ASSERT_NO_MSG(result != NULL);
242 : int rv = -EAGAIN;
243 :
244 : if (sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_COMPLETED) {
245 : rv = 0;
246 : *result = notify->result;
247 : }
248 :
249 : return rv;
250 : }
251 :
252 : /**
253 : * @brief Initialize a notify object for spin-wait notification.
254 : *
255 : * Clients that use this initialization receive no asynchronous
256 : * notification, and instead must periodically check for completion
257 : * using sys_notify_fetch_result().
258 : *
259 : * On completion of the operation the client object must be
260 : * reinitialized before it can be re-used.
261 : *
262 : * @param notify pointer to the notification configuration object.
263 : */
264 1 : static inline void sys_notify_init_spinwait(struct sys_notify *notify)
265 : {
266 : __ASSERT_NO_MSG(notify != NULL);
267 :
268 : *notify = (struct sys_notify){
269 : .flags = SYS_NOTIFY_METHOD_SPINWAIT,
270 : };
271 : }
272 :
273 : /**
274 : * @brief Initialize a notify object for (k_poll) signal notification.
275 : *
276 : * Clients that use this initialization will be notified of the
277 : * completion of operations through the provided signal.
278 : *
279 : * On completion of the operation the client object must be
280 : * reinitialized before it can be re-used.
281 : *
282 : * @note
283 : * This capability is available only when @kconfig{CONFIG_POLL} is
284 : * selected.
285 : *
286 : * @param notify pointer to the notification configuration object.
287 : *
288 : * @param sigp pointer to the signal to use for notification. The
289 : * value must not be null. The signal must be reset before the client
290 : * object is passed to the on-off service API.
291 : */
292 1 : static inline void sys_notify_init_signal(struct sys_notify *notify,
293 : struct k_poll_signal *sigp)
294 : {
295 : __ASSERT_NO_MSG(notify != NULL);
296 : __ASSERT_NO_MSG(sigp != NULL);
297 :
298 : *notify = (struct sys_notify){
299 : .method = {
300 : .signal = sigp,
301 : },
302 : .flags = SYS_NOTIFY_METHOD_SIGNAL,
303 : };
304 : }
305 :
306 : /**
307 : * @brief Initialize a notify object for callback notification.
308 : *
309 : * Clients that use this initialization will be notified of the
310 : * completion of operations through the provided callback. Note that
311 : * callbacks may be invoked from various contexts depending on the
312 : * specific service; see @ref sys_notify_generic_callback.
313 : *
314 : * On completion of the operation the client object must be
315 : * reinitialized before it can be re-used.
316 : *
317 : * @param notify pointer to the notification configuration object.
318 : *
319 : * @param handler a function pointer to use for notification.
320 : */
321 1 : static inline void sys_notify_init_callback(struct sys_notify *notify,
322 : sys_notify_generic_callback handler)
323 : {
324 : __ASSERT_NO_MSG(notify != NULL);
325 : __ASSERT_NO_MSG(handler != NULL);
326 :
327 : *notify = (struct sys_notify){
328 : .method = {
329 : .callback = handler,
330 : },
331 : .flags = SYS_NOTIFY_METHOD_CALLBACK,
332 : };
333 : }
334 :
335 : /**
336 : * @brief Detect whether a particular notification uses a callback.
337 : *
338 : * The generic handler does not capture the signature expected by the
339 : * callback, and the translation to a service-specific callback must
340 : * be provided by the service. This check allows abstracted services
341 : * to reject callback notification requests when the service doesn't
342 : * provide a translation function.
343 : *
344 : * @return true if and only if a callback is to be used for notification.
345 : */
346 1 : static inline bool sys_notify_uses_callback(const struct sys_notify *notify)
347 : {
348 : __ASSERT_NO_MSG(notify != NULL);
349 :
350 : return sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_CALLBACK;
351 : }
352 :
353 : /** @} */
354 :
355 : #ifdef __cplusplus
356 : }
357 : #endif
358 :
359 : #endif /* ZEPHYR_INCLUDE_SYS_NOTIFY_H_ */
|