ChibiOS  21.6.0
chevt.c
Go to the documentation of this file.
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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);
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  */
292 
293  chSysLock();
294  chEvtBroadcastFlagsI(esp, flags);
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  */
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  */
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;
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  */
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;
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  */
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;
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 /** @} */
chSchReadyI
thread_t * chSchReadyI(thread_t *tp)
Inserts a thread in the Ready List placing it behind its peers.
Definition: chschd.c:276
event_source
Event Source structure.
Definition: chevents.h:74
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:144
chEvtWaitAllTimeout
eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout)
Waits for all the specified events.
Definition: chevt.c:453
eventflags_t
uint32_t eventflags_t
Definition: chearly.h:91
chEvtGetAndClearEventsI
eventmask_t chEvtGetAndClearEventsI(eventmask_t events)
Clears the pending events specified in the events mask.
Definition: chevt.c:130
eventmask_t
uint32_t eventmask_t
Definition: chearly.h:90
chEvtSignalI
void chEvtSignalI(thread_t *tp, eventmask_t events)
Adds a set of event flags directly to the specified thread_t.
Definition: chevt.c:264
chSchGoSleepTimeoutS
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:355
event_listener::flags
eventflags_t flags
Flags added to the listener by the event source.
Definition: chevents.h:65
chEvtWaitOneTimeout
eventmask_t chEvtWaitOneTimeout(eventmask_t events, sysinterval_t timeout)
Waits for exactly one of the specified events.
Definition: chevt.c:366
chEvtAddEvents
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:166
chDbgCheck
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:118
TIME_IMMEDIATE
#define TIME_IMMEDIATE
Zero interval specification for some functions with a timeout specification.
Definition: chtime.h:47
chEvtGetAndClearFlagsI
eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp)
Returns the unmasked flags associated to an event_listener_t.
Definition: chevt.c:310
nil
os_instance_t nil
System data structures.
Definition: ch.c:41
event_listener::listener
thread_t * listener
Thread interested in the event source.
Definition: chevents.h:61
event_listener
Event Listener structure.
Definition: chevents.h:57
ch_thread
Structure representing a thread.
Definition: chobjects.h:156
ch_thread::ewmask
eventmask_t ewmask
Enabled events mask.
Definition: chobjects.h:294
chEvtAddEventsI
#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:206
eventid_t
int32_t eventid_t
Definition: chearly.h:89
chEvtWaitAnyTimeout
eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout)
Waits for any of the specified events.
Definition: chevt.c:411
event_listener::wflags
eventflags_t wflags
Flags that this listener interested in.
Definition: chevents.h:67
event_listener::events
eventmask_t events
Events to be set in the listening thread.
Definition: chevents.h:63
chSchRescheduleS
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:454
chEvtDispatch
void chEvtDispatch(const evhandler_t *handlers, eventmask_t events)
Invokes the event handlers associated to an event flags mask.
Definition: chevt.c:328
chEvtSignal
void chEvtSignal(thread_t *tp, eventmask_t events)
Adds a set of event flags directly to the specified thread_t.
Definition: chevt.c:244
MSG_OK
#define MSG_OK
Normal wakeup message.
Definition: chschd.h:39
chEvtBroadcastFlagsI
void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags)
Signals all the Event Listeners registered on the specified Event Source.
Definition: chevt.c:193
sysinterval_t
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
chEvtUnregister
void chEvtUnregister(event_source_t *esp, event_listener_t *elp)
Unregisters an Event Listener from its Event Source.
Definition: chevt.c:101
EVENT_MASK
#define EVENT_MASK(eid)
Returns an event mask from an event identifier.
Definition: chevents.h:97
chEvtGetAndClearEvents
eventmask_t chEvtGetAndClearEvents(eventmask_t events)
Clears the pending events specified in the events mask.
Definition: chevt.c:147
NIL_STATE_WTOREVT
#define NIL_STATE_WTOREVT
Waiting for events.
Definition: nil/include/ch.h:147
chEvtBroadcastFlags
void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags)
Signals all the Event Listeners registered on the specified Event Source.
Definition: chevt.c:291
event_listener::next
event_listener_t * next
Next Event Listener registered on the event source.
Definition: chevents.h:58
NIL_STATE_WTANDEVT
#define NIL_STATE_WTANDEVT
Waiting for events.
Definition: nil/include/ch.h:148
evhandler_t
void(* evhandler_t)(eventid_t id)
Event Handler callback function.
Definition: chevents.h:83
event_source::next
event_listener_t * next
First Event Listener registered on the Event Source.
Definition: chevents.h:75
chEvtGetAndClearFlags
eventflags_t chEvtGetAndClearFlags(event_listener_t *elp)
Returns the flags associated to an event_listener_t.
Definition: chevt.c:225
chSysUnlock
#define chSysUnlock()
Leaves the kernel lock state.
Definition: nil/include/ch.h:1053
chThdGetSelfX
#define chThdGetSelfX()
Returns a pointer to the current thread_t.
Definition: nil/include/ch.h:1132
chEvtRegisterMaskWithFlags
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:71
chSysLock
#define chSysLock()
Enters the kernel lock state.
Definition: nil/include/ch.h:1043