diff options
Diffstat (limited to 'lib/chibios/os/rt/src/chevents.c')
-rw-r--r-- | lib/chibios/os/rt/src/chevents.c | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/lib/chibios/os/rt/src/chevents.c b/lib/chibios/os/rt/src/chevents.c new file mode 100644 index 000000000..2ada41eb2 --- /dev/null +++ b/lib/chibios/os/rt/src/chevents.c | |||
@@ -0,0 +1,603 @@ | |||
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 | Concepts and parts of this file have been contributed by Scott (skute). | ||
21 | */ | ||
22 | |||
23 | /** | ||
24 | * @file rt/src/chevents.c | ||
25 | * @brief Events code. | ||
26 | * | ||
27 | * @addtogroup events | ||
28 | * @details Event Flags, Event Sources and Event Listeners. | ||
29 | * <h2>Operation mode</h2> | ||
30 | * Each thread has a mask of pending events inside its | ||
31 | * @p thread_t structure. | ||
32 | * Operations defined for events: | ||
33 | * - <b>Wait</b>, the invoking thread goes to sleep until a certain | ||
34 | * AND/OR combination of events are signaled. | ||
35 | * - <b>Clear</b>, a mask of events is cleared from the pending | ||
36 | * events, the cleared events mask is returned (only the | ||
37 | * events that were actually pending and then cleared). | ||
38 | * - <b>Signal</b>, an events mask is directly ORed to the mask of | ||
39 | * the signaled thread. | ||
40 | * - <b>Broadcast</b>, each thread registered on an Event Source is | ||
41 | * signaled with the events specified in its Event Listener. | ||
42 | * - <b>Dispatch</b>, an events mask is scanned and for each bit set | ||
43 | * to one an associated handler function is invoked. Bit masks are | ||
44 | * scanned from bit zero upward. | ||
45 | * . | ||
46 | * An Event Source is a special object that can be "broadcasted" by | ||
47 | * a thread or an interrupt service routine. Broadcasting an Event | ||
48 | * Source has the effect that all the threads registered on the | ||
49 | * Event Source will be signaled with an events mask.<br> | ||
50 | * An unlimited number of Event Sources can exists in a system and | ||
51 | * each thread can be listening on an unlimited number of | ||
52 | * them. | ||
53 | * @pre In order to use the Events APIs the @p CH_CFG_USE_EVENTS option | ||
54 | * must be enabled in @p chconf.h. | ||
55 | * @post Enabling events requires 1-4 (depending on the architecture) | ||
56 | * extra bytes in the @p thread_t structure. | ||
57 | * @{ | ||
58 | */ | ||
59 | |||
60 | #include "ch.h" | ||
61 | |||
62 | #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) | ||
63 | |||
64 | /*===========================================================================*/ | ||
65 | /* Module local definitions. */ | ||
66 | /*===========================================================================*/ | ||
67 | |||
68 | /*===========================================================================*/ | ||
69 | /* Module exported variables. */ | ||
70 | /*===========================================================================*/ | ||
71 | |||
72 | /*===========================================================================*/ | ||
73 | /* Module local types. */ | ||
74 | /*===========================================================================*/ | ||
75 | |||
76 | /*===========================================================================*/ | ||
77 | /* Module local variables. */ | ||
78 | /*===========================================================================*/ | ||
79 | |||
80 | /*===========================================================================*/ | ||
81 | /* Module local functions. */ | ||
82 | /*===========================================================================*/ | ||
83 | |||
84 | /*===========================================================================*/ | ||
85 | /* Module exported functions. */ | ||
86 | /*===========================================================================*/ | ||
87 | |||
88 | /** | ||
89 | * @brief Registers an Event Listener on an Event Source. | ||
90 | * @details Once a thread has registered as listener on an event source it | ||
91 | * will be notified of all events broadcasted there. | ||
92 | * @note Multiple Event Listeners can specify the same bits to be ORed to | ||
93 | * different threads. | ||
94 | * | ||
95 | * @param[in] esp pointer to the @p event_source_t structure | ||
96 | * @param[in] elp pointer to the @p event_listener_t structure | ||
97 | * @param[in] events events to be ORed to the thread when | ||
98 | * the event source is broadcasted | ||
99 | * @param[in] wflags mask of flags the listening thread is interested in | ||
100 | * | ||
101 | * @api | ||
102 | */ | ||
103 | void chEvtRegisterMaskWithFlags(event_source_t *esp, | ||
104 | event_listener_t *elp, | ||
105 | eventmask_t events, | ||
106 | eventflags_t wflags) { | ||
107 | |||
108 | chDbgCheck((esp != NULL) && (elp != NULL)); | ||
109 | |||
110 | chSysLock(); | ||
111 | elp->next = esp->next; | ||
112 | esp->next = elp; | ||
113 | elp->listener = currp; | ||
114 | elp->events = events; | ||
115 | elp->flags = (eventflags_t)0; | ||
116 | elp->wflags = wflags; | ||
117 | chSysUnlock(); | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * @brief Unregisters an Event Listener from its Event Source. | ||
122 | * @note If the event listener is not registered on the specified event | ||
123 | * source then the function does nothing. | ||
124 | * @note For optimal performance it is better to perform the unregister | ||
125 | * operations in inverse order of the register operations (elements | ||
126 | * are found on top of the list). | ||
127 | * | ||
128 | * @param[in] esp pointer to the @p event_source_t structure | ||
129 | * @param[in] elp pointer to the @p event_listener_t structure | ||
130 | * | ||
131 | * @api | ||
132 | */ | ||
133 | void chEvtUnregister(event_source_t *esp, event_listener_t *elp) { | ||
134 | event_listener_t *p; | ||
135 | |||
136 | chDbgCheck((esp != NULL) && (elp != NULL)); | ||
137 | |||
138 | /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ | ||
139 | p = (event_listener_t *)esp; | ||
140 | /*lint -restore*/ | ||
141 | chSysLock(); | ||
142 | /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ | ||
143 | while (p->next != (event_listener_t *)esp) { | ||
144 | /*lint -restore*/ | ||
145 | if (p->next == elp) { | ||
146 | p->next = elp->next; | ||
147 | break; | ||
148 | } | ||
149 | p = p->next; | ||
150 | } | ||
151 | chSysUnlock(); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * @brief Clears the pending events specified in the events mask. | ||
156 | * | ||
157 | * @param[in] events the events to be cleared | ||
158 | * @return The mask of pending events that were cleared. | ||
159 | * | ||
160 | * @iclass | ||
161 | */ | ||
162 | eventmask_t chEvtGetAndClearEventsI(eventmask_t events) { | ||
163 | eventmask_t m; | ||
164 | |||
165 | m = currp->epending & events; | ||
166 | currp->epending &= ~events; | ||
167 | |||
168 | return m; | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * @brief Clears the pending events specified in the events mask. | ||
173 | * | ||
174 | * @param[in] events the events to be cleared | ||
175 | * @return The mask of pending events that were cleared. | ||
176 | * | ||
177 | * @api | ||
178 | */ | ||
179 | eventmask_t chEvtGetAndClearEvents(eventmask_t events) { | ||
180 | eventmask_t m; | ||
181 | |||
182 | chSysLock(); | ||
183 | m = chEvtGetAndClearEventsI(events); | ||
184 | chSysUnlock(); | ||
185 | |||
186 | return m; | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * @brief Adds (OR) a set of events to the current thread, this is | ||
191 | * @b much faster than using @p chEvtBroadcast() or @p chEvtSignal(). | ||
192 | * | ||
193 | * @param[in] events the events to be added | ||
194 | * @return The mask of currently pending events. | ||
195 | * | ||
196 | * @api | ||
197 | */ | ||
198 | eventmask_t chEvtAddEvents(eventmask_t events) { | ||
199 | eventmask_t newevt; | ||
200 | |||
201 | chSysLock(); | ||
202 | newevt = chEvtAddEventsI(events); | ||
203 | chSysUnlock(); | ||
204 | |||
205 | return newevt; | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * @brief Signals all the Event Listeners registered on the specified Event | ||
210 | * Source. | ||
211 | * @details This function variants ORs the specified event flags to all the | ||
212 | * threads registered on the @p event_source_t in addition to the | ||
213 | * event flags specified by the threads themselves in the | ||
214 | * @p event_listener_t objects. | ||
215 | * @post This function does not reschedule so a call to a rescheduling | ||
216 | * function must be performed before unlocking the kernel. Note that | ||
217 | * interrupt handlers always reschedule on exit so an explicit | ||
218 | * reschedule must not be performed in ISRs. | ||
219 | * | ||
220 | * @param[in] esp pointer to the @p event_source_t structure | ||
221 | * @param[in] flags the flags set to be added to the listener flags mask | ||
222 | * | ||
223 | * @iclass | ||
224 | */ | ||
225 | void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags) { | ||
226 | event_listener_t *elp; | ||
227 | |||
228 | chDbgCheckClassI(); | ||
229 | chDbgCheck(esp != NULL); | ||
230 | |||
231 | elp = esp->next; | ||
232 | /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ | ||
233 | while (elp != (event_listener_t *)esp) { | ||
234 | /*lint -restore*/ | ||
235 | elp->flags |= flags; | ||
236 | /* When flags == 0 the thread will always be signaled because the | ||
237 | source does not emit any flag.*/ | ||
238 | if ((flags == (eventflags_t)0) || | ||
239 | ((flags & elp->wflags) != (eventflags_t)0)) { | ||
240 | chEvtSignalI(elp->listener, elp->events); | ||
241 | } | ||
242 | elp = elp->next; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * @brief Returns the flags associated to an @p event_listener_t. | ||
248 | * @details The flags are returned and the @p event_listener_t flags mask is | ||
249 | * cleared. | ||
250 | * | ||
251 | * @param[in] elp pointer to the @p event_listener_t structure | ||
252 | * @return The flags added to the listener by the associated | ||
253 | * event source. | ||
254 | * | ||
255 | * @api | ||
256 | */ | ||
257 | eventflags_t chEvtGetAndClearFlags(event_listener_t *elp) { | ||
258 | eventflags_t flags; | ||
259 | |||
260 | chSysLock(); | ||
261 | flags = elp->flags; | ||
262 | elp->flags = (eventflags_t)0; | ||
263 | chSysUnlock(); | ||
264 | |||
265 | return flags & elp->wflags; | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * @brief Adds a set of event flags directly to the specified @p thread_t. | ||
270 | * | ||
271 | * @param[in] tp the thread to be signaled | ||
272 | * @param[in] events the events set to be ORed | ||
273 | * | ||
274 | * @api | ||
275 | */ | ||
276 | void chEvtSignal(thread_t *tp, eventmask_t events) { | ||
277 | |||
278 | chDbgCheck(tp != NULL); | ||
279 | |||
280 | chSysLock(); | ||
281 | chEvtSignalI(tp, events); | ||
282 | chSchRescheduleS(); | ||
283 | chSysUnlock(); | ||
284 | } | ||
285 | |||
286 | /** | ||
287 | * @brief Adds a set of event flags directly to the specified @p thread_t. | ||
288 | * @post This function does not reschedule so a call to a rescheduling | ||
289 | * function must be performed before unlocking the kernel. Note that | ||
290 | * interrupt handlers always reschedule on exit so an explicit | ||
291 | * reschedule must not be performed in ISRs. | ||
292 | * | ||
293 | * @param[in] tp the thread to be signaled | ||
294 | * @param[in] events the events set to be ORed | ||
295 | * | ||
296 | * @iclass | ||
297 | */ | ||
298 | void chEvtSignalI(thread_t *tp, eventmask_t events) { | ||
299 | |||
300 | chDbgCheckClassI(); | ||
301 | chDbgCheck(tp != NULL); | ||
302 | |||
303 | tp->epending |= events; | ||
304 | /* Test on the AND/OR conditions wait states.*/ | ||
305 | if (((tp->state == CH_STATE_WTOREVT) && | ||
306 | ((tp->epending & tp->u.ewmask) != (eventmask_t)0)) || | ||
307 | ((tp->state == CH_STATE_WTANDEVT) && | ||
308 | ((tp->epending & tp->u.ewmask) == tp->u.ewmask))) { | ||
309 | tp->u.rdymsg = MSG_OK; | ||
310 | (void) chSchReadyI(tp); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * @brief Signals all the Event Listeners registered on the specified Event | ||
316 | * Source. | ||
317 | * @details This function variants ORs the specified event flags to all the | ||
318 | * threads registered on the @p event_source_t in addition to the | ||
319 | * event flags specified by the threads themselves in the | ||
320 | * @p event_listener_t objects. | ||
321 | * | ||
322 | * @param[in] esp pointer to the @p event_source_t structure | ||
323 | * @param[in] flags the flags set to be added to the listener flags mask | ||
324 | * | ||
325 | * @api | ||
326 | */ | ||
327 | void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags) { | ||
328 | |||
329 | chSysLock(); | ||
330 | chEvtBroadcastFlagsI(esp, flags); | ||
331 | chSchRescheduleS(); | ||
332 | chSysUnlock(); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * @brief Returns the unmasked flags associated to an @p event_listener_t. | ||
337 | * @details The flags are returned and the @p event_listener_t flags mask is | ||
338 | * cleared. | ||
339 | * | ||
340 | * @param[in] elp pointer to the @p event_listener_t structure | ||
341 | * @return The flags added to the listener by the associated | ||
342 | * event source. | ||
343 | * | ||
344 | * @iclass | ||
345 | */ | ||
346 | eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp) { | ||
347 | eventflags_t flags; | ||
348 | |||
349 | flags = elp->flags; | ||
350 | elp->flags = (eventflags_t)0; | ||
351 | |||
352 | return flags & elp->wflags; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * @brief Invokes the event handlers associated to an event flags mask. | ||
357 | * | ||
358 | * @param[in] events mask of events to be dispatched | ||
359 | * @param[in] handlers an array of @p evhandler_t. The array must have size | ||
360 | * equal to the number of bits in eventmask_t. | ||
361 | * | ||
362 | * @api | ||
363 | */ | ||
364 | void chEvtDispatch(const evhandler_t *handlers, eventmask_t events) { | ||
365 | eventid_t eid; | ||
366 | |||
367 | chDbgCheck(handlers != NULL); | ||
368 | |||
369 | eid = (eventid_t)0; | ||
370 | while (events != (eventmask_t)0) { | ||
371 | if ((events & EVENT_MASK(eid)) != (eventmask_t)0) { | ||
372 | chDbgAssert(handlers[eid] != NULL, "null handler"); | ||
373 | events &= ~EVENT_MASK(eid); | ||
374 | handlers[eid](eid); | ||
375 | } | ||
376 | eid++; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | #if (CH_CFG_OPTIMIZE_SPEED == TRUE) || \ | ||
381 | (CH_CFG_USE_EVENTS_TIMEOUT == FALSE) || \ | ||
382 | defined(__DOXYGEN__) | ||
383 | /** | ||
384 | * @brief Waits for exactly one of the specified events. | ||
385 | * @details The function waits for one event among those specified in | ||
386 | * @p events to become pending then the event is cleared and returned. | ||
387 | * @note One and only one event is served in the function, the one with the | ||
388 | * lowest event id. The function is meant to be invoked into a loop in | ||
389 | * order to serve all the pending events.<br> | ||
390 | * This means that Event Listeners with a lower event identifier have | ||
391 | * an higher priority. | ||
392 | * | ||
393 | * @param[in] events events that the function should wait | ||
394 | * for, @p ALL_EVENTS enables all the events | ||
395 | * @return The mask of the lowest event id served and cleared. | ||
396 | * | ||
397 | * @api | ||
398 | */ | ||
399 | eventmask_t chEvtWaitOne(eventmask_t events) { | ||
400 | thread_t *ctp = currp; | ||
401 | eventmask_t m; | ||
402 | |||
403 | chSysLock(); | ||
404 | m = ctp->epending & events; | ||
405 | if (m == (eventmask_t)0) { | ||
406 | ctp->u.ewmask = events; | ||
407 | chSchGoSleepS(CH_STATE_WTOREVT); | ||
408 | m = ctp->epending & events; | ||
409 | } | ||
410 | m ^= m & (m - (eventmask_t)1); | ||
411 | ctp->epending &= ~m; | ||
412 | chSysUnlock(); | ||
413 | |||
414 | return m; | ||
415 | } | ||
416 | |||
417 | /** | ||
418 | * @brief Waits for any of the specified events. | ||
419 | * @details The function waits for any event among those specified in | ||
420 | * @p events to become pending then the events are cleared and | ||
421 | * returned. | ||
422 | * | ||
423 | * @param[in] events events that the function should wait | ||
424 | * for, @p ALL_EVENTS enables all the events | ||
425 | * @return The mask of the served and cleared events. | ||
426 | * | ||
427 | * @api | ||
428 | */ | ||
429 | eventmask_t chEvtWaitAny(eventmask_t events) { | ||
430 | thread_t *ctp = currp; | ||
431 | eventmask_t m; | ||
432 | |||
433 | chSysLock(); | ||
434 | m = ctp->epending & events; | ||
435 | if (m == (eventmask_t)0) { | ||
436 | ctp->u.ewmask = events; | ||
437 | chSchGoSleepS(CH_STATE_WTOREVT); | ||
438 | m = ctp->epending & events; | ||
439 | } | ||
440 | ctp->epending &= ~m; | ||
441 | chSysUnlock(); | ||
442 | |||
443 | return m; | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * @brief Waits for all the specified events. | ||
448 | * @details The function waits for all the events specified in @p events to | ||
449 | * become pending then the events are cleared and returned. | ||
450 | * | ||
451 | * @param[in] events events that the function should wait | ||
452 | * for, @p ALL_EVENTS requires all the events | ||
453 | * @return The mask of the served and cleared events. | ||
454 | * | ||
455 | * @api | ||
456 | */ | ||
457 | eventmask_t chEvtWaitAll(eventmask_t events) { | ||
458 | thread_t *ctp = currp; | ||
459 | |||
460 | chSysLock(); | ||
461 | if ((ctp->epending & events) != events) { | ||
462 | ctp->u.ewmask = events; | ||
463 | chSchGoSleepS(CH_STATE_WTANDEVT); | ||
464 | } | ||
465 | ctp->epending &= ~events; | ||
466 | chSysUnlock(); | ||
467 | |||
468 | return events; | ||
469 | } | ||
470 | #endif /* CH_CFG_OPTIMIZE_SPEED || !CH_CFG_USE_EVENTS_TIMEOUT */ | ||
471 | |||
472 | #if (CH_CFG_USE_EVENTS_TIMEOUT == TRUE) || defined(__DOXYGEN__) | ||
473 | /** | ||
474 | * @brief Waits for exactly one of the specified events. | ||
475 | * @details The function waits for one event among those specified in | ||
476 | * @p events to become pending then the event is cleared and returned. | ||
477 | * @note One and only one event is served in the function, the one with the | ||
478 | * lowest event id. The function is meant to be invoked into a loop | ||
479 | * in order to serve all the pending events.<br> | ||
480 | * This means that Event Listeners with a lower event identifier have | ||
481 | * an higher priority. | ||
482 | * | ||
483 | * @param[in] events events that the function should wait | ||
484 | * for, @p ALL_EVENTS enables all the events | ||
485 | * @param[in] timeout the number of ticks before the operation timeouts, | ||
486 | * the following special values are allowed: | ||
487 | * - @a TIME_IMMEDIATE immediate timeout. | ||
488 | * - @a TIME_INFINITE no timeout. | ||
489 | * . | ||
490 | * @return The mask of the lowest event id served and cleared. | ||
491 | * @retval 0 if the operation has timed out. | ||
492 | * | ||
493 | * @api | ||
494 | */ | ||
495 | eventmask_t chEvtWaitOneTimeout(eventmask_t events, sysinterval_t timeout) { | ||
496 | thread_t *ctp = currp; | ||
497 | eventmask_t m; | ||
498 | |||
499 | chSysLock(); | ||
500 | m = ctp->epending & events; | ||
501 | if (m == (eventmask_t)0) { | ||
502 | if (TIME_IMMEDIATE == timeout) { | ||
503 | chSysUnlock(); | ||
504 | return (eventmask_t)0; | ||
505 | } | ||
506 | ctp->u.ewmask = events; | ||
507 | if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, timeout) < MSG_OK) { | ||
508 | chSysUnlock(); | ||
509 | return (eventmask_t)0; | ||
510 | } | ||
511 | m = ctp->epending & events; | ||
512 | } | ||
513 | m ^= m & (m - (eventmask_t)1); | ||
514 | ctp->epending &= ~m; | ||
515 | chSysUnlock(); | ||
516 | |||
517 | return m; | ||
518 | } | ||
519 | |||
520 | /** | ||
521 | * @brief Waits for any of the specified events. | ||
522 | * @details The function waits for any event among those specified in | ||
523 | * @p events to become pending then the events are cleared and | ||
524 | * returned. | ||
525 | * | ||
526 | * @param[in] events events that the function should wait | ||
527 | * for, @p ALL_EVENTS enables all the events | ||
528 | * @param[in] timeout the number of ticks before the operation timeouts, | ||
529 | * the following special values are allowed: | ||
530 | * - @a TIME_IMMEDIATE immediate timeout. | ||
531 | * - @a TIME_INFINITE no timeout. | ||
532 | * . | ||
533 | * @return The mask of the served and cleared events. | ||
534 | * @retval 0 if the operation has timed out. | ||
535 | * | ||
536 | * @api | ||
537 | */ | ||
538 | eventmask_t chEvtWaitAnyTimeout(eventmask_t events, sysinterval_t timeout) { | ||
539 | thread_t *ctp = currp; | ||
540 | eventmask_t m; | ||
541 | |||
542 | chSysLock(); | ||
543 | m = ctp->epending & events; | ||
544 | if (m == (eventmask_t)0) { | ||
545 | if (TIME_IMMEDIATE == timeout) { | ||
546 | chSysUnlock(); | ||
547 | return (eventmask_t)0; | ||
548 | } | ||
549 | ctp->u.ewmask = events; | ||
550 | if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, timeout) < MSG_OK) { | ||
551 | chSysUnlock(); | ||
552 | return (eventmask_t)0; | ||
553 | } | ||
554 | m = ctp->epending & events; | ||
555 | } | ||
556 | ctp->epending &= ~m; | ||
557 | chSysUnlock(); | ||
558 | |||
559 | return m; | ||
560 | } | ||
561 | |||
562 | /** | ||
563 | * @brief Waits for all the specified events. | ||
564 | * @details The function waits for all the events specified in @p events to | ||
565 | * become pending then the events are cleared and returned. | ||
566 | * | ||
567 | * @param[in] events events that the function should wait | ||
568 | * for, @p ALL_EVENTS requires all the events | ||
569 | * @param[in] timeout the number of ticks before the operation timeouts, | ||
570 | * the following special values are allowed: | ||
571 | * - @a TIME_IMMEDIATE immediate timeout. | ||
572 | * - @a TIME_INFINITE no timeout. | ||
573 | * . | ||
574 | * @return The mask of the served and cleared events. | ||
575 | * @retval 0 if the operation has timed out. | ||
576 | * | ||
577 | * @api | ||
578 | */ | ||
579 | eventmask_t chEvtWaitAllTimeout(eventmask_t events, sysinterval_t timeout) { | ||
580 | thread_t *ctp = currp; | ||
581 | |||
582 | chSysLock(); | ||
583 | if ((ctp->epending & events) != events) { | ||
584 | if (TIME_IMMEDIATE == timeout) { | ||
585 | chSysUnlock(); | ||
586 | return (eventmask_t)0; | ||
587 | } | ||
588 | ctp->u.ewmask = events; | ||
589 | if (chSchGoSleepTimeoutS(CH_STATE_WTANDEVT, timeout) < MSG_OK) { | ||
590 | chSysUnlock(); | ||
591 | return (eventmask_t)0; | ||
592 | } | ||
593 | } | ||
594 | ctp->epending &= ~events; | ||
595 | chSysUnlock(); | ||
596 | |||
597 | return events; | ||
598 | } | ||
599 | #endif /* CH_CFG_USE_EVENTS_TIMEOUT == TRUE */ | ||
600 | |||
601 | #endif /* CH_CFG_USE_EVENTS == TRUE */ | ||
602 | |||
603 | /** @} */ | ||