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