diff options
Diffstat (limited to 'lib/chibios/os/nil/src/chevt.c')
-rw-r--r-- | lib/chibios/os/nil/src/chevt.c | 478 |
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 | */ | ||
71 | void 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 | */ | ||
101 | void 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 | */ | ||
130 | eventmask_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 | */ | ||
147 | eventmask_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 | */ | ||
166 | eventmask_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 | */ | ||
193 | void 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 | */ | ||
225 | eventflags_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 | */ | ||
244 | void 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 | */ | ||
264 | void 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 | */ | ||
291 | void 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 | */ | ||
310 | eventflags_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 | */ | ||
328 | void 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 | */ | ||
366 | eventmask_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 | */ | ||
411 | eventmask_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 | */ | ||
453 | eventmask_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 | /** @} */ | ||