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