aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/nil/src/chevt.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/nil/src/chevt.c')
-rw-r--r--lib/chibios/os/nil/src/chevt.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/lib/chibios/os/nil/src/chevt.c b/lib/chibios/os/nil/src/chevt.c
new file mode 100644
index 000000000..0c6a3aa35
--- /dev/null
+++ b/lib/chibios/os/nil/src/chevt.c
@@ -0,0 +1,478 @@
1/*
2 ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
3 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
4
5 This file is part of ChibiOS.
6
7 ChibiOS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation version 3 of the License.
10
11 ChibiOS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/**
21 * @file nil/src/chevt.c
22 * @brief Nil RTOS events source file.
23 *
24 * @addtogroup NIL_EVENTS
25 * @{
26 */
27
28#include "ch.h"
29
30#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
31
32/*===========================================================================*/
33/* Module local definitions. */
34/*===========================================================================*/
35
36/*===========================================================================*/
37/* Module exported variables. */
38/*===========================================================================*/
39
40/*===========================================================================*/
41/* Module local variables. */
42/*===========================================================================*/
43
44/*===========================================================================*/
45/* Module local functions. */
46/*===========================================================================*/
47
48/*===========================================================================*/
49/* Module interrupt handlers. */
50/*===========================================================================*/
51
52/*===========================================================================*/
53/* Module exported functions. */
54/*===========================================================================*/
55
56/**
57 * @brief Registers an Event Listener on an Event Source.
58 * @details Once a thread has registered as listener on an event source it
59 * will be notified of all events broadcasted there.
60 * @note Multiple Event Listeners can specify the same bits to be ORed to
61 * different threads.
62 *
63 * @param[in] esp pointer to the @p event_source_t structure
64 * @param[in] elp pointer to the @p event_listener_t structure
65 * @param[in] events events to be ORed to the thread when
66 * the event source is broadcasted
67 * @param[in] wflags mask of flags the listening thread is interested in
68 *
69 * @api
70 */
71void chEvtRegisterMaskWithFlags(event_source_t *esp,
72 event_listener_t *elp,
73 eventmask_t events,
74 eventflags_t wflags) {
75
76 chDbgCheck((esp != NULL) && (elp != NULL));
77
78 chSysLock();
79 elp->next = esp->next;
80 esp->next = elp;
81 elp->listener = chThdGetSelfX();
82 elp->events = events;
83 elp->flags = (eventflags_t)0;
84 elp->wflags = wflags;
85 chSysUnlock();
86}
87
88/**
89 * @brief Unregisters an Event Listener from its Event Source.
90 * @note If the event listener is not registered on the specified event
91 * source then the function does nothing.
92 * @note For optimal performance it is better to perform the unregister
93 * operations in inverse order of the register operations (elements
94 * are found on top of the list).
95 *
96 * @param[in] esp pointer to the @p event_source_t structure
97 * @param[in] elp pointer to the @p event_listener_t structure
98 *
99 * @api
100 */
101void chEvtUnregister(event_source_t *esp, event_listener_t *elp) {
102 event_listener_t *p;
103
104 chDbgCheck((esp != NULL) && (elp != NULL));
105
106 /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
107 p = (event_listener_t *)esp;
108 /*lint -restore*/
109 chSysLock();
110 /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
111 while (p->next != (event_listener_t *)esp) {
112 /*lint -restore*/
113 if (p->next == elp) {
114 p->next = elp->next;
115 break;
116 }
117 p = p->next;
118 }
119 chSysUnlock();
120}
121
122/**
123 * @brief Clears the pending events specified in the events mask.
124 *
125 * @param[in] events the events to be cleared
126 * @return The mask of pending events that were cleared.
127 *
128 * @iclass
129 */
130eventmask_t chEvtGetAndClearEventsI(eventmask_t events) {
131 eventmask_t m;
132
133 m = chThdGetSelfX()->epmask & events;
134 chThdGetSelfX()->epmask &= ~events;
135
136 return m;
137}
138
139/**
140 * @brief Clears the pending events specified in the events mask.
141 *
142 * @param[in] events the events to be cleared
143 * @return The mask of pending events that were cleared.
144 *
145 * @api
146 */
147eventmask_t chEvtGetAndClearEvents(eventmask_t events) {
148 eventmask_t m;
149
150 chSysLock();
151 m = chEvtGetAndClearEventsI(events);
152 chSysUnlock();
153
154 return m;
155}
156
157/**
158 * @brief Adds (OR) a set of events to the current thread, this is
159 * @b much faster than using @p chEvtBroadcast() or @p chEvtSignal().
160 *
161 * @param[in] events the events to be added
162 * @return The mask of currently pending events.
163 *
164 * @api
165 */
166eventmask_t chEvtAddEvents(eventmask_t events) {
167 eventmask_t newevt;
168
169 chSysLock();
170 newevt = chEvtAddEventsI(events);
171 chSysUnlock();
172
173 return newevt;
174}
175
176/**
177 * @brief Signals all the Event Listeners registered on the specified Event
178 * Source.
179 * @details This function variants ORs the specified event flags to all the
180 * threads registered on the @p event_source_t in addition to the
181 * event flags specified by the threads themselves in the
182 * @p event_listener_t objects.
183 * @post This function does not reschedule so a call to a rescheduling
184 * function must be performed before unlocking the kernel. Note that
185 * interrupt handlers always reschedule on exit so an explicit
186 * reschedule must not be performed in ISRs.
187 *
188 * @param[in] esp pointer to the @p event_source_t structure
189 * @param[in] flags the flags set to be added to the listener flags mask
190 *
191 * @iclass
192 */
193void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags) {
194 event_listener_t *elp;
195
196 chDbgCheckClassI();
197 chDbgCheck(esp != NULL);
198
199 elp = esp->next;
200 /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
201 while (elp != (event_listener_t *)esp) {
202 /*lint -restore*/
203 elp->flags |= flags;
204 /* When flags == 0 the thread will always be signaled because the
205 source does not emit any flag.*/
206 if ((flags == (eventflags_t)0) ||
207 ((flags & elp->wflags) != (eventflags_t)0)) {
208 chEvtSignalI(elp->listener, elp->events);
209 }
210 elp = elp->next;
211 }
212}
213
214/**
215 * @brief Returns the flags associated to an @p event_listener_t.
216 * @details The flags are returned and the @p event_listener_t flags mask is
217 * cleared.
218 *
219 * @param[in] elp pointer to the @p event_listener_t structure
220 * @return The flags added to the listener by the associated
221 * event source.
222 *
223 * @api
224 */
225eventflags_t chEvtGetAndClearFlags(event_listener_t *elp) {
226 eventflags_t flags;
227
228 chSysLock();
229 flags = elp->flags;
230 elp->flags = (eventflags_t)0;
231 chSysUnlock();
232
233 return flags & elp->wflags;
234}
235
236/**
237 * @brief Adds a set of event flags directly to the specified @p thread_t.
238 *
239 * @param[in] tp the thread to be signaled
240 * @param[in] events the event flags set to be ORed
241 *
242 * @api
243 */
244void chEvtSignal(thread_t *tp, eventmask_t events) {
245
246 chSysLock();
247 chEvtSignalI(tp, events);
248 chSchRescheduleS();
249 chSysUnlock();
250}
251
252/**
253 * @brief Adds a set of event flags directly to the specified @p thread_t.
254 * @post This function does not reschedule so a call to a rescheduling
255 * function must be performed before unlocking the kernel. Note that
256 * interrupt handlers always reschedule on exit so an explicit
257 * reschedule must not be performed in ISRs.
258 *
259 * @param[in] tp the thread to be signaled
260 * @param[in] events the event flags set to be ORed
261 *
262 * @iclass
263 */
264void chEvtSignalI(thread_t *tp, eventmask_t events) {
265
266 chDbgCheckClassI();
267 chDbgCheck(tp != NULL);
268
269 tp->epmask |= events;
270 if ((NIL_THD_IS_WTOREVT(tp) &&
271 ((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) ||
272 (NIL_THD_IS_WTANDEVT(tp) &&
273 ((tp->epmask & tp->u1.ewmask) == tp->u1.ewmask))) {
274 (void) chSchReadyI(tp, MSG_OK);
275 }
276}
277
278/**
279 * @brief Signals all the Event Listeners registered on the specified Event
280 * Source.
281 * @details This function variants ORs the specified event flags to all the
282 * threads registered on the @p event_source_t in addition to the
283 * event flags specified by the threads themselves in the
284 * @p event_listener_t objects.
285 *
286 * @param[in] esp pointer to the @p event_source_t structure
287 * @param[in] flags the flags set to be added to the listener flags mask
288 *
289 * @api
290 */
291void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags) {
292
293 chSysLock();
294 chEvtBroadcastFlagsI(esp, flags);
295 chSchRescheduleS();
296 chSysUnlock();
297}
298
299/**
300 * @brief Returns the unmasked flags associated to an @p event_listener_t.
301 * @details The flags are returned and the @p event_listener_t flags mask is
302 * cleared.
303 *
304 * @param[in] elp pointer to the @p event_listener_t structure
305 * @return The flags added to the listener by the associated
306 * event source.
307 *
308 * @iclass
309 */
310eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp) {
311 eventflags_t flags;
312
313 flags = elp->flags;
314 elp->flags = (eventflags_t)0;
315
316 return flags & elp->wflags;
317}
318
319/**
320 * @brief Invokes the event handlers associated to an event flags mask.
321 *
322 * @param[in] events mask of events to be dispatched
323 * @param[in] handlers an array of @p evhandler_t. The array must have size
324 * equal to the number of bits in eventmask_t.
325 *
326 * @api
327 */
328void chEvtDispatch(const evhandler_t *handlers, eventmask_t events) {
329 eventid_t eid;
330
331 chDbgCheck(handlers != NULL);
332
333 eid = (eventid_t)0;
334 while (events != (eventmask_t)0) {
335 if ((events & EVENT_MASK(eid)) != (eventmask_t)0) {
336 chDbgAssert(handlers[eid] != NULL, "null handler");
337 events &= ~EVENT_MASK(eid);
338 handlers[eid](eid);
339 }
340 eid++;
341 }
342}
343
344/**
345 * @brief Waits for exactly one of the specified events.
346 * @details The function waits for one event among those specified in
347 * @p events to become pending then the event is cleared and returned.
348 * @note One and only one event is served in the function, the one with the
349 * lowest event id. The function is meant to be invoked into a loop
350 * in order to serve all the pending events.<br>
351 * This means that Event Listeners with a lower event identifier have
352 * an higher priority.
353 *
354 * @param[in] events events that the function should wait
355 * for, @p ALL_EVENTS enables all the events
356 * @param[in] timeout the number of ticks before the operation timeouts,
357 * the following special values are allowed:
358 * - @a TIME_IMMEDIATE immediate timeout.
359 * - @a TIME_INFINITE no timeout.
360 * .
361 * @return The mask of the lowest event id served and cleared.
362 * @retval 0 if the operation has timed out.
363 *
364 * @api
365 */
366eventmask_t chEvtWaitOneTimeout(eventmask_t events, sysinterval_t timeout) {
367 thread_t *ctp = nil.current;
368 eventmask_t m;
369
370 chSysLock();
371 m = ctp->epmask & events;
372 if (m == (eventmask_t)0) {
373 if (TIME_IMMEDIATE == timeout) {
374 chSysUnlock();
375
376 return (eventmask_t)0;
377 }
378 ctp->u1.ewmask = events;
379 if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) {
380 chSysUnlock();
381
382 return (eventmask_t)0;
383 }
384 m = ctp->epmask & events;
385 }
386 m ^= m & (m - (eventmask_t)1);
387 ctp->epmask &= ~m;
388 chSysUnlock();
389
390 return m;
391}
392
393/**
394 * @brief Waits for any of the specified events.
395 * @details The function waits for any event among those specified in
396 * @p mask to become pending then the events are cleared and
397 * returned.
398 *
399 * @param[in] mask mask of the event flags that the function should wait
400 * for, @p ALL_EVENTS enables all the events
401 * @param[in] timeout the number of ticks before the operation timeouts,
402 * the following special values are allowed:
403 * - @a TIME_IMMEDIATE immediate timeout.
404 * - @a TIME_INFINITE no timeout.
405 * .
406 * @return The mask of the served and cleared events.
407 * @retval 0 if the operation has timed out.
408 *
409 * @api
410 */
411eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout) {
412 thread_t *ctp = nil.current;
413 eventmask_t m;
414
415 chSysLock();
416 if ((m = (ctp->epmask & mask)) == (eventmask_t)0) {
417 if (TIME_IMMEDIATE == timeout) {
418 chSysUnlock();
419
420 return (eventmask_t)0;
421 }
422 ctp->u1.ewmask = mask;
423 if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) {
424 chSysUnlock();
425
426 return (eventmask_t)0;
427 }
428 m = ctp->epmask & mask;
429 }
430 ctp->epmask &= ~m;
431 chSysUnlock();
432
433 return m;
434}
435
436/**
437 * @brief Waits for all the specified events.
438 * @details The function waits for all the events specified in @p mask to
439 * become pending then the events are cleared and returned.
440 *
441 * @param[in] mask mask of the event flags that the function should wait
442 * for, @p ALL_EVENTS enables all the events
443 * @param[in] timeout the number of ticks before the operation timeouts,
444 * the following special values are allowed:
445 * - @a TIME_IMMEDIATE immediate timeout.
446 * - @a TIME_INFINITE no timeout.
447 * .
448 * @return The mask of the served and cleared events.
449 * @retval 0 if the operation has timed out.
450 *
451 * @api
452 */
453eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout) {
454 thread_t *ctp = nil.current;
455
456 chSysLock();
457 if ((ctp->epmask & mask) != mask) {
458 if (TIME_IMMEDIATE == timeout) {
459 chSysUnlock();
460
461 return (eventmask_t)0;
462 }
463 ctp->u1.ewmask = mask;
464 if (chSchGoSleepTimeoutS(NIL_STATE_WTANDEVT, timeout) < MSG_OK) {
465 chSysUnlock();
466
467 return (eventmask_t)0;
468 }
469 }
470 ctp->epmask &= ~mask;
471 chSysUnlock();
472
473 return mask;
474}
475
476#endif /* CH_CFG_USE_EVENTS == TRUE */
477
478/** @} */